diff --git a/src/gevent/_ffi/loop.py b/src/gevent/_ffi/loop.py index 4fc4f257f..35adf3361 100644 --- a/src/gevent/_ffi/loop.py +++ b/src/gevent/_ffi/loop.py @@ -295,8 +295,6 @@ def assign_standard_callbacks(ffi, lib, callbacks_class, extras=()): # pylint:di -_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 @@ def destroy(self): 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 diff --git a/src/gevent/libev/_corecffi_cdef.c b/src/gevent/libev/_corecffi_cdef.c index dcc1d73ac..3280e9912 100644 --- a/src/gevent/libev/_corecffi_cdef.c +++ b/src/gevent/libev/_corecffi_cdef.c @@ -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); diff --git a/src/gevent/libev/_corecffi_source.c b/src/gevent/libev/_corecffi_source.c index b131b0c37..63b216e52 100644 --- a/src/gevent/libev/_corecffi_source.c +++ b/src/gevent/libev/_corecffi_source.c @@ -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)); +} diff --git a/src/gevent/libev/corecffi.py b/src/gevent/libev/corecffi.py index 84bbb3843..6dab8722c 100644 --- a/src/gevent/libev/corecffi.py +++ b/src/gevent/libev/corecffi.py @@ -265,29 +265,37 @@ def _stop_aux_watchers(self): 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): diff --git a/src/gevent/libuv/loop.py b/src/gevent/libuv/loop.py index 796744c2d..d92ee643e 100644 --- a/src/gevent/libuv/loop.py +++ b/src/gevent/libuv/loop.py @@ -266,51 +266,6 @@ def _setup_for_run_callback(self): 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 @@ def _can_destroy_loop(self, ptr): # 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): """