Browse Source

Initial commit

master
Stefan Bühler 9 years ago
commit
f5fc31c6b7
  1. 13
      .gitignore
  2. 22
      COPYING
  3. 12
      Makefile.am
  4. 65
      README.md
  5. 31
      autogen.sh
  6. 126
      configure.ac
  7. 11
      evcon-ev.pc.in
  8. 11
      evcon-event.pc.in
  9. 11
      evcon-glib.pc.in
  10. 11
      evcon.pc.in
  11. 2
      libevcon-ev0.symbols
  12. 2
      libevcon-event0.symbols
  13. 4
      libevcon-glib0.symbols
  14. 66
      libevcon0.symbols
  15. 1
      src/Makefile.am
  16. 16
      src/backend-ev/Makefile.am
  17. 165
      src/backend-ev/ev-backend.c
  18. 10
      src/backend-ev/evcon-ev.h
  19. 16
      src/backend-event/Makefile.am
  20. 10
      src/backend-event/evcon-event.h
  21. 157
      src/backend-event/event-backend.c
  22. 16
      src/backend-glib/Makefile.am
  23. 13
      src/backend-glib/evcon-glib.h
  24. 38
      src/backend-glib/glib-allocator.c
  25. 376
      src/backend-glib/glib-backend.c
  26. 16
      src/backend-qt/Makefile.am
  27. 14
      src/core/Makefile.am
  28. 35
      src/core/evcon-allocator.h
  29. 64
      src/core/evcon-backend.h
  30. 98
      src/core/evcon-config-private.h.in
  31. 9
      src/core/evcon-config.h.in
  32. 564
      src/core/evcon.c
  33. 114
      src/core/evcon.h
  34. 33
      src/tests/Makefile.am
  35. 365
      src/tests/evcon-echo.c
  36. 54
      src/tests/evcon-echo.h
  37. 45
      src/tests/evcon-test-ev.c
  38. 43
      src/tests/evcon-test-event.c
  39. 47
      src/tests/evcon-test-glib.c

13
.gitignore

@ -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

22
COPYING

@ -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.

12
Makefile.am

@ -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

65
README.md

@ -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, ...).

31
autogen.sh

@ -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."

126
configure.ac

@ -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

11
evcon-ev.pc.in

@ -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:

11
evcon-event.pc.in

@ -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:

11
evcon-glib.pc.in

@ -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:

11
evcon.pc.in

@ -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:

2
libevcon-ev0.symbols

@ -0,0 +1,2 @@
libevcon-ev.so.0 libevcon-ev0 #MINVER#
evcon_loop_from_ev@Base 0.1.0

2
libevcon-event0.symbols

@ -0,0 +1,2 @@
libevcon-event.so.0 libevcon-event0 #MINVER#
evcon_loop_from_event@Base 0.1.0

4
libevcon-glib0.symbols

@ -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

66
libevcon0.symbols

@ -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

1
src/Makefile.am

@ -0,0 +1 @@
SUBDIRS = core backend-glib backend-ev backend-event tests

16
src/backend-ev/Makefile.am

@ -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)

165
src/backend-ev/ev-backend.c

@ -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;
}

10
src/backend-ev/evcon-ev.h

@ -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

16
src/backend-event/Makefile.am

@ -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)

10
src/backend-event/evcon-event.h

@ -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

157
src/backend-event/event-backend.c

@ -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;
}

16
src/backend-glib/Makefile.am

@ -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)

13
src/backend-glib/evcon-glib.h

@ -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

38
src/backend-glib/glib-allocator.c

@ -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;
}

376
src/backend-glib/glib-backend.c

@ -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;
}

16
src/backend-qt/Makefile.am

@ -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)

14
src/core/Makefile.am

@ -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

35
src/core/evcon-allocator.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

64
src/core/evcon-backend.h

@ -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

98
src/core/evcon-config-private.h.in

@ -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

9
src/core/evcon-config.h.in

@ -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

564
src/core/evcon.c

@ -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,