# HG changeset patch # User Tero Marttila # Date 1253972360 -10800 # Node ID da394bb715af950502d716149744425e13b0d4e2 # Parent e2f79e68418ac4aa5ea37590a9f280e96f40aa1e try and keep lib.event2.event objects alive (via self-ref) while pending diff -r e2f79e68418a -r da394bb715af qmsk/net/lib/event2/event.pxd --- 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 = ?) diff -r e2f79e68418a -r da394bb715af qmsk/net/lib/event2/event.pyx --- 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? -1 : """ @@ -32,14 +33,20 @@ # unpack opaque arg cdef event ev = 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, 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? """ diff -r e2f79e68418a -r da394bb715af qmsk/net/py.pxd --- 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