# HG changeset patch # Parent 96c88daac37a43a51dce51da14686265ffc1c904 Issue #25868: Block SIGUSR1 in attempt to fix test_eintr hang Posix says that sigwait(), and therefore sigwaitinfo(), is undefined unless the signal in question is blocked. Blocking the signal should avoid a few race conditions that may have been triggering an occasional hang on Free BSD. Also added a counter to the SIGALRM handler to verify that it is being called by Python's sigwaitinfo() implementation, and removed the previous pipe workaround. diff -r 96c88daac37a Lib/test/eintrdata/eintr_tester.py --- a/Lib/test/eintrdata/eintr_tester.py Wed Jan 27 11:52:13 2016 -0500 +++ b/Lib/test/eintrdata/eintr_tester.py Fri Jan 29 03:25:45 2016 +0000 @@ -47,7 +47,8 @@ @classmethod def setUpClass(cls): - cls.orig_handler = signal.signal(signal.SIGALRM, lambda *args: None) + cls.count = 0 + cls.orig_handler = signal.signal(signal.SIGALRM, cls.handler) signal.setitimer(signal.ITIMER_REAL, cls.signal_delay, cls.signal_period) @@ -56,6 +57,10 @@ faulthandler.dump_traceback_later(10 * 60, exit=True) @classmethod + def handler(cls, *args): + cls.count += 1 + + @classmethod def stop_alarm(cls): signal.setitimer(signal.ITIMER_REAL, 0, 0) @@ -379,45 +384,37 @@ @unittest.skipUnless(hasattr(signal, 'sigwaitinfo'), 'need signal.sigwaitinfo()') def test_sigwaitinfo(self): - # Issue #25277, #25868: give a few miliseconds to the parent process - # between os.write() and signal.sigwaitinfo() to works around a race - # condition - self.sleep_time = 0.100 - signum = signal.SIGUSR1 pid = os.getpid() old_handler = signal.signal(signum, lambda *args: None) self.addCleanup(signal.signal, signum, old_handler) - rpipe, wpipe = os.pipe() - code = '\n'.join(( 'import os, time', 'pid = %s' % os.getpid(), 'signum = %s' % int(signum), 'sleep_time = %r' % self.sleep_time, - 'rpipe = %r' % rpipe, - 'os.read(rpipe, 1)', - 'os.close(rpipe)', 'time.sleep(sleep_time)', 'os.kill(pid, signum)', )) - t0 = time.monotonic() - proc = self.subprocess(code, pass_fds=(rpipe,)) - os.close(rpipe) - with kill_on_error(proc): - # sync child-parent - os.write(wpipe, b'x') - os.close(wpipe) - - # parent - signal.sigwaitinfo([signum]) - dt = time.monotonic() - t0 - self.assertEqual(proc.wait(), 0) + old_mask = signal.pthread_sigmask(signal.SIG_BLOCK, {signum}) + try: + t0 = time.monotonic() + proc = self.subprocess(code) + with kill_on_error(proc): + # parent + type(self).count = 0 + signal.sigwaitinfo([signum]) + dt = time.monotonic() - t0 + interrupts = self.count + self.assertEqual(proc.wait(), 0) + finally: + signal.pthread_sigmask(signal.SIG_SETMASK, old_mask) self.assertGreaterEqual(dt, self.sleep_time) + self.assertGreaterEqual(interrupts, 1) @unittest.skipUnless(hasattr(signal, "setitimer"), "requires setitimer()")