@@ -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 ()
@@ -290,8 +306,32 @@ async def probe():
290306
291307 return "done"
292308
293-
294- class WinPolicyTests (test_utils .TestCase ):
309+ def test_loop_restart (self ):
310+ # We're fishing for the "RuntimeError: <_overlapped.Overlapped object at XXX>
311+ # still has pending operation at deallocation, the process may crash" error
312+ stop = threading .Event ()
313+ def threadMain ():
314+ while not stop .is_set ():
315+ self .loop .call_soon_threadsafe (lambda : None )
316+ time .sleep (0.01 )
317+ thr = threading .Thread (target = threadMain )
318+
319+ # In 10 60-second runs of this test prior to the fix:
320+ # time in seconds until failure: (none), 15.0, 6.4, (none), 7.6, 8.3, 1.7, 22.2, 23.5, 8.3
321+ # 10 seconds had a 50% failure rate but longer would be more costly
322+ end_time = time .time () + 10 # Run for 10 seconds
323+ self .loop .call_soon (thr .start )
324+ while not self ._unraisable : # Stop if we got an unraisable exc
325+ self .loop .stop ()
326+ self .loop .run_forever ()
327+ if time .time () >= end_time :
328+ break
329+
330+ stop .set ()
331+ thr .join ()
332+
333+
334+ class WinPolicyTests (WindowsEventsTestCase ):
295335
296336 def test_selector_win_policy (self ):
297337 async def main ():
0 commit comments