commit
f5fc31c6b7
39 changed files with 2706 additions and 0 deletions
@ -0,0 +1,13 @@ |
||||
Makefile.in |
||||
aclocal.m4 |
||||
autom4te.cache |
||||
config.guess* |
||||
config.sub* |
||||
configure |
||||
depcomp |
||||
install-sh |
||||
ltmain.sh |
||||
m4/ |
||||
missing |
||||
*~ |
||||
src/core/evcon-config-private.h.in |
@ -0,0 +1,22 @@ |
||||
|
||||
The MIT License |
||||
|
||||
Copyright (c) 2012 Stefan Bühler |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the "Software"), to deal |
||||
in the Software without restriction, including without limitation the rights |
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
copies of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in |
||||
all copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
||||
THE SOFTWARE. |
@ -0,0 +1,12 @@ |
||||
|
||||
SUBDIRS = . src
|
||||
|
||||
EXTRA_DIST=README.md autogen.sh evcon.pc.in evcon-ev.pc.in evcon-glib.pc.in evcon-event.pc.in
|
||||
EXTRA_DIST+=libevcon-ev0.symbols libevcon-event0.symbols libevcon-glib0.symbols libevcon0.symbols
|
||||
|
||||
ACLOCAL_AMFLAGS=-I m4
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = evcon.pc evcon-ev.pc evcon-glib.pc evcon-event.pc
|
||||
|
||||
$(pkgconfig_DATA): config.status |
@ -0,0 +1,65 @@ |
||||
Description |
||||
----------- |
||||
|
||||
evon is a generic wrapper library that sits between libraries that need socket (file descriptor), timeout and (thread safe) asynchronous events, and an application that wants to use the library. |
||||
|
||||
Platforms |
||||
--------- |
||||
|
||||
Should work on all POSIX compatible platforms. |
||||
|
||||
Features |
||||
-------- |
||||
|
||||
Event types: |
||||
|
||||
* read and write events for asynchronous file descriptors (sockets) |
||||
* simple timeout events |
||||
* (thread safe) asynchronous events (notifications - for example from other threads, that wakeup the event loop) |
||||
|
||||
Backends for: |
||||
|
||||
* [libev](http://software.schmorp.de/pkg/libev.html) |
||||
* [libevent](http://libevent.org/) |
||||
* [glib](http://developer.gnome.org/glib/unstable/glib-The-Main-Event-Loop.html) |
||||
|
||||
|
||||
Simple Scenario |
||||
--------------- |
||||
|
||||
You want to write an application that uses two different event based libraries; if these libraries don't use the same event loop (say X uses libev and Y libevent) you will have difficulties using them - you could give each library its own thread for example, but embedding one event loop in another is usually not easy. |
||||
|
||||
If the libraries were built against evcon, you could use any event loop - if there is no backend for it yet, you probably can write one. |
||||
|
||||
Examples |
||||
-------- |
||||
|
||||
See `src/tests/evcon-echo.c` and `src/tests/evcon-echo.h` for an example "library", and `src/tests/evcon-test-*.c` for how to use them in an application. |
||||
|
||||
Building from git |
||||
----------------- |
||||
|
||||
Run the following in the source directory to prepare the build system: |
||||
|
||||
./autogen.sh |
||||
|
||||
You will need automake and autoconf for this. |
||||
|
||||
Building |
||||
-------- |
||||
|
||||
All backends need glib (>= 2.14). |
||||
The libev backend needs libev >= 4, the libevent backend needs libevent >= 2. |
||||
|
||||
Build in a sub directory: |
||||
|
||||
mkdir build |
||||
cd build |
||||
../configure |
||||
make check |
||||
|
||||
Install (probably has to be run as root): |
||||
|
||||
make install |
||||
|
||||
As always it is recommended to use a package system to install files instead (dpkg, rpm, ...). |
@ -0,0 +1,31 @@ |
||||
#!/bin/sh |
||||
# Run this to generate all the initial makefiles, etc. |
||||
|
||||
LIBTOOLIZE=${LIBTOOLIZE:-libtoolize} |
||||
LIBTOOLIZE_FLAGS="--copy --force" |
||||
ACLOCAL=${ACLOCAL:-aclocal} |
||||
AUTOHEADER=${AUTOHEADER:-autoheader} |
||||
AUTOMAKE=${AUTOMAKE:-automake} |
||||
AUTOMAKE_FLAGS="--add-missing --copy" |
||||
AUTOCONF=${AUTOCONF:-autoconf} |
||||
|
||||
ARGV0=$0 |
||||
|
||||
srcdir=$(readlink -f "$0") |
||||
srcdir=$(dirname "$srcdir") |
||||
cd "$srcdir" |
||||
|
||||
set -e |
||||
|
||||
|
||||
run() { |
||||
echo "$ARGV0: running \`$@'" |
||||
$@ |
||||
} |
||||
|
||||
run $LIBTOOLIZE $LIBTOOLIZE_FLAGS |
||||
run $ACLOCAL $ACLOCAL_FLAGS |
||||
run $AUTOHEADER |
||||
run $AUTOMAKE $AUTOMAKE_FLAGS |
||||
run $AUTOCONF |
||||
echo "Now type './configure ...' and 'make' to compile." |
@ -0,0 +1,126 @@ |
||||
# -*- Autoconf -*- |
||||
# Process this file with autoconf to produce a configure script. |
||||
|
||||
AC_PREREQ([2.63]) |
||||
AC_INIT([evcon], [0.1.0], [lighttpd@stbuehler.de]) |
||||
AC_CONFIG_SRCDIR([src/core/evcon.c]) |
||||
AC_CONFIG_HEADERS([src/core/evcon-config-private.h]) |
||||
AC_CONFIG_HEADERS([src/core/evcon-config.h]) |
||||
|
||||
AC_CONFIG_MACRO_DIR([m4]) |
||||
|
||||
AM_INIT_AUTOMAKE([-Wall -Werror foreign]) |
||||
|
||||
m4_ifndef([PKG_PROG_PKG_CONFIG], [m4_fatal([pkg-config not installed])]) |
||||
m4_ifndef([AC_PROG_LIBTOOL], [m4_fatal([libtool not installed])]) |
||||
|
||||
# Checks for programs. |
||||
AC_PROG_CC |
||||
AC_PROG_LIBTOOL |
||||
AC_PROG_MAKE_SET |
||||
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics. |
||||
AC_TYPE_PID_T |
||||
AC_TYPE_SIZE_T |
||||
|
||||
# Checks for library functions. |
||||
AC_FUNC_FORK |
||||
AC_CHECK_FUNCS([dup2 pipe2]) |
||||
|
||||
# Checks for libraries. |
||||
|
||||
AC_ARG_ENABLE([glib], AS_HELP_STRING([--disable-glib], [Disable building glib wrapper]), [build_glib=no], [build_glib=yes]) |
||||
AC_ARG_ENABLE([ev], AS_HELP_STRING([--disable-ev], [Disable building ev wrapper]), [build_ev=no], [build_ev=yes]) |
||||
AC_ARG_ENABLE([event], AS_HELP_STRING([--disable-event], [Disable building event wrapper]), [build_event=no], [build_event=yes]) |
||||
|
||||
if test "x${build_glib}" != "xno" -o "x${build_ev}" != "xno" -o "x${build_event}" != "xno"; then |
||||
AC_MSG_CHECKING([Enabled at least one backend. Requires glib.]) |
||||
|
||||
# glib |
||||
PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.16.0], [],[AC_MSG_ERROR("glib-2.0 >= 2.16.0 not found")]) |
||||
fi |
||||
|
||||
AC_ARG_ENABLE(glib-compat, |
||||
AC_HELP_STRING([--enable-glib-compat],[build for older glib versions even with new headers]), |
||||
AC_DEFINE([EVCON_GLIB_COMPAT_API], [1], [build for older glib versions even with new headers]),[]) |
||||
|
||||
LIBEV_CFLAGS="" |
||||
LIBEV_LIBS="" |
||||
if test "x${build_ev}" != "xno"; then |
||||
AC_MSG_CHECKING([Enabled ev wrapper. Requires libev.]) |
||||
|
||||
# libev |
||||
AC_MSG_CHECKING([for libev support]) |
||||
AC_ARG_WITH([libev], |
||||
[AS_HELP_STRING([--with-libev@<:@=PATH@:>@],[Search for libev in PATH/include and PATH/lib])], |
||||
[WITH_LIBEV=$withval],[WITH_LIBEV=yes]) |
||||
|
||||
PKG_CHECK_MODULES([LIBEV], [libev], [], [ |
||||
# no pkg-config for libev, searching manually: |
||||
|
||||
if test "$WITH_LIBEV" != "yes"; then |
||||
LIBEV_CFLAGS="-I$WITH_LIBEV/include" |
||||
LIBEV_LIBS="-L$WITH_LIBEV/lib -lev" |
||||
else |
||||
AC_CHECK_HEADERS([ev.h],[ |
||||
AC_CHECK_LIB([ev], [ev_time], [ |
||||
LIBEV_LIBS="-lev" |
||||
],[ |
||||
AC_MSG_ERROR([libev not found]) |
||||
] |
||||
)],[ |
||||
AC_MSG_ERROR([libev not found]) |
||||
] |
||||
) |
||||
fi |
||||
]) |
||||
fi |
||||
AC_SUBST([LIBEV_CFLAGS]) |
||||
AC_SUBST([LIBEV_LIBS]) |
||||
|
||||
if test "x${build_event}" != "xno"; then |
||||
AC_MSG_CHECKING([Enabled event wrapper. Requires libevent.]) |
||||
|
||||
# event |
||||
PKG_CHECK_MODULES([LIBEVENT], [libevent >= 2], [ |
||||
# we want event_core, not event |
||||
LIBEVENT_LIBS=`echo "$LIBEVENT_LIBS" | sed 's#\(^\| \)-levent\($\| \)# -levent_core #'` |
||||
],[AC_MSG_ERROR("libevent >= 2 not found")]) |
||||
fi |
||||
|
||||
|
||||
AM_CONDITIONAL([BUILD_GLIB], [test "x${build_glib}" != "xno"]) |
||||
AM_CONDITIONAL([BUILD_EV], [test "x${build_ev}" != "xno"]) |
||||
AM_CONDITIONAL([BUILD_EVENT], [test "x${build_event}" != "xno"]) |
||||
|
||||
|
||||
#AC_ARG_ENABLE([qt], AS_HELP_STRING([--disable-qt], [Disable building qt wrapper]), [build_qt=$withval], [build_qt=yes]) |
||||
# |
||||
#if test "x${build_qt}" != "xno"; then |
||||
# AC_MSG_CHECKING([Enabled qt wrapper. Requires c++ and qt4.]) |
||||
# AC_PROG_CXX |
||||
# PKG_CHECK_MODULES([QT], [QtCore >= 4.0.0], [],[AC_MSG_ERROR("QtCore >= 4.0.0 not found")]) |
||||
#fi |
||||
#AM_CONDITIONAL([BUILD_QT], [test "x${build_qt}" != "xno"]) |
||||
|
||||
|
||||
# check for extra compiler options (warning options) |
||||
if test "${GCC}" = "yes"; then |
||||
CFLAGS="${CFLAGS} -Wall -W -Wshadow -pedantic -std=gnu99" |
||||
fi |
||||
|
||||
AC_ARG_ENABLE(extra-warnings, |
||||
AC_HELP_STRING([--enable-extra-warnings],[enable extra warnings (gcc specific)]), |
||||
[case "${enableval}" in |
||||
yes) extrawarnings=true ;; |
||||
no) extrawarnings=false ;; |
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-extra-warnings) ;; |
||||
esac],[extrawarnings=false]) |
||||
|
||||
if test x$extrawarnings = xtrue; then |
||||
CFLAGS="${CFLAGS} -g -O2 -g2 -Wall -Wmissing-declarations -Wdeclaration-after-statement -Wno-pointer-sign -Wcast-align -Winline -Wsign-compare -Wnested-externs -Wpointer-arith -Wl,--as-needed -Wformat-security" |
||||
fi |
||||
|
||||
AC_CONFIG_FILES([Makefile src/Makefile src/core/Makefile src/backend-glib/Makefile src/backend-ev/Makefile src/backend-event/Makefile src/tests/Makefile evcon.pc evcon-ev.pc evcon-glib.pc evcon-event.pc]) |
||||
AC_OUTPUT |
@ -0,0 +1,11 @@ |
||||
prefix=@prefix@ |
||||
exec_prefix=@exec_prefix@ |
||||
libdir=@libdir@ |
||||
includedir=@includedir@ |
||||
|
||||
Name: evcon-ev |
||||
Description: libev backend for event connector library |
||||
Version: @VERSION@ |
||||
Requires: evcon |
||||
Libs: -L${libdir} -levcon-ev |
||||
Cflags: |
@ -0,0 +1,11 @@ |
||||
prefix=@prefix@ |
||||
exec_prefix=@exec_prefix@ |
||||
libdir=@libdir@ |
||||
includedir=@includedir@ |
||||
|
||||
Name: evcon-event |
||||
Description: libevent backend for event connector library |
||||
Version: @VERSION@ |
||||
Requires: evcon |
||||
Libs: -L${libdir} -levcon-event |
||||
Cflags: |
@ -0,0 +1,11 @@ |
||||
prefix=@prefix@ |
||||
exec_prefix=@exec_prefix@ |
||||
libdir=@libdir@ |
||||
includedir=@includedir@ |
||||
|
||||
Name: evcon-glib |
||||
Description: glib backend for event connector library |
||||
Version: @VERSION@ |
||||
Requires: evcon |
||||
Libs: -L${libdir} -levcon-glib |
||||
Cflags: |
@ -0,0 +1,11 @@ |
||||
prefix=@prefix@ |
||||
exec_prefix=@exec_prefix@ |
||||
libdir=@libdir@ |
||||
includedir=@includedir@ |
||||
|
||||
Name: evcon |
||||
Description: event connector library |
||||
Version: @VERSION@ |
||||
Requires: |
||||
Libs: -L${libdir} -levcon |
||||
Cflags: |
@ -0,0 +1,2 @@ |
||||
libevcon-ev.so.0 libevcon-ev0 #MINVER# |
||||
evcon_loop_from_ev@Base 0.1.0 |
@ -0,0 +1,2 @@ |
||||
libevcon-event.so.0 libevcon-event0 #MINVER# |
||||
evcon_loop_from_event@Base 0.1.0 |
@ -0,0 +1,4 @@ |
||||
libevcon-glib.so.0 libevcon-glib0 #MINVER# |
||||
evcon_glib_allocator@Base 0.1.0 |
||||
evcon_loop_from_glib@Base 0.1.0 |
||||
evcon_loop_glib_get_context@Base 0.1.0 |
@ -0,0 +1,66 @@ |
||||
libevcon.so.0 libevcon0 #MINVER# |
||||
evcon_alloc0@Base 0.1.0 |
||||
evcon_alloc@Base 0.1.0 |
||||
evcon_allocator_free@Base 0.1.0 |
||||
evcon_allocator_get_data@Base 0.1.0 |
||||
evcon_allocator_init@Base 0.1.0 |
||||
evcon_allocator_new@Base 0.1.0 |
||||
evcon_allocator_set_data@Base 0.1.0 |
||||
evcon_async_free@Base 0.1.0 |
||||
evcon_async_get_backend_data@Base 0.1.0 |
||||
evcon_async_get_cb@Base 0.1.0 |
||||
evcon_async_get_loop@Base 0.1.0 |
||||
evcon_async_get_user_data@Base 0.1.0 |
||||
evcon_async_new@Base 0.1.0 |
||||
evcon_async_set_backend_data@Base 0.1.0 |
||||
evcon_async_set_cb@Base 0.1.0 |
||||
evcon_async_set_user_data@Base 0.1.0 |
||||
evcon_async_wakeup@Base 0.1.0 |
||||
evcon_backend_free@Base 0.1.0 |
||||
evcon_backend_get_data@Base 0.1.0 |
||||
evcon_backend_init@Base 0.1.0 |
||||
evcon_backend_new@Base 0.1.0 |
||||
evcon_backend_set_data@Base 0.1.0 |
||||
evcon_fd_free@Base 0.1.0 |
||||
evcon_fd_get_backend_data@Base 0.1.0 |
||||
evcon_fd_get_cb@Base 0.1.0 |
||||
evcon_fd_get_events@Base 0.1.0 |
||||
evcon_fd_get_fd@Base 0.1.0 |
||||
evcon_fd_get_loop@Base 0.1.0 |
||||
evcon_fd_get_user_data@Base 0.1.0 |
||||
evcon_fd_is_active@Base 0.1.0 |
||||
evcon_fd_new@Base 0.1.0 |
||||
evcon_fd_set_backend_data@Base 0.1.0 |
||||
evcon_fd_set_cb@Base 0.1.0 |
||||
evcon_fd_set_events@Base 0.1.0 |
||||
evcon_fd_set_fd@Base 0.1.0 |
||||
evcon_fd_set_user_data@Base 0.1.0 |
||||
evcon_fd_start@Base 0.1.0 |
||||
evcon_fd_stop@Base 0.1.0 |
||||
evcon_feed_async@Base 0.1.0 |
||||
evcon_feed_fd@Base 0.1.0 |
||||
evcon_feed_timer@Base 0.1.0 |
||||
evcon_free@Base 0.1.0 |
||||
evcon_init_fd@Base 0.1.0 |
||||
evcon_loop_get_allocator@Base 0.1.0 |
||||
evcon_loop_get_backend_data@Base 0.1.0 |
||||
evcon_loop_new@Base 0.1.0 |
||||
evcon_loop_ref@Base 0.1.0 |
||||
evcon_loop_set_backend_data@Base 0.1.0 |
||||
evcon_loop_unref@Base 0.1.0 |
||||
evcon_timer_free@Base 0.1.0 |
||||
evcon_timer_get_backend_data@Base 0.1.0 |
||||
evcon_timer_get_cb@Base 0.1.0 |
||||
evcon_timer_get_loop@Base 0.1.0 |
||||
evcon_timer_get_repeat@Base 0.1.0 |
||||
evcon_timer_get_timeout@Base 0.1.0 |
||||
evcon_timer_get_user_data@Base 0.1.0 |
||||
evcon_timer_is_active@Base 0.1.0 |
||||
evcon_timer_new@Base 0.1.0 |
||||
evcon_timer_once@Base 0.1.0 |
||||
evcon_timer_repeat@Base 0.1.0 |
||||
evcon_timer_set_backend_data@Base 0.1.0 |
||||
evcon_timer_set_cb@Base 0.1.0 |
||||
evcon_timer_set_repeat@Base 0.1.0 |
||||
evcon_timer_set_user_data@Base 0.1.0 |
||||
evcon_timer_stop@Base 0.1.0 |
@ -0,0 +1 @@ |
||||
SUBDIRS = core backend-glib backend-ev backend-event tests
|
@ -0,0 +1,16 @@ |
||||
AM_CFLAGS=-I$(srcdir)/../core
|
||||
|
||||
install_libs=
|
||||
install_headers=
|
||||
|
||||
if BUILD_EV |
||||
install_libs += libevcon-ev.la
|
||||
install_headers += evcon-ev.h
|
||||
libevcon_ev_la_CPPFLAGS = $(GLIB_CFLAGS) $(LIBEV_CFLAGS)
|
||||
libevcon_ev_la_LDFLAGS = -export-dynamic -no-undefined $(GLIB_LIBS) $(LIBEV_LIBS)
|
||||
libevcon_ev_la_SOURCES = ev-backend.c
|
||||
libevcon_ev_la_LIBADD = ../core/libevcon.la
|
||||
endif |
||||
|
||||
lib_LTLIBRARIES = $(install_libs)
|
||||
include_HEADERS = $(install_headers)
|
@ -0,0 +1,165 @@ |
||||
|
||||
#include <evcon-ev.h> |
||||
|
||||
#include <evcon-allocator.h> |
||||
#include <evcon-backend.h> |
||||
|
||||
#include <evcon-config-private.h> |
||||
|
||||
#include <glib.h> |
||||
|
||||
#define UNUSED(x) ((void)(x)) |
||||
|
||||
/* ev loop wrapper */ |
||||
|
||||
static void evcon_ev_free_loop(evcon_loop *loop, void *loop_data, void *backend_data) { |
||||
UNUSED(loop); |
||||
UNUSED(backend_data); |
||||
UNUSED(loop_data); |
||||
} |
||||
|
||||
static void evcon_ev_fd_cb(struct ev_loop *loop, ev_io *w, int revents) { |
||||
evcon_fd_watcher *watcher = (evcon_fd_watcher*) w->data; |
||||
int events; |
||||
UNUSED(loop); |
||||
|
||||
events = 0; |
||||
if (0 != (revents & EV_ERROR)) events |= EVCON_ERROR; |
||||
if (0 != (revents & EV_READ)) events |= EVCON_READ; |
||||
if (0 != (revents & EV_WRITE)) events |= EVCON_WRITE; |
||||
|
||||
evcon_feed_fd(watcher, events); |
||||
} |
||||
|
||||
static void evcon_ev_fd_update(evcon_fd_watcher *watcher, evcon_fd fd, int events, evcon_allocator *allocator, void *loop_data, void *watcher_data) { |
||||
ev_io *w = (ev_io*) watcher_data; |
||||
struct ev_loop *evl = (struct ev_loop*) loop_data; |
||||
int evs; |
||||
|
||||
if (-1 == fd) { |
||||
/* delete watcher */ |
||||
if (NULL == w) return; |
||||
|
||||
ev_io_stop(evl, w); |
||||
evcon_free(allocator, w, sizeof(*w)); |
||||
evcon_fd_set_backend_data(watcher, NULL); |
||||
return; |
||||
} |
||||
|
||||
evs = 0; |
||||
if (0 != (events & EVCON_READ)) evs |= EV_READ; |
||||
if (0 != (events & EVCON_WRITE)) evs |= EV_WRITE; |
||||
|
||||
if (NULL == w) { |
||||
w = evcon_alloc0(allocator, sizeof(ev_io)); |
||||
evcon_fd_set_backend_data(watcher, w); |
||||
ev_io_init(w, evcon_ev_fd_cb, fd, evs); |
||||
w->data = watcher; |
||||
if (0 != evs) ev_io_start(evl, w); |
||||
return; |
||||
} |
||||
|
||||
if (w->events == evs && fd == w->fd) return; |
||||
|
||||
ev_io_stop(evl, w); |
||||
ev_io_set(w, fd, evs); |
||||
if (0 != evs) ev_io_start(evl, w); |
||||
} |
||||
|
||||
static void evcon_ev_timer_cb(struct ev_loop *loop, ev_timer *w, int revents) { |
||||
evcon_timer_watcher *watcher = (evcon_timer_watcher*) w->data; |
||||
UNUSED(loop); |
||||
UNUSED(revents); |
||||
|
||||
evcon_feed_timer(watcher); |
||||
} |
||||
|
||||
static void evcon_ev_timer_update(evcon_timer_watcher *watcher, evcon_interval timeout, evcon_allocator *allocator, void *loop_data, void *watcher_data) { |
||||
ev_timer *w = (ev_timer*) watcher_data; |
||||
struct ev_loop *evl = (struct ev_loop*) loop_data; |
||||
|
||||
if (-2 == timeout) { |
||||
/* delete watcher */ |
||||
if (NULL == w) return; |
||||
|
||||
ev_timer_stop(evl, w); |
||||
evcon_free(allocator, w, sizeof(*w)); |
||||
evcon_timer_set_backend_data(watcher, NULL); |
||||
return; |
||||
} |
||||
|
||||
if (-1 == timeout && NULL == w) return; |
||||
|
||||
if (-1 == timeout) { |
||||
ev_timer_stop(evl, w); |
||||
return; |
||||
} |
||||
|
||||
if (NULL == w) { |
||||
w = evcon_alloc0(allocator, sizeof(ev_timer)); |
||||
evcon_timer_set_backend_data(watcher, w); |
||||
ev_timer_init(w, evcon_ev_timer_cb, EVCON_INTERVAL_AS_DOUBLE_SEC(timeout), 0.); |
||||
w->data = watcher; |
||||
ev_timer_start(evl, w); |
||||
return; |
||||
} |
||||
|
||||
ev_timer_stop(evl, w); |
||||
ev_timer_set(w, EVCON_INTERVAL_AS_DOUBLE_SEC(timeout), 0.); |
||||
ev_timer_start(evl, w); |
||||
} |
||||
|
||||
static void evcon_ev_async_cb(struct ev_loop *loop, ev_async *w, int revents) { |
||||
evcon_async_watcher *watcher = (evcon_async_watcher*) w->data; |
||||
UNUSED(loop); |
||||
UNUSED(revents); |
||||
|
||||
evcon_feed_async(watcher); |
||||
} |
||||
|
||||
static void evcon_ev_async_update(evcon_async_watcher *watcher, evcon_async_func f, evcon_allocator *allocator, void *loop_data, void *watcher_data) { |
||||
ev_async *w = (ev_async*) watcher_data; |
||||
struct ev_loop *evl = (struct ev_loop*) loop_data; |
||||
|
||||
switch (f) { |
||||
case EVCON_ASYNC_TRIGGER: |
||||
ev_async_send(evl, w); |
||||
break; |
||||
case EVCON_ASYNC_NEW: |
||||
w = evcon_alloc0(allocator, sizeof(ev_async)); |
||||
evcon_async_set_backend_data(watcher, w); |
||||
ev_async_init(w, evcon_ev_async_cb); |
||||
w->data = watcher; |
||||
ev_async_start(evl, w); |
||||
break; |
||||
case EVCON_ASYNC_FREE: |
||||
if (NULL == w) return; |
||||
|
||||
ev_async_stop(evl, w); |
||||
evcon_free(allocator, w, sizeof(*w)); |
||||
evcon_async_set_backend_data(watcher, NULL); |
||||
return; |
||||
} |
||||
} |
||||
|
||||
static evcon_backend* evcon_ev_backend(evcon_allocator* allocator) { |
||||
static char static_backend_buf[EVCON_BACKEND_RECOMMENDED_SIZE]; |
||||
static volatile evcon_backend* backend = NULL; |
||||
|
||||
if (g_once_init_enter(&backend)) { |
||||
evcon_backend* bcknd = evcon_backend_init(static_backend_buf, sizeof(static_backend_buf), NULL, allocator, evcon_ev_free_loop, evcon_ev_fd_update, evcon_ev_timer_update, evcon_ev_async_update); |
||||
|
||||
g_once_init_leave(&backend, bcknd); |
||||
} |
||||
|
||||
return (evcon_backend*) backend; |
||||
} |
||||
|
||||
evcon_loop* evcon_loop_from_ev(struct ev_loop *loop, evcon_allocator* allocator) { |
||||
evcon_backend *backend = evcon_ev_backend(allocator); |
||||
evcon_loop *evc_loop = evcon_loop_new(backend, allocator); |
||||
|
||||
evcon_loop_set_backend_data(evc_loop, loop); |
||||
|
||||
return evc_loop; |
||||
} |
@ -0,0 +1,10 @@ |
||||
#ifndef __EVCON_EVCON_EV_H |
||||
#define __EVCON_EVCON_EV_H __EVCON_EVCON_EV_H |
||||
|
||||
#include <evcon.h> |
||||
|
||||
#include <ev.h> |
||||
|
||||
evcon_loop* evcon_loop_from_ev(struct ev_loop *loop, evcon_allocator* allocator); |
||||
|
||||
#endif |
@ -0,0 +1,16 @@ |
||||
AM_CFLAGS=-I$(srcdir)/../core
|
||||
|
||||
install_libs=
|
||||
install_headers=
|
||||
|
||||
if BUILD_EVENT |
||||
install_libs += libevcon-event.la
|
||||
install_headers += evcon-event.h
|
||||
libevcon_event_la_CPPFLAGS = $(GLIB_CFLAGS) $(LIBEVENT_CFLAGS)
|
||||
libevcon_event_la_LDFLAGS = -export-dynamic -no-undefined $(GLIB_LIBS) $(LIBEVENT_LIBS)
|
||||
libevcon_event_la_SOURCES = event-backend.c
|
||||
libevcon_event_la_LIBADD = ../core/libevcon.la
|
||||
endif |
||||
|
||||
lib_LTLIBRARIES = $(install_libs)
|
||||
include_HEADERS = $(install_headers)
|
@ -0,0 +1,10 @@ |
||||
#ifndef __EVCON_EVCON_EVENT_H |
||||
#define __EVCON_EVCON_EVENT_H __EVCON_EVCON_EVENT_H |
||||
|
||||
#include <evcon.h> |
||||
|
||||
#include <event2/event.h> |
||||
|
||||
evcon_loop* evcon_loop_from_event(struct event_base *base, evcon_allocator* allocator); |
||||
|
||||
#endif |
@ -0,0 +1,157 @@ |
||||
|
||||
#include <evcon-event.h> |
||||
|
||||
#include <evcon-allocator.h> |
||||
#include <evcon-backend.h> |
||||
|
||||
#include <evcon-config-private.h> |
||||
|
||||
#include <glib.h> |
||||
|
||||
#define UNUSED(x) ((void)(x)) |
||||
|
||||
/* event loop wrapper */ |
||||
|
||||
static void evcon_event_free_loop(evcon_loop *loop, void *loop_data, void *backend_data) { |
||||
UNUSED(loop); |
||||
UNUSED(backend_data); |
||||
UNUSED(loop_data); |
||||
} |
||||
|
||||
static void evcon_event_fd_cb(evutil_socket_t fd, short revents, void *user_data) { |
||||
evcon_fd_watcher *watcher = (evcon_fd_watcher*) user_data; |
||||
int events; |
||||
UNUSED(fd); |
||||
|
||||
events = 0; |
||||
if (0 != (revents & EV_READ)) events |= EVCON_READ; |
||||
if (0 != (revents & EV_WRITE)) events |= EVCON_WRITE; |
||||
|
||||
evcon_feed_fd(watcher, events); |
||||
} |
||||
|
||||
static void evcon_event_fd_update(evcon_fd_watcher *watcher, evcon_fd fd, int events, evcon_allocator *allocator, void *loop_data, void *watcher_data) { |
||||
struct event *w = (struct event*) watcher_data; |
||||
struct event_base *base = (struct event_base*) loop_data; |
||||
short evs; |
||||
UNUSED(allocator); |
||||
|
||||
if (-1 == fd) { |
||||
/* delete watcher */ |
||||
if (NULL == w) return; |
||||
|
||||
event_free(w); |
||||
evcon_fd_set_backend_data(watcher, NULL); |
||||
return; |
||||
} |
||||
|
||||
evs = EV_PERSIST; |
||||
if (0 != (events & EVCON_READ)) evs |= EV_READ; |
||||
if (0 != (events & EVCON_WRITE)) evs |= EV_WRITE; |
||||
|
||||
if (NULL == w) { |
||||
w = event_new(base, fd, evs, evcon_event_fd_cb, watcher); |
||||
evcon_fd_set_backend_data(watcher, w); |
||||
if (EV_PERSIST != evs) event_add(w, NULL); |
||||
return; |
||||
} |
||||
|
||||
if (event_get_events(w) == evs && event_get_fd(w) == fd) return; |
||||
|
||||
event_del(w); |
||||
event_assign(w, base, fd, evs, evcon_event_fd_cb, watcher); |
||||
if (EV_PERSIST != evs) event_add(w, NULL); |
||||
} |
||||
|
||||
static void evcon_event_timer_cb(evutil_socket_t fd, short revents, void *user_data) { |
||||
evcon_timer_watcher *watcher = (evcon_timer_watcher*) user_data; |
||||
UNUSED(fd); |
||||
UNUSED(revents); |
||||
|
||||
evcon_feed_timer(watcher); |
||||
} |
||||
|
||||
static void evcon_event_timer_update(evcon_timer_watcher *watcher, evcon_interval timeout, evcon_allocator *allocator, void *loop_data, void *watcher_data) { |
||||
struct event *w = (struct event*) watcher_data; |
||||
struct event_base *base = (struct event_base*) loop_data; |
||||
struct timeval tv; |
||||
UNUSED(allocator); |
||||
|
||||
if (-2 == timeout) { |
||||
/* delete watcher */ |
||||
if (NULL == w) return; |
||||
|
||||
event_free(w); |
||||
evcon_timer_set_backend_data(watcher, NULL); |
||||
return; |
||||
} |
||||
|
||||
if (-1 == timeout && NULL == w) return; |
||||
|
||||
if (-1 == timeout) { |
||||
event_del(w); |
||||
return; |
||||
} |
||||
|
||||
if (NULL == w) { |
||||
w = event_new(base, -1, EV_TIMEOUT, evcon_event_timer_cb, watcher); |
||||
evcon_timer_set_backend_data(watcher, w); |
||||
} |
||||
|
||||
tv.tv_sec = EVCON_INTERVAL_AS_SEC(timeout); |
||||
//tv.tv_usec = EVCON_INTERVAL_AS_USEC(timeout) % 1000000;
|
||||
event_add(w, &tv); |
||||
} |
||||
|
||||
static void evcon_event_async_cb(evutil_socket_t fd, short revents, void *user_data) { |
||||
evcon_async_watcher *watcher = (evcon_async_watcher*) user_data; |
||||
UNUSED(fd); |
||||
UNUSED(revents); |
||||
|
||||
evcon_feed_async(watcher); |
||||
} |
||||
|
||||
static void evcon_event_async_update(evcon_async_watcher *watcher, evcon_async_func f, evcon_allocator *allocator, void *loop_data, void *watcher_data) { |
||||
struct event *w = (struct event*) watcher_data; |
||||
struct event_base *base = (struct event_base*) loop_data; |
||||
UNUSED(allocator); |
||||
|
||||
switch (f) { |
||||
case EVCON_ASYNC_TRIGGER: |
||||
event_active(w, EV_SIGNAL, 0); |
||||
break; |
||||
case EVCON_ASYNC_NEW: |
||||
w = event_new(base, -1, EV_PERSIST, evcon_event_async_cb, watcher); |
||||
evcon_async_set_backend_data(watcher, w); |
||||
event_add(w, NULL); |
||||
break; |
||||
case EVCON_ASYNC_FREE: |
||||
if (NULL == w) return; |
||||
|
||||
event_free(w); |
||||
evcon_async_set_backend_data(watcher, NULL); |
||||
return; |
||||
} |
||||
} |
||||
|
||||
static evcon_backend* evcon_event_backend(evcon_allocator* allocator) { |
||||
static char static_backend_buf[EVCON_BACKEND_RECOMMENDED_SIZE]; |
||||
static volatile evcon_backend* backend = NULL; |
||||
|
||||
if (g_once_init_enter(&backend)) { |
||||
evcon_backend* bcknd = evcon_backend_init(static_backend_buf, sizeof(static_backend_buf), NULL, allocator, evcon_event_free_loop, evcon_event_fd_update, evcon_event_timer_update, evcon_event_async_update); |
||||
|
||||
g_once_init_leave(&backend, bcknd); |
||||
} |
||||
|
||||
return (evcon_backend*) backend; |
||||
} |
||||
|
||||
evcon_loop* evcon_loop_from_event(struct event_base *base, evcon_allocator* allocator) { |
||||
evcon_backend *backend = evcon_event_backend(allocator); |
||||
evcon_loop *evc_loop = evcon_loop_new(backend, allocator); |
||||
|
||||
evcon_loop_set_backend_data(evc_loop, base); |
||||
|
||||
return evc_loop; |
||||
} |
@ -0,0 +1,16 @@ |
||||
AM_CFLAGS=-I$(srcdir)/../core
|
||||
|
||||
install_libs=
|
||||
install_headers=
|
||||
|
||||
if BUILD_GLIB |
||||
install_libs += libevcon-glib.la
|
||||
install_headers += evcon-glib.h
|
||||
libevcon_glib_la_CPPFLAGS = $(GLIB_CFLAGS)
|
||||
libevcon_glib_la_LDFLAGS = -export-dynamic -no-undefined $(GLIB_LIBS)
|
||||
libevcon_glib_la_SOURCES = glib-allocator.c glib-backend.c
|
||||
libevcon_glib_la_LIBADD = ../core/libevcon.la
|
||||
endif |
||||
|
||||
lib_LTLIBRARIES = $(install_libs)
|
||||
include_HEADERS = $(install_headers)
|
@ -0,0 +1,13 @@ |
||||
#ifndef __EVCON_EVCON_GLIB_H |
||||
#define __EVCON_EVCON_GLIB_H __EVCON_EVCON_GLIB_H |
||||
|
||||
#include <evcon.h> |
||||
|
||||
#include <glib.h> |
||||
|
||||
evcon_allocator* evcon_glib_allocator(void); |
||||
evcon_loop* evcon_loop_from_glib(GMainContext *ctx, evcon_allocator *allocator); |
||||
|
||||
GMainContext* evcon_loop_glib_get_context(evcon_loop *loop); |
||||
|
||||
#endif |
@ -0,0 +1,38 @@ |
||||
|
||||
#include <evcon-glib.h> |
||||
|
||||
#include <evcon-allocator.h> |
||||
|
||||
#include <evcon-config-private.h> |
||||
|
||||
#define UNUSED(x) ((void)(x)) |
||||
|
||||
/* GLib slice wrapper */ |
||||
|
||||
static void* evcon_glib_alloc_cb(size_t size, void* user_data) { |
||||
UNUSED(user_data); |
||||
return g_slice_alloc(size); |
||||
} |
||||
|
||||
static void evcon_glib_free_cb(void *ptr, size_t size, void *user_data) { |
||||
UNUSED(user_data); |
||||
g_slice_free1(size, ptr); |
||||
} |
||||
|
||||
evcon_allocator* evcon_glib_allocator(void) { |
||||
static char static_allocator_buf[EVCON_ALLOCATOR_RECOMMENDED_SIZE]; |
||||
static volatile evcon_allocator* allocator = NULL; |
||||
static volatile int lock = 0; |
||||
|
||||
if (2 == g_atomic_int_get(&lock)) return (evcon_allocator*) allocator; |
||||
|
||||
while (!g_atomic_int_compare_and_exchange(&lock, 0, 1)) { |
||||
if (2 == g_atomic_int_get(&lock)) return (evcon_allocator*) allocator; |
||||
} |
||||
|
||||
allocator = evcon_allocator_init(static_allocator_buf, sizeof(static_allocator_buf), NULL, evcon_glib_alloc_cb, evcon_glib_free_cb); |
||||
|
||||
g_atomic_int_set(&lock, 2); |
||||
|
||||
return (evcon_allocator*) allocator; |
||||
} |
@ -0,0 +1,376 @@ |
||||
|
||||
#define _GNU_SOURCE |
||||
|
||||
#include <evcon-glib.h> |
||||
|
||||
#include <evcon-allocator.h> |
||||
#include <evcon-backend.h> |
||||
|
||||
#include <evcon-config-private.h> |
||||
|
||||
#include <errno.h> |
||||
#include <fcntl.h> |
||||
#include <unistd.h> |
||||
|
||||
#define UNUSED(x) ((void)(x)) |
||||
|
||||
#ifndef EVCON_GLIB_COMPAT_API |
||||
# if GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION < 31 |
||||
# define EVCON_GLIB_COMPAT_API 1 |
||||
# endif |
||||
#endif |
||||
|
||||
#ifdef EVCON_GLIB_COMPAT_API |
||||
|
||||
typedef GMutex* evcon_glib_mutex; |
||||
|
||||
static void evcon_glib_mutex_init(evcon_glib_mutex *m) { |
||||
*m = (*g_thread_functions_for_glib_use.mutex_new)(); |
||||
} |
||||
|
||||
static void evcon_glib_mutex_clear(evcon_glib_mutex *m) { |
||||
GMutex *mx = *m; |
||||
if (g_thread_supported()) (*g_thread_functions_for_glib_use.mutex_free)(mx); |
||||
*m = NULL; |
||||
} |
||||
|
||||
static void evcon_glib_mutex_lock(evcon_glib_mutex *m) { |
||||
GMutex *mx = *m; |
||||
if (g_thread_supported()) (*g_thread_functions_for_glib_use.mutex_lock)(mx); |
||||
} |
||||
|
||||
static void evcon_glib_mutex_unlock(evcon_glib_mutex *m) { |
||||
GMutex *mx = *m; |
||||
if (g_thread_supported()) (*g_thread_functions_for_glib_use.mutex_unlock)(mx); |
||||
} |
||||
|
||||
#else |
||||
|
||||
typedef GMutex evcon_glib_mutex; |
||||
|
||||
static void evcon_glib_mutex_init(evcon_glib_mutex *m) { |
||||
g_mutex_init(m); |
||||
} |
||||
|
||||
static void evcon_glib_mutex_clear(evcon_glib_mutex *m) { |
||||
g_mutex_clear(m); |
||||
} |
||||
|
||||
static void evcon_glib_mutex_lock(evcon_glib_mutex *m) { |
||||
g_mutex_lock(m); |
||||
} |
||||
|
||||
static void evcon_glib_mutex_unlock(evcon_glib_mutex *m) { |
||||
g_mutex_unlock(m); |
||||
} |
||||
|
||||
#endif |
||||
|
||||
/* GLib loop wrapper */ |
||||
|
||||
typedef struct evcon_glib_data evcon_glib_data; |
||||
typedef struct evcon_glib_fd_source evcon_glib_fd_source; |
||||
typedef struct evcon_glib_async_watcher evcon_glib_async_watcher; |
||||
|
||||
struct evcon_glib_data { |
||||
GMainContext *ctx; |
||||
|
||||
gint async_pipe_fds[2]; |
||||
evcon_fd_watcher *async_watcher; |
||||
evcon_glib_mutex async_mutex; |
||||
GQueue async_pending; |
||||
}; |
||||
|
||||
struct evcon_glib_fd_source { |
||||
GSource source; |
||||
GPollFD pollfd; |
||||
evcon_fd_watcher *watcher; |
||||
}; |
||||
|
||||
struct evcon_glib_async_watcher { |
||||
GList pending_link; |
||||
evcon_async_watcher *orig; |
||||
gboolean active; |
||||
}; |
||||
|
||||
static void evcon_glib_free_loop(evcon_loop *loop, void *loop_data, void *backend_data) { |
||||
evcon_glib_data *data = (evcon_glib_data*) loop_data; |
||||
UNUSED(loop); |
||||
UNUSED(backend_data); |
||||
|
||||
evcon_loop_ref(loop); |
||||
evcon_fd_free(data->async_watcher); |
||||
|
||||
close(data->async_pipe_fds[0]); data->async_pipe_fds[0] = -1; |
||||
close(data->async_pipe_fds[1]); data->async_pipe_fds[1] = -1; |
||||
|
||||
g_main_context_ref(data->ctx); |
||||
evcon_glib_mutex_clear(&data->async_mutex); |
||||
g_slice_free(evcon_glib_data, data); |
||||
} |
||||
|
||||
/* own FD poll handling */ |
||||
|
||||
static gboolean fd_source_prepare(GSource *source, gint *timeout); |
||||
static gboolean fd_source_check(GSource *source); |
||||
static gboolean fd_source_dispatch(GSource *source, GSourceFunc callback, gpointer user_data); |
||||
static void fd_source_finalize(GSource *source); |
||||
|
||||
static GSourceFuncs fd_source_funcs = { |
||||
fd_source_prepare, |
||||
fd_source_check, |
||||
fd_source_dispatch, |
||||
fd_source_finalize, 0, 0 |
||||
}; |
||||
|
||||
static gboolean fd_source_prepare(GSource *source, gint *timeout) { |
||||
UNUSED(source); |
||||
*timeout = -1; |
||||
return FALSE; |
||||
} |
||||
static gboolean fd_source_check(GSource *source) { |
||||
evcon_glib_fd_source *watch = (evcon_glib_fd_source*) source; |
||||
return 0 != (watch->pollfd.revents & watch->pollfd.events); |
||||
} |
||||
static gboolean fd_source_dispatch(GSource *source, GSourceFunc callback, gpointer user_data) { |
||||
evcon_glib_fd_source *watch = (evcon_glib_fd_source*) source; |
||||
int events; |
||||
UNUSED(callback); |
||||
UNUSED(user_data); |
||||
|
||||
events = 0; |
||||
watch->pollfd.revents &= watch->pollfd.events; |
||||
if (0 != (watch->pollfd.revents & (G_IO_IN | G_IO_HUP))) events |= EVCON_READ; |
||||
if (0 != (watch->pollfd.revents & G_IO_ERR)) events |= EVCON_ERROR; |
||||
if (0 != (watch->pollfd.revents & G_IO_OUT)) events |= EVCON_WRITE; |
||||
|
||||
if (0 != events) evcon_feed_fd(watch->watcher, events); |
||||
|
||||
return TRUE; |
||||
} |
||||
static void fd_source_finalize(GSource *source) { |
||||
UNUSED(source); |
||||
} |
||||
|
||||
static GSource* fd_source_new(evcon_fd_watcher *watcher) { |
||||
GSource *source = g_source_new(&fd_source_funcs, sizeof(evcon_glib_fd_source)); |
||||
evcon_glib_fd_source *watch = (evcon_glib_fd_source*) source; |
||||
watch->watcher = watcher; |
||||
watch->pollfd.fd = -1; |
||||
watch->pollfd.events = watch->pollfd.revents = 0; |
||||
evcon_fd_set_backend_data(watcher, watch); |
||||
return source; |
||||
} |
||||
|
||||
static void evcon_glib_fd_update(evcon_fd_watcher *watcher, evcon_fd fd, int events, evcon_allocator *allocator, void *loop_data, void *watcher_data) { |
||||
GMainContext *ctx = ((evcon_glib_data*) loop_data)->ctx; |
||||
GSource *source = (GSource*) watcher_data; |
||||
evcon_glib_fd_source *watch; |
||||
int evs; |
||||
UNUSED(allocator); |
||||
|
||||
if (-1 == fd) { |
||||
/* delete watcher */ |
||||
if (NULL == source) return; |
||||
g_source_destroy(source); |
||||
g_source_unref(source); |
||||
return; |
||||
} |
||||
|
||||
if (NULL == source) { |
||||
source = fd_source_new(watcher); |
||||
g_source_attach(source, ctx); |
||||
watch = (evcon_glib_fd_source*) source; |
||||
g_source_add_poll(source, &watch->pollfd); |
||||
} else { |
||||
watch = (evcon_glib_fd_source*) source; |
||||
} |
||||
|
||||
evs = 0; |
||||
if (0 != (events & EVCON_READ)) evs |= G_IO_IN | G_IO_HUP | G_IO_ERR; |
||||
if (0 != (events & EVCON_WRITE)) evs |= G_IO_OUT | G_IO_ERR; |
||||
|
||||
if (fd == watch->pollfd.fd && evs == watch->pollfd.events) return; |
||||
|
||||
if (fd != watch->pollfd.fd) watch->pollfd.revents = 0; |
||||
|
||||
watch->pollfd.fd = fd; |
||||
watch->pollfd.events = evs; |
||||
} |
||||
|
||||
static gboolean evcon_glib_timer_cb(gpointer data) { |
||||
evcon_timer_watcher *watcher = (evcon_timer_watcher*) data; |
||||
evcon_feed_timer(watcher); |
||||
return FALSE; |
||||
} |
||||
|
||||
static void evcon_glib_timer_update(evcon_timer_watcher *watcher, evcon_interval timeout, evcon_allocator *allocator, void *loop_data, void *watcher_data) { |
||||
GMainContext *ctx = ((evcon_glib_data*) loop_data)->ctx; |
||||
GSource *source = (GSource*) watcher_data; |
||||
UNUSED(allocator); |
||||
|
||||
if (NULL != source) { |
||||
/* delete old source */ |
||||
g_source_destroy(source); |
||||
g_source_unref(source); |
||||
} |
||||
|
||||
if (timeout < 0) return; |
||||
|
||||
if (timeout == 0) { |
||||
source = g_idle_source_new(); |
||||
} else { |
||||
source = g_timeout_source_new(EVCON_INTERVAL_AS_MSEC(timeout)); |
||||
} |
||||
evcon_timer_set_backend_data(watcher, source); |
||||
g_source_set_callback(source, evcon_glib_timer_cb, watcher, NULL); |
||||
g_source_attach(source, ctx); |
||||
} |
||||
|
||||
|
||||
static void evcon_glib_async_update(evcon_async_watcher *watcher, evcon_async_func f, evcon_allocator *allocator, void *loop_data, void *watcher_data) { |
||||
static const char val = 'A'; |
||||
evcon_glib_data *data = (evcon_glib_data*) loop_data; |
||||
evcon_glib_async_watcher *w = (evcon_glib_async_watcher*) watcher_data; |
||||
UNUSED(allocator); |
||||
|
||||
evcon_glib_mutex_lock(&data->async_mutex); |
||||
|
||||
switch (f) { |
||||
case EVCON_ASYNC_TRIGGER: |
||||
if (!w->active) { |
||||
w->active = TRUE; |
||||
if (0 == data->async_pending.length) { |
||||
int r; |
||||
trigger_again: |
||||
r = write(data->async_pipe_fds[1], &val, sizeof(val)); |
||||
if (-1 == r) { |
||||
switch (errno) { |
||||
case EINTR: |
||||
goto trigger_again; |
||||
case EAGAIN: |
||||
#if EWOULDBLOCK != EAGAIN |
||||
case EWOULDBLOCK: |
||||
#endif |
||||
break; /* enough data in the pipe to trigger */ |
||||
default: |
||||
g_error("async wake write failed: %s", g_strerror(errno)); |
||||
} |
||||
} |
||||
} |
||||
g_queue_push_tail_link(&data->async_pending, &w->pending_link); |
||||
} |
||||
break; |
||||
case EVCON_ASYNC_NEW: |
||||
w = g_slice_new0(evcon_glib_async_watcher); |
||||
w->pending_link.data = w; |
||||
w->orig = watcher; |
||||
evcon_async_set_backend_data(watcher, w); |
||||
break; |
||||
case EVCON_ASYNC_FREE: |
||||
if (NULL == w) goto exit; |
||||
|
||||
if (w->active) { |
||||
g_queue_unlink(&data->async_pending, &w->pending_link); |
||||
w->active = FALSE; |
||||
} |
||||
g_slice_free(evcon_glib_async_watcher, w); |
||||
evcon_async_set_backend_data(watcher, NULL); |
||||
goto exit; |
||||
} |
||||
|
||||
exit: |
||||
evcon_glib_mutex_unlock(&data->async_mutex); |
||||
} |
||||
|
||||
static void evcon_glib_async_cb(evcon_loop *loop, evcon_fd_watcher *watcher, evcon_fd fd, int revents, void* user_data) { |
||||
evcon_glib_data *data = user_data; |
||||
evcon_glib_async_watcher *w; |
||||
char buf[32]; |
||||
UNUSED(loop); |
||||
UNUSED(watcher); |
||||
UNUSED(revents); |
||||
|
||||
(void) read(fd, buf, sizeof(buf)); |
||||
|
||||
for (;;) { |
||||
{ |
||||
GList *link; |
||||
evcon_glib_mutex_lock(&data->async_mutex); |
||||
link = g_queue_pop_head_link(&data->async_pending); |
||||
if (NULL != link) { |
||||
w = (evcon_glib_async_watcher*) link->data; |
||||
w->active = FALSE; |
||||
} else { |
||||
w = NULL; |
||||
} |
||||
evcon_glib_mutex_unlock(&data->async_mutex); |
||||
} |
||||
|
||||
if (NULL == w) break; |
||||
|
||||
evcon_feed_async(w->orig); |
||||
} |
||||
} |
||||
|
||||
static evcon_backend* evcon_glib_backend(void) { |
||||
static char static_backend_buf[EVCON_BACKEND_RECOMMENDED_SIZE]; |
||||
static volatile evcon_backend* backend = NULL; |
||||
|
||||
if (g_once_init_enter(&backend)) { |
||||
evcon_backend* bcknd = evcon_backend_init(static_backend_buf, sizeof(static_backend_buf), NULL, evcon_glib_allocator(), evcon_glib_free_loop, evcon_glib_fd_update, evcon_glib_timer_update, evcon_glib_async_update); |
||||
|
||||
g_once_init_leave(&backend, bcknd); |
||||
} |
||||
|
||||
return (evcon_backend*) backend; |
||||
} |
||||
|
||||
static gboolean setup_pipe(int fds[2]) { |
||||
#ifdef HAVE_PIPE2 |
||||
if (-1 == pipe2(fds, O_NONBLOCK | O_CLOEXEC)) { |
||||
g_error("Cannot create pipe: %s\n", g_strerror(errno)); |
||||
return FALSE; |
||||
} |
||||
#else |
||||
if (-1 == pipe(fds)) { |
||||
g_error("Cannot create pipe: %s\n", g_strerror(errno)); |
||||
return FALSE; |
||||
} |
||||
|
||||
evcon_init_fd(fds[0]); |
||||
evcon_init_fd(fds[1]); |
||||
#endif |
||||
return TRUE; |
||||
} |
||||
|
||||
evcon_loop* evcon_loop_from_glib(GMainContext *ctx, evcon_allocator *allocator) { |
||||
evcon_backend *backend; |
||||
evcon_glib_data *loop_data; |
||||
evcon_loop *evc_loop; |
||||
int async_pipe_fds[2]; |
||||
|
||||
if (!setup_pipe(async_pipe_fds)) return NULL; |
||||
|
||||
if (NULL == allocator) allocator = evcon_glib_allocator(); |
||||
|
||||
backend = evcon_glib_backend(); |
||||
loop_data = g_slice_new0(evcon_glib_data); |
||||
evc_loop = evcon_loop_new(backend, allocator); |
||||
|
||||
g_main_context_ref(ctx); |
||||
loop_data->ctx = ctx; |
||||
loop_data->async_pipe_fds[0] = async_pipe_fds[0]; |
||||
loop_data->async_pipe_fds[1] = async_pipe_fds[1]; |
||||
evcon_glib_mutex_init(&loop_data->async_mutex); |
||||
evcon_loop_set_backend_data(evc_loop, loop_data); |
||||
|
||||
loop_data->async_watcher = evcon_fd_new(evc_loop, evcon_glib_async_cb, async_pipe_fds[0], EVCON_READ, loop_data); |
||||
evcon_loop_unref(evc_loop); |
||||
|
||||
return evc_loop; |
||||
} |
||||
|
||||
GMainContext* evcon_loop_glib_get_context(evcon_loop *loop) { |
||||
return ((evcon_glib_data*) evcon_loop_get_backend_data(loop))->ctx; |
||||
} |
@ -0,0 +1,16 @@ |
||||
AM_CFLAGS=-I$(srcdir)/../core
|
||||
|
||||
install_libs=
|
||||
install_headers=
|
||||
|
||||
if BUILD_QT |
||||
install_libs += libevcon-qt.la
|
||||
install_headers += evcon-qt.h
|
||||
libevcon_qt_la_CPPFLAGS = $(QT_CFLAGS)
|
||||
libevcon_qt_la_LDFLAGS = -export-dynamic -no-undefined $(QT_LIBS)
|
||||
libevcon_qt_la_SOURCES = evcon-qt.cpp
|
||||
libevcon_qt_la_LIBADD = ../core/libevcon.la
|
||||
endif |
||||
|
||||
lib_LTLIBRARIES = $(install_libs)
|
||||
include_HEADERS = $(install_headers)
|
@ -0,0 +1,14 @@ |
||||
|
||||
install_libs=
|
||||
install_headers=
|
||||
|
||||
install_libs += libevcon.la
|
||||
install_headers += evcon.h evcon-config.h evcon-allocator.h evcon-backend.h
|
||||
libevcon_la_LDFLAGS = -export-dynamic -no-undefined
|
||||
libevcon_la_SOURCES = evcon.c
|
||||
|
||||
lib_LTLIBRARIES = $(install_libs)
|
||||
include_HEADERS = $(install_headers)
|
||||
|
||||
dist-hook: |
||||
rm -f $(distdir)/evcon-config.h
|
@ -0,0 +1,35 @@ |
||||
#ifndef __EVCON_EVCON_ALLOCATOR_H |
||||
#define __EVCON_EVCON_ALLOCATOR_H __EVCON_EVCON_ALLOCATOR_H |
||||
|
||||
#include <evcon.h> |
||||
|
||||
/* Slab allocator */ |
||||
|
||||
/*
|
||||
* public interface |
||||
*/ |
||||
|
||||
void* evcon_alloc(evcon_allocator* allocator, size_t size); |
||||
void* evcon_alloc0(evcon_allocator* allocator, size_t size); |
||||
void evcon_free(evcon_allocator* allocator, void* ptr, size_t size); |
||||
|
||||
/*
|
||||
* implementation interface |
||||
*/ |
||||
|
||||
typedef void* (*evcon_alloc_cb)(size_t size, void* user_data); |
||||
typedef void (*evcon_free_cb)(void *ptr, size_t size, void *user_data); |
||||
|
||||
evcon_allocator* evcon_allocator_new(void* user_data, evcon_alloc_cb alloc_cb, evcon_free_cb free_cb); |
||||
void evcon_allocator_free(evcon_allocator* allocator); /* freeing the allocator should be the last thing your app does */ |
||||
|
||||
#define EVCON_ALLOCATOR_RECOMMENDED_SIZE (4*sizeof(void*)) |
||||
/* if memsize is large enough to contain a backend, initialize it and returns mem. otherwise allocates a new block */ |
||||
evcon_allocator* evcon_allocator_init(char *mem, size_t memsize, |
||||
void *user_data, evcon_alloc_cb alloc_cb, evcon_free_cb free_cb); |
||||
|
||||
/* allows to change user_data */ |
||||
void* evcon_allocator_get_data(evcon_allocator *allocator); |
||||
void evcon_allocator_set_data(evcon_allocator *allocator, void *user_data); |
||||
|
||||
#endif |
@ -0,0 +1,64 @@ |
||||
#ifndef __EVCON_EVCON_BACKEND_H |
||||
#define __EVCON_EVCON_BACKEND_H __EVCON_EVCON_BACKEND_H |
||||
|
||||
#include <evcon.h> |
||||
|
||||
typedef void (*evcon_backend_free_loop_cb)(evcon_loop *loop, void *loop_data, void *backend_data); |
||||
|
||||
/* fd == -1: delete watcher */ |
||||
typedef void (*evcon_backend_fd_update_cb)(evcon_fd_watcher *watcher, evcon_fd fd, int events, evcon_allocator *allocator, void *loop_data, void *watcher_data); |
||||
|
||||
/* special timeout values:
|
||||
* 0: idle watcher (for background jobs) |
||||
* -1: disable temporarily |
||||
* -2: delete watcher |
||||
* gets called after *each* timer event to set a new timeout value |
||||
*/ |
||||
typedef void (*evcon_backend_timer_update_cb)(evcon_timer_watcher *watcher, evcon_interval timeout, evcon_allocator *allocator, void *loop_data, void *watcher_data); |
||||
|
||||
typedef enum { |
||||
EVCON_ASYNC_TRIGGER = 0, /* <- trigger be thread safe */ |
||||
EVCON_ASYNC_NEW = 1, |
||||
EVCON_ASYNC_FREE = 2 |
||||
} evcon_async_func; |
||||
|
||||
typedef void (*evcon_backend_async_update_cb)(evcon_async_watcher *watcher, evcon_async_func f, evcon_allocator *allocator, void *loop_data, void *watcher_data); |
||||
|
||||
evcon_backend* evcon_backend_new(void *backend_data, |
||||
evcon_allocator *allocator, |
||||
evcon_backend_free_loop_cb free_loop_cb, |
||||
evcon_backend_fd_update_cb fd_update_cb, |
||||
evcon_backend_timer_update_cb timer_update_cb, |
||||
evcon_backend_async_update_cb async_udpate_cb); |
||||
void evcon_backend_free(evcon_backend *backend); |
||||
|
||||
#define EVCON_BACKEND_RECOMMENDED_SIZE (8*sizeof(void*)) |
||||
/* if memsize is large enough to contain a backend, initialize it and returns @mem. otherwise alloc a new block */ |
||||
evcon_backend* evcon_backend_init(char *mem, size_t memsize, |
||||
void *backend_data, |
||||
evcon_allocator *allocator, |
||||
evcon_backend_free_loop_cb free_loop_cb, |
||||
evcon_backend_fd_update_cb fd_update_cb, |
||||
evcon_backend_timer_update_cb timer_update_cb, |
||||
evcon_backend_async_update_cb async_udpate_cb); |
||||
|
||||
evcon_loop* evcon_loop_new(evcon_backend *backend, evcon_allocator *allocator); |
||||
|
||||
void* evcon_backend_get_data(evcon_backend *backend); |
||||
void* evcon_loop_get_backend_data(evcon_loop *loop); |
||||
void* evcon_fd_get_backend_data(evcon_fd_watcher *watcher); |
||||
void* evcon_timer_get_backend_data(evcon_timer_watcher *watcher); |
||||
void* evcon_async_get_backend_data(evcon_async_watcher *watcher); |
||||
|
||||
void evcon_backend_set_data(evcon_backend *backend, void *data); |
||||
void evcon_loop_set_backend_data(evcon_loop *loop, void *data); |
||||
void evcon_fd_set_backend_data(evcon_fd_watcher *watcher, void *data); |
||||
void evcon_timer_set_backend_data(evcon_timer_watcher *watcher, void *data); |
||||
void evcon_async_set_backend_data(evcon_async_watcher *watcher, void *data); |
||||
|
||||
|
||||
void evcon_feed_fd(evcon_fd_watcher *watcher, int events); |
||||
void evcon_feed_timer(evcon_timer_watcher *watcher); |
||||
void evcon_feed_async(evcon_async_watcher *watcher); |
||||
|
||||
#endif |
@ -0,0 +1,98 @@ |
||||
/* src/core/evcon-config-private.h.in. Generated from configure.ac by autoheader. */ |
||||
|
||||
/* build for older glib versions even with new headers */ |
||||
#undef EVCON_GLIB_COMPAT_API |
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */ |
||||
#undef HAVE_DLFCN_H |
||||
|
||||
/* Define to 1 if you have the `dup2' function. */ |
||||
#undef HAVE_DUP2 |
||||
|
||||
/* Define to 1 if you have the <ev.h> header file. */ |
||||
#undef HAVE_EV_H |
||||
|
||||
/* Define to 1 if you have the `fork' function. */ |
||||
#undef HAVE_FORK |
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */ |
||||
#undef HAVE_INTTYPES_H |
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */ |
||||
#undef HAVE_MEMORY_H |
||||
|
||||
/* Define to 1 if you have the `pipe2' function. */ |
||||
#undef HAVE_PIPE2 |
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */ |
||||
#undef HAVE_STDINT_H |
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */ |
||||
#undef HAVE_STDLIB_H |
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */ |
||||
#undef HAVE_STRINGS_H |
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */ |
||||
#undef HAVE_STRING_H |
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */ |
||||
#undef HAVE_SYS_STAT_H |
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */ |
||||
#undef HAVE_SYS_TYPES_H |
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */ |
||||
#undef HAVE_UNISTD_H |
||||
|
||||
/* Define to 1 if you have the `vfork' function. */ |
||||
#undef HAVE_VFORK |
||||
|
||||
/* Define to 1 if you have the <vfork.h> header file. */ |
||||
#undef HAVE_VFORK_H |
||||
|
||||
/* Define to 1 if `fork' works. */ |
||||
#undef HAVE_WORKING_FORK |
||||
|
||||
/* Define to 1 if `vfork' works. */ |
||||
#undef HAVE_WORKING_VFORK |
||||
|
||||
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||
*/ |
||||
#undef LT_OBJDIR |
||||
|
||||
/* Name of package */ |
||||