9
9
"""
10
10
11
11
import contextlib
12
- import io
12
+ import faulthandler
13
13
import os
14
14
import select
15
15
import signal
@@ -50,6 +50,10 @@ def setUpClass(cls):
50
50
signal .setitimer (signal .ITIMER_REAL , cls .signal_delay ,
51
51
cls .signal_period )
52
52
53
+ # Issue #25277: Use faulthandler to try to debug a hang on FreeBSD
54
+ if hasattr (faulthandler , 'dump_traceback_later' ):
55
+ faulthandler .dump_traceback_later (10 * 60 , exit = True )
56
+
53
57
@classmethod
54
58
def stop_alarm (cls ):
55
59
signal .setitimer (signal .ITIMER_REAL , 0 , 0 )
@@ -58,6 +62,8 @@ def stop_alarm(cls):
58
62
def tearDownClass (cls ):
59
63
cls .stop_alarm ()
60
64
signal .signal (signal .SIGALRM , cls .orig_handler )
65
+ if hasattr (faulthandler , 'cancel_dump_traceback_later' ):
66
+ faulthandler .cancel_dump_traceback_later ()
61
67
62
68
def subprocess (self , * args , ** kw ):
63
69
cmd_args = (sys .executable , '-c' ) + args
@@ -77,6 +83,9 @@ def _test_wait_multiple(self, wait_func):
77
83
processes = [self .new_sleep_process () for _ in range (num )]
78
84
for _ in range (num ):
79
85
wait_func ()
86
+ # Call the Popen method to avoid a ResourceWarning
87
+ for proc in processes :
88
+ proc .wait ()
80
89
81
90
def test_wait (self ):
82
91
self ._test_wait_multiple (os .wait )
@@ -88,6 +97,8 @@ def test_wait3(self):
88
97
def _test_wait_single (self , wait_func ):
89
98
proc = self .new_sleep_process ()
90
99
wait_func (proc .pid )
100
+ # Call the Popen method to avoid a ResourceWarning
101
+ proc .wait ()
91
102
92
103
def test_waitpid (self ):
93
104
self ._test_wait_single (lambda pid : os .waitpid (pid , 0 ))
@@ -358,59 +369,55 @@ def test_sleep(self):
358
369
359
370
360
371
@unittest .skipUnless (hasattr (signal , "setitimer" ), "requires setitimer()" )
372
+ # bpo-30320: Need pthread_sigmask() to block the signal, otherwise the test
373
+ # is vulnerable to a race condition between the child and the parent processes.
374
+ @unittest .skipUnless (hasattr (signal , 'pthread_sigmask' ),
375
+ 'need signal.pthread_sigmask()' )
361
376
class SignalEINTRTest (EINTRBaseTest ):
362
377
""" EINTR tests for the signal module. """
363
378
364
- @unittest .skipUnless (hasattr (signal , 'sigtimedwait' ),
365
- 'need signal.sigtimedwait()' )
366
- def test_sigtimedwait (self ):
367
- t0 = time .monotonic ()
368
- signal .sigtimedwait ([signal .SIGUSR1 ], self .sleep_time )
369
- dt = time .monotonic () - t0
370
- self .assertGreaterEqual (dt , self .sleep_time )
371
-
372
- @unittest .skipUnless (hasattr (signal , 'sigwaitinfo' ),
373
- 'need signal.sigwaitinfo()' )
374
- def test_sigwaitinfo (self ):
375
- # Issue #25277, #25868: give a few milliseconds to the parent process
376
- # between os.write() and signal.sigwaitinfo() to works around a race
377
- # condition
378
- self .sleep_time = 0.100
379
-
379
+ def check_sigwait (self , wait_func ):
380
380
signum = signal .SIGUSR1
381
381
pid = os .getpid ()
382
382
383
383
old_handler = signal .signal (signum , lambda * args : None )
384
384
self .addCleanup (signal .signal , signum , old_handler )
385
385
386
- rpipe , wpipe = os .pipe ()
387
-
388
386
code = '\n ' .join ((
389
387
'import os, time' ,
390
388
'pid = %s' % os .getpid (),
391
389
'signum = %s' % int (signum ),
392
390
'sleep_time = %r' % self .sleep_time ,
393
- 'rpipe = %r' % rpipe ,
394
- 'os.read(rpipe, 1)' ,
395
- 'os.close(rpipe)' ,
396
391
'time.sleep(sleep_time)' ,
397
392
'os.kill(pid, signum)' ,
398
393
))
399
394
395
+ old_mask = signal .pthread_sigmask (signal .SIG_BLOCK , [signum ])
396
+ self .addCleanup (signal .pthread_sigmask , signal .SIG_UNBLOCK , [signum ])
397
+
400
398
t0 = time .monotonic ()
401
- proc = self .subprocess (code , pass_fds = (rpipe ,))
402
- os .close (rpipe )
399
+ proc = self .subprocess (code )
403
400
with kill_on_error (proc ):
404
- # sync child-parent
405
- os .write (wpipe , b'x' )
406
- os .close (wpipe )
401
+ wait_func (signum )
402
+ dt = time .monotonic () - t0
403
+
404
+ self .assertEqual (proc .wait (), 0 )
407
405
408
- # parent
406
+ @unittest .skipUnless (hasattr (signal , 'sigwaitinfo' ),
407
+ 'need signal.sigwaitinfo()' )
408
+ def test_sigwaitinfo (self ):
409
+ def wait_func (signum ):
409
410
signal .sigwaitinfo ([signum ])
410
- dt = time .monotonic () - t0
411
- self .assertEqual (proc .wait (), 0 )
412
411
413
- self .assertGreaterEqual (dt , self .sleep_time )
412
+ self .check_sigwait (wait_func )
413
+
414
+ @unittest .skipUnless (hasattr (signal , 'sigtimedwait' ),
415
+ 'need signal.sigwaitinfo()' )
416
+ def test_sigtimedwait (self ):
417
+ def wait_func (signum ):
418
+ signal .sigtimedwait ([signum ], 120.0 )
419
+
420
+ self .check_sigwait (wait_func )
414
421
415
422
416
423
@unittest .skipUnless (hasattr (signal , "setitimer" ), "requires setitimer()" )
0 commit comments