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