[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[Libevent-users] Proposal for libevent-2 to provide functions to hide event structure details
Niels and others, # try 4 hopefully correct now and freehaven.net online
please, consider addition of functions to allow access more fields
of struct event a way ensuring compatibility with future libevent version.
The list of possible functions prototypes follow. Implementation is attached
at the end of e-mail.
int event_assign_fd(struct event *ev, evutil_socket_t fd, short events);
int event_assign_callback(struct event *ev, void (*callback)(evutil_socket_t,
short, void *), void *arg);
void *event_get_callback_arg(struct event *ev);
int event_assign_persist(struct event *ev, int persist);
size_t event_struct_size(void);
The rationale:
- hide event structure implementation/layout. Application using these
functions
instead of direct access can keep compatibility with future libevent
versions.
To achieve this separation, functions can not be implemented outside of
libevent.so
- the function event_get_callback_arg allows read stored callback argument
without need of its duplication in additional field of some other
structures
- the functions event_assign_fd, event_assign_callback and
event_assign_persist
allows to allocate event for use with known base in advance and fill FD
and monitored events later. This can be interresting for RT applications,
where malloc should not be part of code executed in critical code paths for
example.
- the event_struct_size functions allows to check for incompatible event size
between libevent version used for program compilation and runtime used
version.
It allows even ensure compatibility for different struct event sizes
in some case. Consider need of large array of libevent structures or use
in structure with open end
struct some_struct {
... some user data fields ...
struct event lev_event[];
}
Above proposed features would help ulevpoll library to be binary compatible
even with future libevent versions.
Some information about ulevpoll library
We have need for FD monitoring for uLan project and other PiKRON company
project in 2007
http://ulan.sourceforge.net/
Use in our university project OCERA CAN/CANopen VCA has been
considered to replace older FD monitoring code as well
http://www.ocera.org/download/components/WP7/index.html
http://ocera.cvs.sourceforge.net/viewvc/ocera/ocera/components/comm/can/canvca/
Because some of these project provide libraries which need to be able
to integrate into different environments and applications, next requirements
have been defined
- use such FD monitoring mechanism, which would be well portable
- even binary version of compiled libraries should not depend
on main loop mechanism used by applications which use our components
=> our libraries have to adapt for main loop used by applications
- our libraries should allow to be used with minimal set of external
dependencies
to allow their use in small embedded applications
- but components should integrate well even with graphical or large
applications,
so should not prevent use of Gtk or Qt for main loop in applications
- the used mechanism should allow to switch to high throughput solution
(as libevent is for example) when required in future.
The ulevpoll library API/ABI has been defined. It exposes minimal amount of
information
directly to user, only "handler" like event trigger structure with minimal set
of fields
and pointer to one field of event base structure with information about used
operations
set
struct ul_evptrig_t {
struct ul_evptrig_data_t *impl_data;
ul_evpbase_t *base;
ul_evpoll_cb_t cb;
};
struct ul_evpbase_t {
const ul_evpoll_ops_t *ops;
};
The base has to be allocated dynamically by library. The ul_evptrig_t is
typically part
of user data structures but all data specific to actual used mechanism are
allocated
during initialization through concrete event base operations set.
The first simple poll based implementation has been provided to allow
standalone use. The use of libevent-1 has been considered as next target,
but after look at libevent-1 distributed with Debian stable, I have found,
that it is unusable for multi-threaded environment. event_base_new() has
not been provided by that version. I implemented epoll based mechanism
for ulevpoll. During its testing some misbehavior in epoll Linux kernel
implementation has been found. Davide Libenzi has kindly provided help
and result is enhancement in Linux epoll implementation and introduction
of keyed wakeups which lead to significant speedup even for plain
blocking read and write socket operations.
Next experiment was to try, if designed ABI really allows components to be
compatible with Gtk/Glib and Qt. Fortunately, usual distributions Qt builds
use Glib main loop so only support for that was added to ulevpoll.
It allows to hide Glib event sources based API under ulevpoll API
for our libraries which can then transparently use Glib main loop
without notice of that. Yet for different threads better performing
epoll base main loop can be used. Even for main thread event loop
it is possible to cascade over ulevpoll Glib abstraction another
ulevpoll base with different mechanism (epoll for example) which
is great win because Glib main loop has horrible scalability.
Then I have finally got to add support for libevent, but I have been
disappointed by version 1. I have looked to version 2 now and added
adaptation for it. It looks much better when compared to version 1.
It really allows multi-threaded support and when more available
by distribution it would allow to use it as high performance
mechanism for ulevpoll.
Snapshot of ulevpoll with libevent-2 support included
http://cmp.felk.cvut.cz/~pisa/ulan/ul_evpoll/ul_evpoll-100108.tar.gz
compile by "make". Invocation of test with selection of libevent-2
_compiled/bin-utils/ul_evpchk libevent2
Test runs some set of timers by default. It react to 'p' with addition
of one pipe transfer. 't' or 'T' allows to add 500 or 5000 active
pipe transfers and reports time to finish 500 transactions for each.
'l' or 'L' add 500 or 4500 inactive pipe transactions. 'q' is quit
from test.
ulevpoll component Git repository (not usable standalone)
http://ulan.git.sourceforge.net/git/gitweb.cgi?p=ulan/ulevpoll
ulevpoll support based on libeven-2
http://ulan.git.sourceforge.net/git/gitweb.cgi?p=ulan/ulevpoll;a=blob;f=ulevpoll/ul_evp_libevent2.c
top-level uLan project repository which loads others as submodules "git
submodule update --init"
http://ulan.git.sourceforge.net/git/gitweb.cgi?p=ulan/ulan
Thanks for comments,
Pavel
Pavel Pisa
e-mail: pisa@xxxxxxxxxxxxxxxx
www: http://cmp.felk.cvut.cz/~pisa
university: http://dce.felk.cvut.cz/
company: http://www.pikron.com/
/*******************************************************************/
int event_assign_fd(struct event *ev, evutil_socket_t fd, short events)
{
if(!_event_initialized((ev), 0)) {
return -1;
}
if (ev->ev_flags & (EVLIST_TIMEOUT | EVLIST_ACTIVE | EVLIST_INSERTED)) {
return -1;
}
ev->ev_fd = fd;
ev->ev_events &= ~(EV_READ | EV_WRITE);
ev->ev_events |= events & (EV_READ | EV_WRITE);
return 0;
}
int event_assign_callback(struct event *ev, void (*callback)(evutil_socket_t,
short, void *), void *arg)
{
if(!_event_initialized((ev), 0)) {
return -1;
}
ev->ev_callback = callback;
ev->ev_arg = arg;
return 0;
}
void *event_get_callback_arg(struct event *ev)
{
return ev->ev_arg;
}
int event_assign_persist(struct event *ev, int persist)
{
if(!_event_initialized((ev), 0)) {
return -1;
}
if (ev->ev_flags & (EVLIST_TIMEOUT | EVLIST_ACTIVE | EVLIST_INSERTED)) {
return -1;
}
if(persist)
ev->ev_events |= EV_PERSIST;
else
ev->ev_events &= ~EV_PERSIST;
return 0;
}
size_t event_struct_size(void)
{
return sizeof(struct event);
}
/*******************************************************************/
-------------------------------------------------------
***********************************************************************
To unsubscribe, send an e-mail to majordomo@xxxxxxxxxxxxx with
unsubscribe libevent-users in the body.