Commit 415007e3 authored by Victor Stinner's avatar Victor Stinner

Issue #12316: Fix sigwait() test using threads

Spawn a new process instead of using fork(). Patch written by Charles-François
Natali.
parent 8d233f2c
...@@ -9,6 +9,7 @@ import struct ...@@ -9,6 +9,7 @@ import struct
import subprocess import subprocess
import traceback import traceback
import sys, os, time, errno import sys, os, time, errno
from test.script_helper import assert_python_ok
try: try:
import threading import threading
except ImportError: except ImportError:
...@@ -598,9 +599,23 @@ class PendingSignalsTests(unittest.TestCase): ...@@ -598,9 +599,23 @@ class PendingSignalsTests(unittest.TestCase):
with self.assertRaises(ZeroDivisionError): with self.assertRaises(ZeroDivisionError):
signal.pthread_kill(current, signum) signal.pthread_kill(current, signum)
@unittest.skipUnless(hasattr(signal, 'sigwait'),
'need signal.sigwait()')
@unittest.skipUnless(hasattr(signal, 'pthread_sigmask'), @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
'need signal.pthread_sigmask()') 'need signal.pthread_sigmask()')
def check_sigwait(self, test, signum): @unittest.skipUnless(hasattr(os, 'fork'), 'need os.fork()')
def test_sigwait(self):
def test(signum):
signal.alarm(1)
received = signal.sigwait([signum])
if received != signum:
print("sigwait() received %s, not %s"
% (received, signum),
file=sys.stderr)
os._exit(1)
signum = signal.SIGALRM
# sigwait must be called with the signal blocked: since the current # sigwait must be called with the signal blocked: since the current
# process might have several threads running, we fork() a child process # process might have several threads running, we fork() a child process
# to have a single thread. # to have a single thread.
...@@ -627,46 +642,43 @@ class PendingSignalsTests(unittest.TestCase): ...@@ -627,46 +642,43 @@ class PendingSignalsTests(unittest.TestCase):
else: else:
os._exit(0) os._exit(0)
else: else:
# parent: let the child some time to wait, send him the signal, and # parent: check that the child correcty received the signal
# check it correcty received it
self.assertEqual(os.waitpid(pid, 0), (pid, 0)) self.assertEqual(os.waitpid(pid, 0), (pid, 0))
@unittest.skipUnless(hasattr(signal, 'sigwait'), @unittest.skipUnless(hasattr(signal, 'sigwait'),
'need signal.sigwait()') 'need signal.sigwait()')
@unittest.skipUnless(hasattr(os, 'fork'), 'need os.fork()') @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
def test_sigwait(self): 'need signal.pthread_sigmask()')
def test(signum):
signal.alarm(1)
received = signal.sigwait([signum])
if received != signum:
print("sigwait() received %s, not %s"
% (received, signum),
file=sys.stderr)
os._exit(1)
self.check_sigwait(test, signal.SIGALRM)
@unittest.skipUnless(hasattr(signal, 'sigwait'),
'need signal.sigwait()')
@unittest.skipIf(threading is None, "test needs threading module") @unittest.skipIf(threading is None, "test needs threading module")
@unittest.skipUnless(hasattr(os, 'fork'), 'need os.fork()')
def test_sigwait_thread(self): def test_sigwait_thread(self):
def kill_later(signum): # Check that calling sigwait() from a thread doesn't suspend the whole
# wait until the main thread is waiting in sigwait() # process. A new interpreter is spawned to avoid problems when mixing
time.sleep(1) # threads and fork(): only async-safe functions are allowed between
os.kill(os.getpid(), signum) # fork() and exec().
assert_python_ok("-c", """if True:
def test(signum): import os, threading, sys, time, signal
killer = threading.Thread(target=kill_later, args=(signum,))
# the default handler terminates the process
signum = signal.SIGUSR1
def kill_later():
# wait until the main thread is waiting in sigwait()
time.sleep(1)
os.kill(os.getpid(), signum)
# the signal must be blocked by all the threads
signal.pthread_sigmask(signal.SIG_BLOCK, [signum])
killer = threading.Thread(target=kill_later)
killer.start() killer.start()
received = signal.sigwait([signum]) received = signal.sigwait([signum])
if received != signum: if received != signum:
print("sigwait() received %s, not %s" % (received, signum), print("sigwait() received %s, not %s" % (received, signum),
file=sys.stderr) file=sys.stderr)
os._exit(1) sys.exit(1)
killer.join() killer.join()
# unblock the signal, which should have been cleared by sigwait()
self.check_sigwait(test, signal.SIGUSR1) signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum])
""")
@unittest.skipUnless(hasattr(signal, 'pthread_sigmask'), @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
'need signal.pthread_sigmask()') 'need signal.pthread_sigmask()')
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment