Commit 6f469120 authored by Denis Bilenko's avatar Denis Bilenko

core: make sure we never incref events more than once and never decref them...

core: make sure we never incref events more than once and never decref them more than we increfed them. Thanks to Cyril Bay.

This fixes Cyril's test as well as test__server_pywsgi.py/test__server.TestDefaultSpawn.test_error_in_spawn which DECREFed event twice (detected by python-dbg).
parent d01b3f46
...@@ -147,19 +147,19 @@ cdef extern from "libevent.h": ...@@ -147,19 +147,19 @@ cdef extern from "libevent.h":
cdef void __event_handler(int fd, short evtype, void *arg) with gil: cdef void __event_handler(int fd, short evtype, void *arg) with gil:
cdef event ev = <event>arg cdef event self = <event>arg
try: try:
ev._callback(ev, evtype) self._callback(self, evtype)
except: except:
traceback.print_exc() traceback.print_exc()
try: try:
sys.stderr.write('Failed to execute callback for %s\n\n' % (ev, )) sys.stderr.write('Failed to execute callback for %s\n\n' % (self, ))
except: except:
traceback.print_exc() traceback.print_exc()
sys.exc_clear() sys.exc_clear()
finally: finally:
if not event_pending(&ev.ev, EV_READ|EV_WRITE|EV_SIGNAL|EV_TIMEOUT, NULL): if not event_pending(&self.ev, EV_READ|EV_WRITE|EV_SIGNAL|EV_TIMEOUT, NULL):
Py_DECREF(ev) self._delref()
cdef class event: cdef class event:
...@@ -172,16 +172,28 @@ cdef class event: ...@@ -172,16 +172,28 @@ cdef class event:
""" """
cdef event_t ev cdef event_t ev
cdef object _callback, _arg cdef object _callback, _arg
cdef int _incref # 1 if we already INCREFed this object once (because libevent references it)
def __init__(self, short evtype, int handle, callback, arg=None): def __init__(self, short evtype, int handle, callback, arg=None):
self._callback = callback self._callback = callback
self._arg = arg self._arg = arg
self._incref = 0
cdef void* c_self = <void*>self cdef void* c_self = <void*>self
if evtype == 0 and not handle: if evtype == 0 and not handle:
evtimer_set(&self.ev, __event_handler, c_self) evtimer_set(&self.ev, __event_handler, c_self)
else: else:
event_set(&self.ev, handle, evtype, __event_handler, c_self) event_set(&self.ev, handle, evtype, __event_handler, c_self)
cdef _addref(self):
if self._incref <= 0:
Py_INCREF(self)
self._incref += 1
cdef _delref(self):
if self._incref > 0:
Py_DECREF(self)
self._incref -= 1
property callback: property callback:
"""User callback that will be called once the event is signalled. """User callback that will be called once the event is signalled.
...@@ -264,7 +276,6 @@ cdef class event: ...@@ -264,7 +276,6 @@ cdef class event:
cdef timeval tv cdef timeval tv
cdef double c_timeout cdef double c_timeout
cdef int result cdef int result
cdef int need_incref = not event_pending(&self.ev, EV_READ|EV_WRITE|EV_SIGNAL|EV_TIMEOUT, NULL)
errno = 0 # event_add sometime does not set errno errno = 0 # event_add sometime does not set errno
if timeout is None: if timeout is None:
result = event_add(&self.ev, NULL) result = event_add(&self.ev, NULL)
...@@ -284,8 +295,7 @@ cdef class event: ...@@ -284,8 +295,7 @@ cdef class event:
raise IOError(errno, strerror(errno)) raise IOError(errno, strerror(errno))
else: else:
raise IOError("event_add(fileno=%s) returned %s" % (self.fd, result)) raise IOError("event_add(fileno=%s) returned %s" % (self.fd, result))
if need_incref: self._addref()
Py_INCREF(self)
def cancel(self): def cancel(self):
"""Remove event from the event queue.""" """Remove event from the event queue."""
...@@ -294,7 +304,7 @@ cdef class event: ...@@ -294,7 +304,7 @@ cdef class event:
result = event_del(&self.ev) result = event_del(&self.ev)
if result < 0: if result < 0:
return result return result
Py_DECREF(self) self._delref()
return result return result
def __repr__(self): def __repr__(self):
...@@ -364,20 +374,20 @@ class readwrite_event(event): ...@@ -364,20 +374,20 @@ class readwrite_event(event):
cdef void __simple_handler(int fd, short evtype, void *arg) with gil: cdef void __simple_handler(int fd, short evtype, void *arg) with gil:
cdef event ev = <event>arg cdef event self = <event>arg
try: try:
args, kwargs = ev._arg args, kwargs = self._arg
ev._callback(*args, **kwargs) self._callback(*args, **kwargs)
except: except:
traceback.print_exc() traceback.print_exc()
try: try:
sys.stderr.write('Failed to execute callback for %s\n\n' % (ev, )) sys.stderr.write('Failed to execute callback for %s\n\n' % (self, ))
except: except:
traceback.print_exc() traceback.print_exc()
sys.exc_clear() sys.exc_clear()
finally: finally:
if not event_pending(&ev.ev, EV_READ|EV_WRITE|EV_SIGNAL|EV_TIMEOUT, NULL): if not event_pending(&self.ev, EV_READ|EV_WRITE|EV_SIGNAL|EV_TIMEOUT, NULL):
Py_DECREF(ev) self._delref()
cdef class timer(event): cdef class timer(event):
...@@ -407,7 +417,7 @@ cdef class active_event(event): ...@@ -407,7 +417,7 @@ cdef class active_event(event):
self._callback = callback self._callback = callback
self._arg = (args, kwargs) self._arg = (args, kwargs)
evtimer_set(&self.ev, __simple_handler, <void*>self) evtimer_set(&self.ev, __simple_handler, <void*>self)
Py_INCREF(self) self._addref()
event_active(&self.ev, EV_TIMEOUT, 1) event_active(&self.ev, EV_TIMEOUT, 1)
def add(self, timeout=None): def add(self, timeout=None):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment