--- a/qmsk/net/lib/event2/base.pxd Sat Sep 26 21:46:36 2009 +0300
+++ b/qmsk/net/lib/event2/base.pxd Sat Sep 26 21:50:42 2009 +0300
@@ -11,10 +11,39 @@
Constructs a new event_base with default parameters.
+ XXX: you must keep a reference to the event_base around yourself!
+ XXX: what happens to events once we are destructed?
+
+ Libevent has its own asynchronous signal-handling mechanism that is incompatible with Python's signal-handling
+ mechanism.
+
+ Technical details:
+ Python's signal handlers will simply set a flag corresponding to the signal, and wait for
+ PyErr_CheckSignals to be run. Following this, libevent's epoll/select/etc() call will return EINTER - but
+ this will only cause libevent to check its own signal state, and continue running.
+
+ To solve this, we register a "wakeup fd" in Python's signal handling system, whereby a byte is written to a
+ socket pair whenever python's signal handler runs. We then register an (internal) event for the other end of
+ this socketpair in the event_base, which then runs the python signal handlers from "inside" of .loop(),
+ propagating exceptions out of .loop() - this solution is more or less equivalent to how libevent's signal
+ handling works.
+
+ This means that python's default signals and any other signals added using the signal module continue to work
+ at the cost of some additional complexity, but any libevent signal-events also work as well :)
+
+ XXX: currently, you can only have one event_base at a time - there should be separate types used for the main
+ thread and sub-threads, since the python signal handling mechanism only works in the main thread.
+
+ XXX: the propagate-exceptions doesn't actually work either, it just aborts the event loop :)
+
XXX: add support for event_config!
XXX: add support for event_base_priority_init!
+
"""
# the underlying ev_base object
cdef lib.event_base *ev_base
+ # internal event for PySignal wakeups
+ cdef lib.event *ev_pysignal
+
--- a/qmsk/net/lib/event2/event.pxd Sat Sep 26 21:46:36 2009 +0300
+++ b/qmsk/net/lib/event2/event.pxd Sat Sep 26 21:50:42 2009 +0300
@@ -25,6 +25,11 @@
The lifetime of event objects is slightly non-trivial, in that they will actually hold a reference to
themselves while "active". In other words, .add() will aquire an internal reference, which will be released
before the __call__().
+
+ XXX: it might be better for refcounting if the event_base were to keep a reference to each event
+ XXX: or if we kept a reference to the event_base? Might be even better
+
+ XXX: propagate errors (including e.g. KeyboardInterrupt?) from __call__ to event_base.loop()?
"""
# the underlying event object
--- a/qmsk/net/lib/event2/event.pyx Sat Sep 26 21:46:36 2009 +0300
+++ b/qmsk/net/lib/event2/event.pyx Sat Sep 26 21:50:42 2009 +0300
@@ -53,7 +53,7 @@
raise ValueError(fd)
# construct event using our internal callback, with self as the arg
- self.ev = lib.event_new(base.ev_base, fd, events, ev_callback, <void *>self)
+ self.ev = lib.event_new(base.ev_base, fd, events, ev_callback, <void *> self)
if self.ev == NULL :
raise Exception("event_new")
@@ -70,7 +70,7 @@
raise RuntimeError("Cannot change event while active")
# interesting... no error return code
- lib.event_assign(self.ev, base.ev_base, fd, events, ev_callback, <void *>self)
+ lib.event_assign(self.ev, base.ev_base, fd, events, ev_callback, <void *> self)
def add (self, timeout = None) :
@@ -197,6 +197,8 @@
class CallbackEvent (event) :
"""
Extends the event type to take a callback and additional arguments to invoke from the __call__ method.
+
+ This will pass the event object itself to the callback in place of the fd.
"""
def __init__ (self, event_base base, lib.evutil_socket_t fd, short events, object callback, *args, **kwargs) :
@@ -209,5 +211,5 @@
self.kwargs = kwargs
def __call__ (self, lib.evutil_socket_t fd, short mask) :
- self.callback(fd, mask, *self.args, **self.kwargs)
+ self.callback(self, mask, *self.args, **self.kwargs)