@@ -36,7 +36,23 @@ def data_received(self, data):
3636 self .trans .close ()
3737
3838
39- class ProactorLoopCtrlC (test_utils .TestCase ):
39+ class WindowsEventsTestCase (test_utils .TestCase ):
40+ def _unraisablehook (self , unraisable ):
41+ # Storing unraisable.object can resurrect an object which is being
42+ # finalized. Storing unraisable.exc_value creates a reference cycle.
43+ self ._unraisable = unraisable
44+ print (unraisable )
45+
46+ def setUp (self ):
47+ self ._prev_unraisablehook = sys .unraisablehook
48+ self ._unraisable = None
49+ sys .unraisablehook = self ._unraisablehook
50+
51+ def tearDown (self ):
52+ sys .unraisablehook = self ._prev_unraisablehook
53+ self .assertIsNone (self ._unraisable )
54+
55+ class ProactorLoopCtrlC (WindowsEventsTestCase ):
4056
4157 def test_ctrl_c (self ):
4258
@@ -58,7 +74,7 @@ def SIGINT_after_delay():
5874 thread .join ()
5975
6076
61- class ProactorMultithreading (test_utils . TestCase ):
77+ class ProactorMultithreading (WindowsEventsTestCase ):
6278 def test_run_from_nonmain_thread (self ):
6379 finished = False
6480
@@ -79,7 +95,7 @@ def func():
7995 self .assertTrue (finished )
8096
8197
82- class ProactorTests (test_utils . TestCase ):
98+ class ProactorTests (WindowsEventsTestCase ):
8399
84100 def setUp (self ):
85101 super ().setUp ()
@@ -239,8 +255,32 @@ def test_read_self_pipe_restart(self):
239255 self .close_loop (self .loop )
240256 self .assertFalse (self .loop .call_exception_handler .called )
241257
242-
243- class WinPolicyTests (test_utils .TestCase ):
258+ def test_loop_restart (self ):
259+ # We're fishing for the "RuntimeError: <_overlapped.Overlapped object at XXX>
260+ # still has pending operation at deallocation, the process may crash" error
261+ stop = threading .Event ()
262+ def threadMain ():
263+ while not stop .is_set ():
264+ self .loop .call_soon_threadsafe (lambda : None )
265+ time .sleep (0.01 )
266+ thr = threading .Thread (target = threadMain )
267+
268+ # In 10 60-second runs of this test prior to the fix:
269+ # time in seconds until failure: (none), 15.0, 6.4, (none), 7.6, 8.3, 1.7, 22.2, 23.5, 8.3
270+ # 10 seconds had a 50% failure rate but longer would be more costly
271+ end_time = time .time () + 10 # Run for 10 seconds
272+ self .loop .call_soon (thr .start )
273+ while not self ._unraisable : # Stop if we got an unraisable exc
274+ self .loop .stop ()
275+ self .loop .run_forever ()
276+ if time .time () >= end_time :
277+ break
278+
279+ stop .set ()
280+ thr .join ()
281+
282+
283+ class WinPolicyTests (WindowsEventsTestCase ):
244284
245285 def test_selector_win_policy (self ):
246286 async def main ():
0 commit comments