Skip to content

Commit

Permalink
run loop until all handles have been closed when garbage collected
Browse files Browse the repository at this point in the history
  • Loading branch information
koehlma committed Jan 24, 2016
1 parent 81de735 commit cf9b19c
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 27 deletions.
8 changes: 4 additions & 4 deletions tests/test_references.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ def test_references(self):
self.assert_is(loop, uv.Loop._thread_locals.loop)
self.assert_false(loop in uv.Loop._loops)
async = uv.Async()
self.assert_in(loop, uv.Loop._loops)
self.assert_false(async in loop._strong_references)
self.assert_false(loop in uv.Loop._loops)
self.assert_false(async in loop._references)
async.send()
self.assert_in(async, loop._strong_references)
self.assert_in(async, loop._references)
loop.run(uv.RunModes.ONCE)
async.close()
loop.run()
self.assert_false(loop in uv.Loop._loops)
self.assert_false(async in loop._strong_references)
self.assert_false(async in loop._references)
10 changes: 5 additions & 5 deletions uv/handle.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ def __call__(self, cls):
@ffi.callback('uv_close_cb')
def uv_close_cb(uv_handle):
handle = library.detach(uv_handle)
handle.loop.deregister_structure(handle)
""" :type: uv.Handle """
try:
handle.on_closed(handle)
Expand All @@ -79,16 +78,16 @@ def uv_close_cb(uv_handle):
@ffi.callback('uv_close_cb')
def uv_close_cb_finalize(uv_handle):
_finalizing.remove(uv_handle)
library.detach(uv_handle.loop).deregister_structure(handle)


def handle_finalizer(uv_handle):
def handle_finalizer(uv_handle, loop):
# do not garbage collect the handle until it has been closed
_finalizing.add(uv_handle)
# remove attached garbage collected handle
uv_handle.data = ffi.NULL
# TODO: this might lead to data races
lib.uv_close(ffi.cast('uv_handle_t*', uv_handle), uv_close_cb_finalize)
del loop


@HandleTypes.UNKNOWN
Expand Down Expand Up @@ -197,8 +196,9 @@ def __init__(self, uv_handle, loop=None):
:type:
uv.loop.Allocator
"""
common.attach_finalizer(self, handle_finalizer, uv_handle)
self.loop.register_structure(self)
# keep references to the handle and the loop to prevent them
# from being garbage collected
common.attach_finalizer(self, handle_finalizer, uv_handle, self.loop)

@property
def active(self):
Expand Down
36 changes: 18 additions & 18 deletions uv/loop.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import threading
import traceback
import warnings
import weakref

from . import common, error, library
from .library import ffi, lib
Expand Down Expand Up @@ -206,7 +205,19 @@ def uv_walk_cb(uv_handle, c_handles_set):
handles.add(handle)


@ffi.callback('uv_walk_cb')
def uv_walk_cb_close(uv_handle, argument):
if not lib.uv_is_closing(uv_handle):
lib.uv_close(uv_handle, ffi.NULL)


def loop_finalizer(uv_loop):
# remove attached garbage collected loop
uv_loop.data = ffi.NULL
# close all handles and run their close callbacks
lib.uv_walk(uv_loop, uv_walk_cb_close, ffi.NULL)
while lib.uv_run(uv_loop, RunModes.NOWAIT):
pass
lib.uv_loop_close(uv_loop)


Expand Down Expand Up @@ -395,8 +406,7 @@ def __init__(self, allocator=None, default=False, buffer_size=2**16):
"""
self.make_current()

self._strong_references = set()
self._weak_references = weakref.WeakSet()
self._references = set()

@property
def alive(self):
Expand Down Expand Up @@ -470,26 +480,16 @@ def handle_exception(self):
sys.exit(1)

def gc_exclude_structure(self, handle):
self._strong_references.add(handle)

def gc_include_structure(self, handle):
try:
self._strong_references.remove(handle)
except KeyError:
pass

def register_structure(self, structure):
if not self._weak_references:
if not self._references:
with Loop._global_lock:
Loop._loops.add(self)
self._weak_references.add(structure)
self._references.add(handle)

def deregister_structure(self, structure):
def gc_include_structure(self, handle):
try:
self._weak_references.remove(structure)
if not self._weak_references:
self._references.remove(handle)
if not self._references:
with Loop._global_lock:
Loop._loops.remove(self)
except KeyError:
pass

0 comments on commit cf9b19c

Please sign in to comment.