diff --git a/uvloop/_testbase.py b/uvloop/_testbase.py index 4648f66..2a658e8 100644 --- a/uvloop/_testbase.py +++ b/uvloop/_testbase.py @@ -87,6 +87,11 @@ class BaseTestCase(unittest.TestCase, metaclass=BaseTestCaseMeta): gc.collect() gc.collect() + self.assertEqual( + self.loop._debug_uv_handles_total, + self.loop._debug_uv_handles_freed, + 'not all uv_handle_t handles were freed') + self.assertEqual( self.loop._debug_cb_handles_count, 0, 'not all callbacks (call_soon) are GCed') diff --git a/uvloop/handles/handle.pyx b/uvloop/handles/handle.pyx index 5adcda4..904662f 100644 --- a/uvloop/handles/handle.pyx +++ b/uvloop/handles/handle.pyx @@ -68,6 +68,12 @@ cdef class UVHandle: self._free() cdef inline _free(self): + if self._handle == NULL: + return + + IF DEBUG: + self._loop._debug_uv_handles_freed += 1 + PyMem_Free(self._handle) self._handle = NULL @@ -101,6 +107,8 @@ cdef class UVHandle: self._handle.data = self if self._loop._debug: self._source_traceback = tb_extract_stack(sys_getframe(0)) + IF DEBUG: + self._loop._debug_uv_handles_total += 1 cdef inline _start_init(self, Loop loop): IF DEBUG: @@ -303,6 +311,13 @@ cdef void __uv_close_handle_cb(uv.uv_handle_t* handle) with gil: if handle.data is NULL: # The original UVHandle is long dead. Just free the mem of # the uv_handle_t* handler. + + IF DEBUG: + if handle.loop == NULL or handle.loop.data == NULL: + raise RuntimeError( + '__uv_close_handle_cb: handle.loop is invalid') + (handle.loop.data)._debug_uv_handles_freed += 1 + PyMem_Free(handle) else: h = handle.data diff --git a/uvloop/loop.pxd b/uvloop/loop.pxd index 4eea4fe..eedc92d 100644 --- a/uvloop/loop.pxd +++ b/uvloop/loop.pxd @@ -87,6 +87,9 @@ cdef class Loop: readonly object _debug_handles_closed readonly object _debug_handles_current + readonly uint64_t _debug_uv_handles_total + readonly uint64_t _debug_uv_handles_freed + readonly uint64_t _debug_cb_handles_total readonly uint64_t _debug_cb_handles_count readonly uint64_t _debug_cb_timer_handles_total diff --git a/uvloop/loop.pyx b/uvloop/loop.pyx index 427e23f..8e84832 100644 --- a/uvloop/loop.pyx +++ b/uvloop/loop.pyx @@ -98,6 +98,9 @@ cdef class Loop: self._debug_handles_closed = col_Counter() self._debug_handles_total = col_Counter() + self._debug_uv_handles_total = 0 + self._debug_uv_handles_freed = 0 + self._debug_stream_read_cb_total = 0 self._debug_stream_read_eof_total = 0 self._debug_stream_read_errors_total = 0 @@ -871,6 +874,12 @@ cdef class Loop: self._debug_handles_total[name])) print() + print('uv_handle_t (current: {}; freed: {}; total: {})'.format( + self._debug_uv_handles_total - self._debug_uv_handles_freed, + self._debug_uv_handles_freed, + self._debug_uv_handles_total)) + print() + print('--- Streams debug info: ---') print('Write errors: {}'.format( self._debug_stream_write_errors_total))