[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [Libevent-users] get next timeout from libevent



On Tue, Nov 24, 2009 at 03:31:18PM +0100, Filippo Giunchedi wrote:
 [rewrapped]
> Hi,
>
> we are trying to build a library which uses libevent but also has
> the capability to be integrated into an application's main loop.
> 
> Our solution so far includes three functions:
> - get the list of file descriptions handled by our library
>   (IOW the list of fds in libevent)
> - register a callback to be called whenever a new fd is added
> - perform a step (i.e. basically call libevent loop once)
> 
> This way the application can poll/select on our lib fds and then make a step
> whenever necessary.
>
> So far so good (please correct me if there's something missing :)).

Hm.  I'm not sure this is such a great design.  If the application is
*already* calling poll()/select() for you, then it's redundant to have
Libevent do it as well.  Worse, if the application is actually using
poll or select, then you'll lose all the performance benefits that
you'd get from Libevent's use of fast backends like kqueue, epoll, or
evport.

Also, how are you getting "the list of fds in Libevent"?  FWICT, there
isn't a public interface that exposes that.

>  At this point though the application won't be able to get the
> timeout for the next event because AFAICS libevent's timeout_next()
> isn't supposed to be called from the outside, is this correct?

Right.

I wouldn't object to adding one, if there turn out to be good uses for
it, or as part of a general extension scheme.

>  Also, what would be the correct approach to build a library upon
> libevent which can be then integrated into another main loop?

This are just my initial thoughts, so I don't promise they're very
good ones:

1. If all your library wants from Libevent is read/write operations on
   fds and timeout operations, and you want to give your fds to an
   application main loop that handle select()/poll()/kqueue()/epoll()
   itself, then I wouldn't tie your library so tightly to Libevent at
   all.  Instead, I'd design the library so you could register
   callbacks for the following situations:

     - The library starts caring about read/write on an fd.
     - The library stops caring about read/write on an fd.
     - The library wants to register a timeout.

   Then, you'd want the application's main loop to call you whenever
   an fd should make progress, and whenever a timeout is ready.

   This way, you wouldn't be tied to any specific main loop.  Of
   course, you'd probably want to include a libevent-implementation of
   these functions in a separate library, so that applications that
   *didn't* want to do their own select()/poll() would just be able to
   use the Libevent-based default.

   Of course, with this approach, you're not actually using the
   Libevent main loop at all, so you're stuck with the performance
   characteristics of whatever the application's main loop does.

1a. Alternatively, if you want to hack on Libevent some, you could
    give Libevent the ability to build an event_base that used some
    other event loop API as its backend.  This could be tricky, but it
    might be a fun project, and you'd be able to use all the features
    of Libevent, either with Libevent's main event loop, or an
    application-supplied event loop.

    With this approach you're not actually using the Libevent main
    loop at all either, so the same caveats apply as above.

2. You might be able to get away with just running all your Libevent
   code in a separate thread, so that it doesn't need to interfere
   with the application main loop at all.  This way Libevent can be as
   fast as it can, while the application can keep its loop.  Of
   course, you'd need a good way to communicate back from the Libevent
   thread to the application thread(s).

2a. You could probably add a feature to Libevent so that the main
    event loop could run in one thread, but it wouldn't actually run
    callbacks itself: instead, it would mark events active and signal
    the main thread to wake up by whatever means you like, and then
    the main thread could call another function.

    I'd probably do this with two new event_base_loop flags: one to
    say "only activate events; do not process active events", and
    another saying "run all the active events; do not actually do an
    event loop".  Then your Libevent thread would say something like:

        while(1) {
           event_base_loop(base, EVLOOP_ACTIVATE_ONLY);
           alert_application();
        }

    And your application's main loop would just need to be set up so
    that it ran "event_base_loop(base, EVLOOP_PROCESSS_ONLY)" whenever
    the Libevent thread called 'alert_application()'.

    Of course, you'd need to do this based on Libevent 2.0.x, since
    earlier versions don't support manipulating an event_base from
    outside the thread it's running in.

    This is my favorite approach so far, since it lets you actually
    use Libevent's event loop (for performance) and the application's
    event loop in parallel without forcing the application to know
    that it's multi-threaded.

These are far from the only designs, I'd bet.  Other people can
probably suggest other designs here too; probably even better ones.

yrs,
-- 
Nick
***********************************************************************
To unsubscribe, send an e-mail to majordomo@xxxxxxxxxxxxx with
unsubscribe libevent-users    in the body.