From c13ef66649985025382c64f6af8e3b956411e05b Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 25 May 2011 02:35:58 +0200 Subject: Issue #8407: Fix the signal handler of the signal module: if it is called twice, it now writes the number of the second signal into the wakeup fd. --- Lib/test/test_signal.py | 36 ++++++++++++++++++++++++++++++++---- Modules/signalmodule.c | 9 +++++---- 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py index 3134031..cdd3f3e 100644 --- a/Lib/test/test_signal.py +++ b/Lib/test/test_signal.py @@ -226,10 +226,16 @@ class WakeupSignalTests(unittest.TestCase): TIMEOUT_FULL = 10 TIMEOUT_HALF = 5 - def check_signum(self, *signals): + def handler(self, signum, frame): + pass + + def check_signum(self, *signals, **kw): data = os.read(self.read, len(signals)+1) raised = struct.unpack('%uB' % len(data), data) - self.assertSequenceEqual(raised, signals) + if kw.get('unordered', False): + raised = set(raised) + signals = set(signals) + self.assertEqual(raised, signals) def test_wakeup_fd_early(self): import select @@ -259,16 +265,38 @@ class WakeupSignalTests(unittest.TestCase): self.check_signum(signal.SIGALRM) def test_signum(self): - old_handler = signal.signal(signal.SIGUSR1, lambda x,y:None) + old_handler = signal.signal(signal.SIGUSR1, self.handler) self.addCleanup(signal.signal, signal.SIGUSR1, old_handler) os.kill(os.getpid(), signal.SIGUSR1) os.kill(os.getpid(), signal.SIGALRM) self.check_signum(signal.SIGUSR1, signal.SIGALRM) + @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'), + 'need signal.pthread_sigmask()') + @unittest.skipUnless(hasattr(signal, 'pthread_kill'), + 'need signal.pthread_kill()') + def test_pending(self): + signum1 = signal.SIGUSR1 + signum2 = signal.SIGUSR2 + tid = threading.current_thread().ident + + old_handler = signal.signal(signum1, self.handler) + self.addCleanup(signal.signal, signum1, old_handler) + old_handler = signal.signal(signum2, self.handler) + self.addCleanup(signal.signal, signum2, old_handler) + + signal.pthread_sigmask(signal.SIG_BLOCK, (signum1, signum2)) + signal.pthread_kill(tid, signum1) + signal.pthread_kill(tid, signum2) + # Unblocking the 2 signals calls the C signal handler twice + signal.pthread_sigmask(signal.SIG_UNBLOCK, (signum1, signum2)) + + self.check_signum(signum1, signum2, unordered=True) + def setUp(self): import fcntl - self.alrm = signal.signal(signal.SIGALRM, lambda x,y:None) + self.alrm = signal.signal(signal.SIGALRM, self.handler) self.read, self.write = os.pipe() flags = fcntl.fcntl(self.write, fcntl.F_GETFL, 0) flags = flags | os.O_NONBLOCK diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c index ff65f04..6d27ab3 100644 --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -177,17 +177,18 @@ static void trip_signal(int sig_num) { unsigned char byte; + Handlers[sig_num].tripped = 1; + if (wakeup_fd != -1) { + byte = (unsigned char)sig_num; + write(wakeup_fd, &byte, 1); + } if (is_tripped) return; /* Set is_tripped after setting .tripped, as it gets cleared in PyErr_CheckSignals() before .tripped. */ is_tripped = 1; Py_AddPendingCall(checksignals_witharg, NULL); - if (wakeup_fd != -1) { - byte = (unsigned char)sig_num; - write(wakeup_fd, &byte, 1); - } } static void -- cgit v0.12