@ -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 */ | |||
#undef PACKAGE | |||
/* Define to the address where bug reports for this package should be sent. */ | |||
#undef PACKAGE_BUGREPORT | |||
/* Define to the full name of this package. */ | |||
#undef PACKAGE_NAME | |||
/* Define to the full name and version of this package. */ | |||
#undef PACKAGE_STRING | |||
/* Define to the one symbol short name of this package. */ | |||
#undef PACKAGE_TARNAME | |||
/* Define to the home page for this package. */ | |||
#undef PACKAGE_URL | |||
/* Define to the version of this package. */ | |||
#undef PACKAGE_VERSION | |||
/* Define to 1 if you have the ANSI C header files. */ | |||
#undef STDC_HEADERS | |||
/* Version number of package */ | |||
#undef VERSION | |||
/* Define to `int' if <sys/types.h> does not define. */ | |||
#undef pid_t | |||
/* Define to `unsigned int' if <sys/types.h> does not define. */ | |||
#undef size_t | |||
/* Define as `fork' if `vfork' does not work. */ | |||
#undef vfork |
@ -0,0 +1,9 @@ | |||
/* Define to 1 if you have the <inttypes.h> header file. */ | |||
#undef HAVE_INTTYPES_H | |||
/* Define to 1 if you have the <stdint.h> header file. */ | |||
#undef HAVE_STDINT_H | |||
/* Define to 1 if you have the <sys/types.h> header file. */ | |||
#undef HAVE_SYS_TYPES_H |
@ -0,0 +1,564 @@ | |||
#include <evcon.h> | |||
#include <evcon-backend.h> | |||
#include <evcon-allocator.h> | |||
#include <evcon-config-private.h> | |||
#include <assert.h> | |||
#include <fcntl.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <time.h> | |||
#include <unistd.h> | |||
#define EVCON_STR_LEN(s) (s), (sizeof(s)-1) | |||
struct evcon_allocator { | |||
void* user_data; | |||
evcon_alloc_cb alloc_cb; | |||
evcon_free_cb free_cb; | |||
}; | |||
struct evcon_backend { | |||
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_update_cb; | |||
}; | |||
struct evcon_loop { | |||
unsigned int refcount; | |||
void *backend_data; | |||
evcon_backend *backend; | |||
evcon_allocator *allocator; | |||
}; | |||
struct evcon_fd_watcher { | |||
void *user_data; | |||
void *backend_data; | |||
unsigned int active:1, incallback:1, delayed_delete:1; | |||
evcon_loop *loop; | |||
evcon_fd_cb cb; | |||
evcon_fd fd; | |||
int events; | |||
}; | |||
struct evcon_timer_watcher { | |||
void *user_data; | |||
void *backend_data; | |||
unsigned int active:1, incallback:1, delayed_delete:1; | |||
evcon_loop *loop; | |||
evcon_timer_cb cb; | |||
evcon_interval timeout, repeat; | |||
}; | |||
struct evcon_async_watcher { | |||
void *user_data; | |||
void *backend_data; | |||
unsigned int incallback:1, delayed_delete:1; | |||
evcon_loop *loop; | |||
evcon_async_cb cb; | |||
}; | |||
/***************************************************** | |||
* Allocator * | |||
*****************************************************/ | |||
void* evcon_alloc(evcon_allocator* allocator, size_t size) { | |||
void *ptr; | |||
if (NULL == allocator) { | |||
ptr = malloc(size); | |||
} else { | |||
ptr = allocator->alloc_cb(size, allocator->user_data); | |||
} | |||
if (NULL == ptr) { | |||
write(2, EVCON_STR_LEN("evcon_alloc: failed to allocate")); | |||
abort(); | |||
} | |||
return ptr; | |||
} | |||
void* evcon_alloc0(evcon_allocator* allocator, size_t size) { | |||
void *ptr = evcon_alloc(allocator, size); | |||
memset(ptr, 0, size); | |||
return ptr; | |||
} | |||
void evcon_free(evcon_allocator* allocator, void* ptr, size_t size) { | |||
if (NULL == ptr) return; | |||
if (NULL == allocator) { | |||
free(ptr); | |||
} else { | |||
allocator->free_cb(ptr, size, allocator->user_data); | |||
} | |||
} | |||
evcon_allocator* evcon_allocator_new(void* user_data, evcon_alloc_cb alloc_cb, evcon_free_cb free_cb) { | |||
evcon_allocator* allocator; | |||
assert(NULL != alloc_cb); | |||
assert(NULL != free_cb); | |||
allocator = alloc_cb(sizeof(evcon_allocator), user_data); | |||
allocator->user_data = user_data; | |||
allocator->alloc_cb = alloc_cb; | |||
allocator->free_cb = free_cb; | |||
return allocator; | |||
} | |||
void evcon_allocator_free(evcon_allocator* allocator) { | |||
evcon_free_cb free_cb; | |||
void* user_data; | |||
if (NULL == allocator) return; | |||
free_cb = allocator->free_cb; | |||
user_data = allocator->user_data; | |||
memset(allocator, 0, sizeof(evcon_allocator)); | |||
free_cb(allocator, sizeof(evcon_allocator), user_data); | |||
} | |||
evcon_allocator* evcon_allocator_init(char *mem, size_t memsize, | |||
void *user_data, evcon_alloc_cb alloc_cb, evcon_free_cb free_cb) { | |||
evcon_allocator *allocator = (evcon_allocator*) mem; | |||
if (sizeof(evcon_allocator) > memsize) { | |||
return evcon_allocator_new(user_data, alloc_cb, free_cb); | |||
} else { | |||
allocator->user_data = user_data; | |||
allocator->alloc_cb = alloc_cb; | |||
allocator->free_cb = free_cb; | |||
return allocator; | |||
} | |||
} | |||
void* evcon_allocator_get_data(evcon_allocator *allocator) { | |||
return allocator->user_data; | |||
} | |||
void evcon_allocator_set_data(evcon_allocator *allocator, void *user_data) { | |||
allocator->user_data = user_data; | |||
} | |||
/***************************************************** | |||
* Backend * | |||
*****************************************************/ | |||
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_update_cb) { | |||
evcon_backend *backend = evcon_alloc0(allocator, sizeof(evcon_backend)); | |||
backend->backend_data = backend_data; | |||
backend->allocator = allocator; | |||
backend->free_loop_cb = free_loop_cb; | |||
backend->fd_update_cb = fd_update_cb; | |||
backend->timer_update_cb = timer_update_cb; | |||
backend->async_update_cb = async_update_cb; | |||
return backend; | |||
} | |||
void evcon_backend_free(evcon_backend *backend) { | |||
evcon_allocator *allocator; | |||
if (NULL == backend) return; | |||
allocator = backend->allocator; | |||
memset(backend, 0, sizeof(evcon_backend)); | |||
evcon_free(allocator, backend, sizeof(evcon_backend)); | |||
} | |||
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_update_cb) { | |||
evcon_backend *backend = (evcon_backend*) mem; | |||
if (sizeof(evcon_backend) > memsize) { | |||
return evcon_backend_new(backend_data, allocator, free_loop_cb, fd_update_cb, timer_update_cb, async_update_cb); | |||
} else { | |||
backend->backend_data = backend_data; | |||
backend->allocator = allocator; | |||
backend->free_loop_cb = free_loop_cb; | |||
backend->fd_update_cb = fd_update_cb; | |||
backend->timer_update_cb = timer_update_cb; | |||
backend->async_update_cb = async_update_cb; | |||
} | |||
return backend; | |||
} | |||
evcon_loop* evcon_loop_new(evcon_backend *backend, evcon_allocator *allocator) { | |||
evcon_loop *loop; | |||
if (NULL == allocator) allocator = backend->allocator; | |||
loop = evcon_alloc0(allocator, sizeof(evcon_loop)); | |||
loop->refcount = 1; | |||
loop->allocator = allocator; | |||
loop->backend = backend; | |||
return loop; | |||
} | |||
void* evcon_backend_get_data(evcon_backend *backend) { | |||
return backend->backend_data; | |||
} | |||
void* evcon_loop_get_backend_data(evcon_loop *loop) { | |||
return loop->backend_data; | |||
} | |||
void* evcon_fd_get_backend_data(evcon_fd_watcher *watcher) { | |||
return watcher->backend_data; | |||
} | |||