Initial commit
This commit is contained in:
commit
f5fc31c6b7
|
@ -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;
|
||||