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