qmsk/net/lib/event2/event.pyx
changeset 50 da394bb715af
parent 47 b45a6648931c
child 52 722fc70a197a
--- 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?
         """