--- a/qmsk/net/lib/event2/event.pxd Fri Sep 25 21:34:04 2009 +0300
+++ b/qmsk/net/lib/event2/event.pxd Sat Sep 26 16:39:20 2009 +0300
@@ -20,9 +20,22 @@
fd - OS file descriptor to watch, or -1
events - bitmask of EV_* flags that represents the events to wait for
- When the event fires, it will "call" this event object. See __call__().
+ When the event fires, it will "call" this event object (see docs for __call__()).
+
+ 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__().
"""
# the underlying event object
cdef lib.event *ev
+ # slightly different meaning from libevent's "active", this is used to track our own refcount
+ cdef readonly bool alive
+
+ # self-refcount scheme
+ cdef object _mark (self)
+ cdef object _unmark (self)
+
+ # methods also used internally
+ cpdef pending (self, short mask = ?)
--- a/qmsk/net/lib/event2/event.pyx Fri Sep 25 21:34:04 2009 +0300
+++ b/qmsk/net/lib/event2/event.pyx Sat Sep 26 16:39:20 2009 +0300
@@ -1,5 +1,6 @@
from qmsk.net.lib.event2.event cimport *
from qmsk.net.lib.event2.base cimport event_base
+cimport qmsk.net.py as py
cdef lib.timeval* build_timeout (lib.timeval *tv, object timeout = None) except? <lib.timeval *>-1 :
"""
@@ -32,14 +33,20 @@
# unpack opaque arg
cdef event ev = <event>arg
+ # drop self-ref if not pending anymore (keep the local ref)
+ # XXX: does the event show up as non-pending here? :/
+ ev._unmark()
+
# invoke
# XXX: logging?
ev(fd, mask)
-
+
cdef class event :
def __init__ (self, event_base base not None, lib.evutil_socket_t fd, short events) :
+ # we don't hold a self-reference yet
+ self.alive = False
# libevent seems to segfault otherwise...
if events & (lib.EV_READ | lib.EV_WRITE) and fd < 0 :
@@ -58,6 +65,9 @@
It is illegal to call this method after calling .add() but before del()/callback!
"""
+
+ if self.alive :
+ 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)
@@ -79,6 +89,9 @@
cdef lib.timeval tv
+ # aquire self-ref
+ self._mark()
+
if lib.event_add(self.ev, build_timeout(&tv, timeout)) < 0 :
raise Exception("event_new")
@@ -90,19 +103,26 @@
If this event has already executed or has never been added this call with have no effect.
"""
+
if lib.event_del(self.ev) < 0 :
raise Exception("event_del")
+ # release self-ref
+ self._unmark()
+
def activate (self, int fd, short mask) :
"""
'Fake' this event as active, triggering the callback.
"""
+
+ # aquire self-ref
+ self._mark()
lib.event_active(self.ev, fd, mask)
- def pending (self, short mask = 0xffff) :
+ cpdef pending (self, short mask = 0xffff) :
"""
Returns a bool indicating if this event is pending (that is, has been .add()'d).
@@ -115,6 +135,31 @@
return bool(lib.event_pending(self.ev, mask, NULL))
+ cdef object _mark (self) :
+ """
+ Refcount magic. Aquires an internal reference *if we don't have one yet*.
+ """
+
+ if not self.alive :
+ self.alive = True
+
+ py.Py_INCREF(self)
+
+
+ cdef object _unmark (self) :
+ """
+ Refcout magic. Releses the internal reference *if we have one* and libevent doesn't think this event is
+ pending anymore.
+
+ XXX: this might cause ourselves to be destroyed... we can't break if that happens.
+ """
+
+ if self.alive and not self.pending() :
+ py.Py_DECREF(self)
+
+ self.alive = False
+
+
property fd :
def __get__ (self) :
"""
@@ -141,7 +186,7 @@
def __dealloc__ (self) :
"""
- Release the event object usign event_free. This should be completely safe as regards out event_base.
+ Release the event object usign event_free. This should be completely safe as regards our event_base.
XXX: what happens if event_base's __dealloc__ is triggered, but there are still event objects alive?
"""
--- a/qmsk/net/py.pxd Fri Sep 25 21:34:04 2009 +0300
+++ b/qmsk/net/py.pxd Sat Sep 26 16:39:20 2009 +0300
@@ -5,6 +5,10 @@
pass
## refcounting
+ # XXX: does this make cython do some dumb refcounting stuff for the object arg?
+ void Py_INCREF (object o)
+ void Py_DECREF (object o)
+
void Py_XDECREF (PyObject *obj)
## object protocol