Commit a5f7a836 authored by Jason Madden's avatar Jason Madden Committed by GitHub

Merge pull request #1111 from gevent/libev-cffi-cleanup

Cleanup the libev destroyed data like the libuv destroyed data.
parents b3eebab9 92d77791
......@@ -295,8 +295,6 @@ else:
_default_loop_destroyed = False
_NOARGS = ()
......@@ -320,9 +318,6 @@ class AbstractLoop(object):
# whether they were the default loop.
_default = None
# A class variable.
_default_loop_destroyed = False
def __init__(self, ffi, lib, watchers, flags=None, default=None):
self._ffi = ffi
self._lib = lib
......@@ -493,21 +488,23 @@ class AbstractLoop(object):
try:
if not self._can_destroy_loop(self._ptr):
return False
self._destroyed_loop(self._ptr)
self._stop_aux_watchers()
self._destroy_loop(self._ptr)
finally:
# not ffi.NULL, we don't want something that can be
# passed to C and crash later. This will create nice friendly
# TypeError from CFFI.
self._ptr = None
del self._handle_to_self
del self._callbacks
del self._keepaliveset
return True
def _can_destroy_loop(self, ptr):
raise NotImplementedError()
def _destroyed_loop(self, ptr):
def _destroy_loop(self, ptr):
raise NotImplementedError()
@property
......
......@@ -237,3 +237,7 @@ extern "Python" {
* object.
*/
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,
// 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):
if libev.ev_is_active(self._check):
self.ref()
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):
self.ref() # we should go through the loop now
def destroy(self):
if self._ptr:
ptr = self._ptr
should_destroy_loop = super(loop, self).destroy()
super(loop, self).destroy()
if globals()["__SYSERR_CALLBACK"] == self._handle_syserr:
set_syserr_cb(None)
if should_destroy_loop:
libev.ev_loop_destroy(ptr)
def _can_destroy_loop(self, ptr):
# Is it marked as destroyed?
return libev.ev_userdata(ptr)
def _destroyed_loop(self, ptr):
def _destroy_loop(self, ptr):
# Mark as destroyed.
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
def MAXPRI(self):
......
......@@ -266,51 +266,6 @@ class loop(AbstractLoop):
self._start_callback_timer()
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):
# We're being asked to destroy a loop that's,
......@@ -320,8 +275,43 @@ class loop(AbstractLoop):
# We track this in the data member.
return ptr.data
def _destroyed_loop(self, ptr):
def _destroy_loop(self, ptr):
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):
"""
......
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