> On Sat, Nov 03, 2007 at 03:45:39PM -0700, William Ahern <[EMAIL PROTECTED]> 
> wrote:
> > Curious how you managed to do this. Are you checking the process PID on each
> > loop?
> I considered that, but I think its too slow (one also needs to be careful
> that watchers don't change e.g. epoll state until the getpid check is
> done), or at leats I think I don't want that speed hit, no matter what.

After giving signal handling and threads a lot of thought, I came to these

- requiring pthreads or windows mutexes by default is not acceptable,
  but thats the only way to distribute signal events among event loops
  properly, or globally among many threads if signal handling were global.
- the only way to do it without locking is to only allow a single
  loop to handle events.

This is the interface I came up with to manage multiple loops (which I
think makes more sense than the interface currently in libevent):

   struct ev_loop *ev_default_loop (int methods);
   void ev_default_destroy (void);
   void ev_default_fork (void);

this would create "the default" loop (event_base). ev_default_loop
would always create the same loop, and it would be the one to use for
third-party libraries in general, too. The fork method can be called in
the parent or child (or even in both, or without forking), and it would
destroy and recreate the kernel state but keep all the watchers for the
default loop.

   struct ev_loop *ev_loop_new (int methods);
   void ev_loop_destroy (EV_P);
   void ev_loop_fork (EV_P);

This would create additional loops (event_bases). The difference is that
these cannot handle signals (or child watchers) at all, with the default loop
being the only one to do signal handling.

This would be consistent with how signals are usually handled in a pthreads
environment: block signals in all threads and in one thread handle them all
(sigwait, or using the default mainloop).

No locking inside libevent would be required this way.

I'll implement this in my libev replacement code, unless somebody else comes
up with a better idea.

One such idea that isn't better, but different, would be to require the
user to provide mutex support, such as in ev_init_locking (size, init_cb,
lock_cb, unlock_cb, free_cb) or similar, then use locking and let any
event loop handle the signals and distribute signal events to the relevant
loops. But I am not sure how much locking would be required and I assume
it would be a lot, as one would need to handle the case where one thread
handles a signal for an event_base currently in use by another thread.

Looking at the code in libevent, it seems that signals get handled by
whatever loop was started last, so signal handling is not reliable at all
unless one registers the signal handlers in all threads, which is hard to
do in a thread-safe manner (for the user code).

Having a deterministic model where one loop handles all that would definitely
an improvement over this.

                The choice of a       Deliantra, the free code+content MORPG
      -----==-     _GNU_              http://www.deliantra.net
      ----==-- _       generation
      ---==---(_)__  __ ____  __      Marc Lehmann
      --==---/ / _ \/ // /\ \/ /      [EMAIL PROTECTED]
      -=====/_/_//_/\_,_/ /_/\_\
Libevent-users mailing list

Reply via email to