Commit 92d77791 authored by Jason Madden's avatar Jason Madden

Cleanup the libev destroyed data like the libuv destroyed data.

parent b3eebab9
...@@ -295,8 +295,6 @@ else: ...@@ -295,8 +295,6 @@ else:
_default_loop_destroyed = False
_NOARGS = () _NOARGS = ()
...@@ -320,9 +318,6 @@ class AbstractLoop(object): ...@@ -320,9 +318,6 @@ class AbstractLoop(object):
# whether they were the default loop. # whether they were the default loop.
_default = None _default = None
# A class variable.
_default_loop_destroyed = False
def __init__(self, ffi, lib, watchers, flags=None, default=None): def __init__(self, ffi, lib, watchers, flags=None, default=None):
self._ffi = ffi self._ffi = ffi
self._lib = lib self._lib = lib
...@@ -493,21 +488,23 @@ class AbstractLoop(object): ...@@ -493,21 +488,23 @@ class AbstractLoop(object):
try: try:
if not self._can_destroy_loop(self._ptr): if not self._can_destroy_loop(self._ptr):
return False return False
self._destroyed_loop(self._ptr)
self._stop_aux_watchers() self._stop_aux_watchers()
self._destroy_loop(self._ptr)
finally: finally:
# not ffi.NULL, we don't want something that can be # not ffi.NULL, we don't want something that can be
# passed to C and crash later. This will create nice friendly # passed to C and crash later. This will create nice friendly
# TypeError from CFFI. # TypeError from CFFI.
self._ptr = None self._ptr = None
del self._handle_to_self
del self._callbacks
del self._keepaliveset
return True return True
def _can_destroy_loop(self, ptr): def _can_destroy_loop(self, ptr):
raise NotImplementedError() raise NotImplementedError()
def _destroyed_loop(self, ptr): def _destroy_loop(self, ptr):
raise NotImplementedError() raise NotImplementedError()
@property @property
......
...@@ -237,3 +237,7 @@ extern "Python" { ...@@ -237,3 +237,7 @@ extern "Python" {
* object. * object.
*/ */
static void _gevent_generic_callback(struct ev_loop* loop, struct ev_watcher* watcher, int revents); static void _gevent_generic_callback(struct ev_loop* loop, struct ev_watcher* watcher, int revents);
static void gevent_zero_check(struct ev_check* handle);
static void gevent_zero_timer(struct ev_timer* handle);
static void gevent_zero_prepare(struct ev_prepare* handle);
...@@ -52,3 +52,18 @@ static void _gevent_generic_callback(struct ev_loop* loop, ...@@ -52,3 +52,18 @@ static void _gevent_generic_callback(struct ev_loop* loop,
// closing the watcher? // closing the watcher?
} }
} }
static void gevent_zero_timer(struct ev_timer* handle)
{
memset(handle, 0, sizeof(struct ev_timer));
}
static void gevent_zero_check(struct ev_check* handle)
{
memset(handle, 0, sizeof(struct ev_check));
}
static void gevent_zero_prepare(struct ev_prepare* handle)
{
memset(handle, 0, sizeof(struct ev_prepare));
}
...@@ -265,29 +265,37 @@ class loop(AbstractLoop): ...@@ -265,29 +265,37 @@ class loop(AbstractLoop):
if libev.ev_is_active(self._check): if libev.ev_is_active(self._check):
self.ref() self.ref()
libev.ev_check_stop(self._ptr, self._check) libev.ev_check_stop(self._ptr, self._check)
if libev.ev_is_active(self._timer0):
libev.ev_timer_stop(self._timer0)
def _setup_for_run_callback(self): def _setup_for_run_callback(self):
self.ref() # we should go through the loop now self.ref() # we should go through the loop now
def destroy(self): def destroy(self):
if self._ptr: if self._ptr:
ptr = self._ptr super(loop, self).destroy()
should_destroy_loop = super(loop, self).destroy()
if globals()["__SYSERR_CALLBACK"] == self._handle_syserr: if globals()["__SYSERR_CALLBACK"] == self._handle_syserr:
set_syserr_cb(None) set_syserr_cb(None)
if should_destroy_loop:
libev.ev_loop_destroy(ptr)
def _can_destroy_loop(self, ptr): def _can_destroy_loop(self, ptr):
# Is it marked as destroyed? # Is it marked as destroyed?
return libev.ev_userdata(ptr) return libev.ev_userdata(ptr)
def _destroyed_loop(self, ptr): def _destroy_loop(self, ptr):
# Mark as destroyed. # Mark as destroyed.
libev.ev_set_userdata(ptr, ffi.NULL) libev.ev_set_userdata(ptr, ffi.NULL)
libev.ev_loop_destroy(ptr)
libev.gevent_zero_prepare(self._prepare)
libev.gevent_zero_check(self._check)
libev.gevent_zero_timer(self._timer0)
del self._prepare
del self._check
del self._timer0
@property @property
def MAXPRI(self): def MAXPRI(self):
......
...@@ -266,51 +266,6 @@ class loop(AbstractLoop): ...@@ -266,51 +266,6 @@ class loop(AbstractLoop):
self._start_callback_timer() self._start_callback_timer()
libuv.uv_ref(self._timer0) libuv.uv_ref(self._timer0)
def destroy(self):
if self._ptr:
ptr = self._ptr
should_destroy = super(loop, self).destroy()
ptr.data = ffi.NULL
assert self._ptr is None
libuv.uv_stop(ptr)
if not should_destroy:
# The default loop has already been destroyed.
# libuv likes to abort() the process in this case.
return
libuv.gevent_close_all_handles(ptr)
closed_failed = libuv.uv_loop_close(ptr)
if closed_failed:
assert closed_failed == libuv.UV_EBUSY
# We already closed all the handles. Run the loop
# once to let them be cut off from the loop.
ran_has_more_callbacks = libuv.uv_run(ptr, libuv.UV_RUN_ONCE)
if ran_has_more_callbacks:
libuv.uv_run(ptr, libuv.UV_RUN_NOWAIT)
closed_failed = libuv.uv_loop_close(ptr)
assert closed_failed == 0, closed_failed
# Destroy the native resources *after* we have closed
# the loop. If we do it before, walking the handles
# attached to the loop is likely to segfault.
libuv.gevent_zero_check(self._check)
libuv.gevent_zero_check(self._timer0)
libuv.gevent_zero_prepare(self._prepare)
libuv.gevent_zero_timer(self._signal_idle)
del self._check
del self._prepare
del self._signal_idle
del self._timer0
libuv.gevent_zero_loop(ptr)
# Destroy any watchers we're still holding on to.
del self._io_watchers
del self._fork_watchers
del self._child_watchers
def _can_destroy_loop(self, ptr): def _can_destroy_loop(self, ptr):
# We're being asked to destroy a loop that's, # We're being asked to destroy a loop that's,
...@@ -320,8 +275,43 @@ class loop(AbstractLoop): ...@@ -320,8 +275,43 @@ class loop(AbstractLoop):
# We track this in the data member. # We track this in the data member.
return ptr.data return ptr.data
def _destroyed_loop(self, ptr): def _destroy_loop(self, ptr):
ptr.data = ffi.NULL ptr.data = ffi.NULL
libuv.uv_stop(ptr)
libuv.gevent_close_all_handles(ptr)
closed_failed = libuv.uv_loop_close(ptr)
if closed_failed:
assert closed_failed == libuv.UV_EBUSY
# We already closed all the handles. Run the loop
# once to let them be cut off from the loop.
ran_has_more_callbacks = libuv.uv_run(ptr, libuv.UV_RUN_ONCE)
if ran_has_more_callbacks:
libuv.uv_run(ptr, libuv.UV_RUN_NOWAIT)
closed_failed = libuv.uv_loop_close(ptr)
assert closed_failed == 0, closed_failed
# Destroy the native resources *after* we have closed
# the loop. If we do it before, walking the handles
# attached to the loop is likely to segfault.
libuv.gevent_zero_check(self._check)
libuv.gevent_zero_check(self._timer0)
libuv.gevent_zero_prepare(self._prepare)
libuv.gevent_zero_timer(self._signal_idle)
del self._check
del self._prepare
del self._signal_idle
del self._timer0
libuv.gevent_zero_loop(ptr)
# Destroy any watchers we're still holding on to.
del self._io_watchers
del self._fork_watchers
del self._child_watchers
def debug(self): def debug(self):
""" """
......
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