change CallbackEvent to replace fd with ev, event2 doc/style tweaks
authorTero Marttila <terom@fixme.fi>
Sat, 26 Sep 2009 21:50:42 +0300
changeset 52 722fc70a197a
parent 51 c6b4abfc21da
child 53 b2d407968973
change CallbackEvent to replace fd with ev, event2 doc/style tweaks
qmsk/net/lib/event2/base.pxd
qmsk/net/lib/event2/event.pxd
qmsk/net/lib/event2/event.pyx
--- 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)