blob: 50cae0793b56a7ab8c55d9cf4a712733414cf2f1 [file] [log] [blame]
Thomas Woutersed03b412007-08-28 21:37:11 +00001import unittest
Benjamin Petersonee8712c2008-05-20 21:35:26 +00002from test import support
Raymond Hettinger722d8c32009-06-18 22:21:03 +00003from contextlib import closing
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +02004import enum
Christian Heimescc47b052008-03-25 14:56:36 +00005import gc
Christian Heimes4fbc72b2008-03-22 00:47:35 +00006import pickle
7import select
Guido van Rossum4f17e3e1995-03-16 15:07:38 +00008import signal
Victor Stinnerd49b1f12011-05-08 02:03:15 +02009import struct
Christian Heimes4fbc72b2008-03-22 00:47:35 +000010import subprocess
11import traceback
Christian Heimesc06950e2008-02-28 21:17:00 +000012import sys, os, time, errno
Victor Stinnerd6284962011-06-20 23:28:09 +020013from test.script_helper import assert_python_ok, spawn_python
Victor Stinnerb3e72192011-05-08 01:46:11 +020014try:
15 import threading
16except ImportError:
17 threading = None
Christian Heimesc06950e2008-02-28 21:17:00 +000018
Guido van Rossumcc5a91d1997-04-16 00:29:15 +000019
Armin Rigo8b2cbfd2004-08-07 21:27:43 +000020class HandlerBCalled(Exception):
21 pass
Guido van Rossum4f17e3e1995-03-16 15:07:38 +000022
Christian Heimes4fbc72b2008-03-22 00:47:35 +000023
24def exit_subprocess():
25 """Use os._exit(0) to exit the current subprocess.
26
27 Otherwise, the test catches the SystemExit and continues executing
28 in parallel with the original test, so you wind up with an
29 exponential number of tests running concurrently.
30 """
31 os._exit(0)
32
33
Benjamin Petersonad9d48d2008-04-02 21:49:44 +000034def ignoring_eintr(__func, *args, **kwargs):
35 try:
36 return __func(*args, **kwargs)
Andrew Svetlov3438fa42012-12-17 23:35:18 +020037 except OSError as e:
Neal Norwitzf5c7c2e2008-04-05 04:47:45 +000038 if e.errno != errno.EINTR:
Benjamin Petersonad9d48d2008-04-02 21:49:44 +000039 raise
40 return None
41
42
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +020043class GenericTests(unittest.TestCase):
44
Stefan Krah63c4b242014-04-15 22:40:06 +020045 @unittest.skipIf(threading is None, "test needs threading module")
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +020046 def test_enums(self):
47 for name in dir(signal):
48 sig = getattr(signal, name)
49 if name in {'SIG_DFL', 'SIG_IGN'}:
50 self.assertIsInstance(sig, signal.Handlers)
51 elif name in {'SIG_BLOCK', 'SIG_UNBLOCK', 'SIG_SETMASK'}:
52 self.assertIsInstance(sig, signal.Sigmasks)
53 elif name.startswith('SIG') and not name.startswith('SIG_'):
54 self.assertIsInstance(sig, signal.Signals)
55 elif name.startswith('CTRL_'):
56 self.assertIsInstance(sig, signal.Signals)
57 self.assertEqual(sys.platform, "win32")
58
59
Brian Curtin3f004b12010-08-06 19:34:52 +000060@unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
Thomas Woutersed03b412007-08-28 21:37:11 +000061class InterProcessSignalTests(unittest.TestCase):
62 MAX_DURATION = 20 # Entire test should last at most 20 sec.
Guido van Rossum4f17e3e1995-03-16 15:07:38 +000063
Christian Heimescc47b052008-03-25 14:56:36 +000064 def setUp(self):
65 self.using_gc = gc.isenabled()
66 gc.disable()
67
68 def tearDown(self):
69 if self.using_gc:
70 gc.enable()
71
Christian Heimes5e696852008-04-09 08:37:03 +000072 def format_frame(self, frame, limit=None):
73 return ''.join(traceback.format_stack(frame, limit=limit))
74
75 def handlerA(self, signum, frame):
Thomas Woutersed03b412007-08-28 21:37:11 +000076 self.a_called = True
Guido van Rossum4f17e3e1995-03-16 15:07:38 +000077
Christian Heimes5e696852008-04-09 08:37:03 +000078 def handlerB(self, signum, frame):
Thomas Woutersed03b412007-08-28 21:37:11 +000079 self.b_called = True
Christian Heimes5e696852008-04-09 08:37:03 +000080 raise HandlerBCalled(signum, self.format_frame(frame))
Neal Norwitz9730bcb2006-01-23 07:50:06 +000081
Christian Heimes4fbc72b2008-03-22 00:47:35 +000082 def wait(self, child):
83 """Wait for child to finish, ignoring EINTR."""
84 while True:
85 try:
86 child.wait()
87 return
88 except OSError as e:
89 if e.errno != errno.EINTR:
90 raise
Fred Drake004d5e62000-10-23 17:22:08 +000091
Christian Heimes4fbc72b2008-03-22 00:47:35 +000092 def run_test(self):
93 # Install handlers. This function runs in a sub-process, so we
94 # don't worry about re-setting the default handlers.
95 signal.signal(signal.SIGHUP, self.handlerA)
96 signal.signal(signal.SIGUSR1, self.handlerB)
97 signal.signal(signal.SIGUSR2, signal.SIG_IGN)
98 signal.signal(signal.SIGALRM, signal.default_int_handler)
Michael W. Hudson5c26e862004-06-11 18:09:28 +000099
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000100 # Variables the signals will modify:
101 self.a_called = False
102 self.b_called = False
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000103
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000104 # Let the sub-processes know who to send signals to.
105 pid = os.getpid()
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000106
Benjamin Petersonad9d48d2008-04-02 21:49:44 +0000107 child = ignoring_eintr(subprocess.Popen, ['kill', '-HUP', str(pid)])
108 if child:
109 self.wait(child)
110 if not self.a_called:
111 time.sleep(1) # Give the signal time to be delivered.
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000112 self.assertTrue(self.a_called)
113 self.assertFalse(self.b_called)
114 self.a_called = False
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000115
Christian Heimes5e696852008-04-09 08:37:03 +0000116 # Make sure the signal isn't delivered while the previous
117 # Popen object is being destroyed, because __del__ swallows
118 # exceptions.
119 del child
Thomas Woutersed03b412007-08-28 21:37:11 +0000120 try:
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000121 child = subprocess.Popen(['kill', '-USR1', str(pid)])
122 # This wait should be interrupted by the signal's exception.
123 self.wait(child)
Benjamin Petersonad9d48d2008-04-02 21:49:44 +0000124 time.sleep(1) # Give the signal time to be delivered.
Andrew Svetlov737fb892012-12-18 21:14:22 +0200125 self.fail('HandlerBCalled exception not raised')
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000126 except HandlerBCalled:
127 self.assertTrue(self.b_called)
128 self.assertFalse(self.a_called)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000129
Benjamin Petersonad9d48d2008-04-02 21:49:44 +0000130 child = ignoring_eintr(subprocess.Popen, ['kill', '-USR2', str(pid)])
131 if child:
132 self.wait(child) # Nothing should happen.
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000133
134 try:
135 signal.alarm(1)
136 # The race condition in pause doesn't matter in this case,
137 # since alarm is going to raise a KeyboardException, which
138 # will skip the call.
139 signal.pause()
Benjamin Petersonad9d48d2008-04-02 21:49:44 +0000140 # But if another signal arrives before the alarm, pause
141 # may return early.
142 time.sleep(1)
Thomas Woutersed03b412007-08-28 21:37:11 +0000143 except KeyboardInterrupt:
Victor Stinner3a7f0f02011-05-08 02:10:36 +0200144 pass
Thomas Woutersed03b412007-08-28 21:37:11 +0000145 except:
Benjamin Petersonad9d48d2008-04-02 21:49:44 +0000146 self.fail("Some other exception woke us from pause: %s" %
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000147 traceback.format_exc())
148 else:
Benjamin Petersonad9d48d2008-04-02 21:49:44 +0000149 self.fail("pause returned of its own accord, and the signal"
150 " didn't arrive after another second.")
Thomas Woutersed03b412007-08-28 21:37:11 +0000151
R. David Murray44546f82010-04-21 01:59:28 +0000152 # Issue 3864, unknown if this affects earlier versions of freebsd also
153 @unittest.skipIf(sys.platform=='freebsd6',
154 'inter process signals not reliable (do not mix well with threading) '
155 'on freebsd6')
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000156 def test_main(self):
157 # This function spawns a child process to insulate the main
158 # test-running process from all the signals. It then
159 # communicates with that child process over a pipe and
160 # re-raises information about any exceptions the child
Andrew Svetlov737fb892012-12-18 21:14:22 +0200161 # raises. The real work happens in self.run_test().
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000162 os_done_r, os_done_w = os.pipe()
Raymond Hettinger686057b2009-06-04 00:11:54 +0000163 with closing(os.fdopen(os_done_r, 'rb')) as done_r, \
164 closing(os.fdopen(os_done_w, 'wb')) as done_w:
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000165 child = os.fork()
166 if child == 0:
167 # In the child process; run the test and report results
168 # through the pipe.
169 try:
170 done_r.close()
171 # Have to close done_w again here because
172 # exit_subprocess() will skip the enclosing with block.
173 with closing(done_w):
174 try:
175 self.run_test()
176 except:
177 pickle.dump(traceback.format_exc(), done_w)
178 else:
179 pickle.dump(None, done_w)
180 except:
181 print('Uh oh, raised from pickle.')
182 traceback.print_exc()
183 finally:
184 exit_subprocess()
185
186 done_w.close()
187 # Block for up to MAX_DURATION seconds for the test to finish.
188 r, w, x = select.select([done_r], [], [], self.MAX_DURATION)
189 if done_r in r:
190 tb = pickle.load(done_r)
191 if tb:
192 self.fail(tb)
193 else:
194 os.kill(child, signal.SIGKILL)
195 self.fail('Test deadlocked after %d seconds.' %
196 self.MAX_DURATION)
Thomas Woutersed03b412007-08-28 21:37:11 +0000197
198
Brian Curtin3f004b12010-08-06 19:34:52 +0000199@unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
Victor Stinnerb3e72192011-05-08 01:46:11 +0200200class PosixTests(unittest.TestCase):
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000201 def trivial_signal_handler(self, *args):
202 pass
203
Thomas Woutersed03b412007-08-28 21:37:11 +0000204 def test_out_of_range_signal_number_raises_error(self):
205 self.assertRaises(ValueError, signal.getsignal, 4242)
206
Thomas Woutersed03b412007-08-28 21:37:11 +0000207 self.assertRaises(ValueError, signal.signal, 4242,
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000208 self.trivial_signal_handler)
Thomas Woutersed03b412007-08-28 21:37:11 +0000209
210 def test_setting_signal_handler_to_none_raises_error(self):
211 self.assertRaises(TypeError, signal.signal,
212 signal.SIGUSR1, None)
213
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000214 def test_getsignal(self):
215 hup = signal.signal(signal.SIGHUP, self.trivial_signal_handler)
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +0200216 self.assertIsInstance(hup, signal.Handlers)
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000217 self.assertEqual(signal.getsignal(signal.SIGHUP),
218 self.trivial_signal_handler)
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000219 signal.signal(signal.SIGHUP, hup)
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000220 self.assertEqual(signal.getsignal(signal.SIGHUP), hup)
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000221
222
Brian Curtin3f004b12010-08-06 19:34:52 +0000223@unittest.skipUnless(sys.platform == "win32", "Windows specific")
224class WindowsSignalTests(unittest.TestCase):
225 def test_issue9324(self):
Brian Curtineccd4d92010-10-01 15:09:53 +0000226 # Updated for issue #10003, adding SIGBREAK
Brian Curtin3f004b12010-08-06 19:34:52 +0000227 handler = lambda x, y: None
Nick Coghlan60b3ac72013-08-03 22:56:30 +1000228 checked = set()
Brian Curtineccd4d92010-10-01 15:09:53 +0000229 for sig in (signal.SIGABRT, signal.SIGBREAK, signal.SIGFPE,
230 signal.SIGILL, signal.SIGINT, signal.SIGSEGV,
231 signal.SIGTERM):
Nick Coghlan60b3ac72013-08-03 22:56:30 +1000232 # Set and then reset a handler for signals that work on windows.
233 # Issue #18396, only for signals without a C-level handler.
234 if signal.getsignal(sig) is not None:
235 signal.signal(sig, signal.signal(sig, handler))
236 checked.add(sig)
237 # Issue #18396: Ensure the above loop at least tested *something*
238 self.assertTrue(checked)
Brian Curtin3f004b12010-08-06 19:34:52 +0000239
240 with self.assertRaises(ValueError):
241 signal.signal(-1, handler)
Brian Curtin80cd4bf2010-08-07 03:52:38 +0000242
243 with self.assertRaises(ValueError):
244 signal.signal(7, handler)
Brian Curtin3f004b12010-08-06 19:34:52 +0000245
246
Benjamin Petersonc68a4a02013-01-18 00:10:24 -0500247class WakeupFDTests(unittest.TestCase):
248
249 def test_invalid_fd(self):
250 fd = support.make_bad_fd()
251 self.assertRaises(ValueError, signal.set_wakeup_fd, fd)
252
253
Brian Curtin3f004b12010-08-06 19:34:52 +0000254@unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000255class WakeupSignalTests(unittest.TestCase):
Charles-François Natali027f9a32011-10-02 18:36:05 +0200256 def check_wakeup(self, test_body, *signals, ordered=True):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200257 # use a subprocess to have only one thread
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200258 code = """if 1:
259 import fcntl
260 import os
261 import signal
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200262 import struct
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000263
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200264 signals = {!r}
Victor Stinnerc13ef662011-05-25 02:35:58 +0200265
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200266 def handler(signum, frame):
267 pass
268
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200269 def check_signum(signals):
270 data = os.read(read, len(signals)+1)
271 raised = struct.unpack('%uB' % len(data), data)
Charles-François Natali027f9a32011-10-02 18:36:05 +0200272 if not {!r}:
273 raised = set(raised)
274 signals = set(signals)
Victor Stinner0a01f132011-07-04 18:06:35 +0200275 if raised != signals:
276 raise Exception("%r != %r" % (raised, signals))
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200277
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200278 {}
279
280 signal.signal(signal.SIGALRM, handler)
281 read, write = os.pipe()
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200282 for fd in (read, write):
283 flags = fcntl.fcntl(fd, fcntl.F_GETFL, 0)
284 flags = flags | os.O_NONBLOCK
285 fcntl.fcntl(fd, fcntl.F_SETFL, flags)
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200286 signal.set_wakeup_fd(write)
287
288 test()
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200289 check_signum(signals)
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200290
291 os.close(read)
292 os.close(write)
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +0200293 """.format(tuple(map(int, signals)), ordered, test_body)
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200294
295 assert_python_ok('-c', code)
Victor Stinnerd49b1f12011-05-08 02:03:15 +0200296
Antoine Pitrou6f6ec372013-08-17 20:27:56 +0200297 def test_wakeup_write_error(self):
298 # Issue #16105: write() errors in the C signal handler should not
299 # pass silently.
300 # Use a subprocess to have only one thread.
301 code = """if 1:
302 import errno
303 import fcntl
304 import os
305 import signal
306 import sys
307 import time
308 from test.support import captured_stderr
309
310 def handler(signum, frame):
311 1/0
312
313 signal.signal(signal.SIGALRM, handler)
314 r, w = os.pipe()
315 flags = fcntl.fcntl(r, fcntl.F_GETFL, 0)
316 fcntl.fcntl(r, fcntl.F_SETFL, flags | os.O_NONBLOCK)
317
318 # Set wakeup_fd a read-only file descriptor to trigger the error
319 signal.set_wakeup_fd(r)
320 try:
321 with captured_stderr() as err:
322 signal.alarm(1)
323 time.sleep(5.0)
324 except ZeroDivisionError:
325 # An ignored exception should have been printed out on stderr
326 err = err.getvalue()
327 if ('Exception ignored when trying to write to the signal wakeup fd'
328 not in err):
329 raise AssertionError(err)
330 if ('OSError: [Errno %d]' % errno.EBADF) not in err:
331 raise AssertionError(err)
332 else:
333 raise AssertionError("ZeroDivisionError not raised")
334 """
Antoine Pitrou8f0bdda2013-08-17 21:43:47 +0200335 r, w = os.pipe()
336 try:
337 os.write(r, b'x')
338 except OSError:
339 pass
340 else:
341 self.skipTest("OS doesn't report write() error on the read end of a pipe")
342 finally:
343 os.close(r)
344 os.close(w)
Antoine Pitrou6f6ec372013-08-17 20:27:56 +0200345
346 assert_python_ok('-c', code)
347
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000348 def test_wakeup_fd_early(self):
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200349 self.check_wakeup("""def test():
350 import select
351 import time
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000352
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200353 TIMEOUT_FULL = 10
354 TIMEOUT_HALF = 5
355
356 signal.alarm(1)
357 before_time = time.time()
358 # We attempt to get a signal during the sleep,
359 # before select is called
360 time.sleep(TIMEOUT_FULL)
361 mid_time = time.time()
362 dt = mid_time - before_time
Victor Stinner0a01f132011-07-04 18:06:35 +0200363 if dt >= TIMEOUT_HALF:
364 raise Exception("%s >= %s" % (dt, TIMEOUT_HALF))
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200365 select.select([read], [], [], TIMEOUT_FULL)
366 after_time = time.time()
367 dt = after_time - mid_time
Victor Stinner0a01f132011-07-04 18:06:35 +0200368 if dt >= TIMEOUT_HALF:
369 raise Exception("%s >= %s" % (dt, TIMEOUT_HALF))
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200370 """, signal.SIGALRM)
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000371
372 def test_wakeup_fd_during(self):
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200373 self.check_wakeup("""def test():
374 import select
375 import time
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000376
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200377 TIMEOUT_FULL = 10
378 TIMEOUT_HALF = 5
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000379
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200380 signal.alarm(1)
381 before_time = time.time()
382 # We attempt to get a signal during the select call
383 try:
384 select.select([read], [], [], TIMEOUT_FULL)
Andrew Svetlov6d8a1222012-12-17 22:23:46 +0200385 except OSError:
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200386 pass
387 else:
Andrew Svetlov6d8a1222012-12-17 22:23:46 +0200388 raise Exception("OSError not raised")
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200389 after_time = time.time()
390 dt = after_time - before_time
Victor Stinner0a01f132011-07-04 18:06:35 +0200391 if dt >= TIMEOUT_HALF:
392 raise Exception("%s >= %s" % (dt, TIMEOUT_HALF))
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200393 """, signal.SIGALRM)
Victor Stinnerd49b1f12011-05-08 02:03:15 +0200394
395 def test_signum(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200396 self.check_wakeup("""def test():
397 signal.signal(signal.SIGUSR1, handler)
398 os.kill(os.getpid(), signal.SIGUSR1)
399 os.kill(os.getpid(), signal.SIGALRM)
400 """, signal.SIGUSR1, signal.SIGALRM)
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000401
Victor Stinnerc13ef662011-05-25 02:35:58 +0200402 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
403 'need signal.pthread_sigmask()')
Victor Stinnerc13ef662011-05-25 02:35:58 +0200404 def test_pending(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200405 self.check_wakeup("""def test():
406 signum1 = signal.SIGUSR1
407 signum2 = signal.SIGUSR2
Victor Stinnerc13ef662011-05-25 02:35:58 +0200408
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200409 signal.signal(signum1, handler)
410 signal.signal(signum2, handler)
Victor Stinnerc13ef662011-05-25 02:35:58 +0200411
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200412 signal.pthread_sigmask(signal.SIG_BLOCK, (signum1, signum2))
413 os.kill(os.getpid(), signum1)
414 os.kill(os.getpid(), signum2)
415 # Unblocking the 2 signals calls the C signal handler twice
416 signal.pthread_sigmask(signal.SIG_UNBLOCK, (signum1, signum2))
Charles-François Natali027f9a32011-10-02 18:36:05 +0200417 """, signal.SIGUSR1, signal.SIGUSR2, ordered=False)
Victor Stinnerc13ef662011-05-25 02:35:58 +0200418
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000419
Brian Curtin3f004b12010-08-06 19:34:52 +0000420@unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
Christian Heimes8640e742008-02-23 16:23:06 +0000421class SiginterruptTest(unittest.TestCase):
Jean-Paul Calderone9c39bc72010-05-09 03:25:16 +0000422
Victor Stinnerd6284962011-06-20 23:28:09 +0200423 def readpipe_interrupted(self, interrupt):
Jean-Paul Calderone9c39bc72010-05-09 03:25:16 +0000424 """Perform a read during which a signal will arrive. Return True if the
425 read is interrupted by the signal and raises an exception. Return False
426 if it returns normally.
427 """
Victor Stinnerd6284962011-06-20 23:28:09 +0200428 # use a subprocess to have only one thread, to have a timeout on the
429 # blocking read and to not touch signal handling in this process
430 code = """if 1:
431 import errno
432 import os
433 import signal
434 import sys
Jean-Paul Calderone9c39bc72010-05-09 03:25:16 +0000435
Victor Stinnerd6284962011-06-20 23:28:09 +0200436 interrupt = %r
437 r, w = os.pipe()
Christian Heimes8640e742008-02-23 16:23:06 +0000438
Victor Stinnerd6284962011-06-20 23:28:09 +0200439 def handler(signum, frame):
440 pass
441
442 signal.signal(signal.SIGALRM, handler)
443 if interrupt is not None:
444 signal.siginterrupt(signal.SIGALRM, interrupt)
445
Victor Stinnerdfde0d42011-07-01 15:58:39 +0200446 print("ready")
447 sys.stdout.flush()
448
Victor Stinnerd6284962011-06-20 23:28:09 +0200449 # run the test twice
450 for loop in range(2):
451 # send a SIGALRM in a second (during the read)
452 signal.alarm(1)
453 try:
454 # blocking call: read from a pipe without data
455 os.read(r, 1)
456 except OSError as err:
457 if err.errno != errno.EINTR:
458 raise
459 else:
460 sys.exit(2)
461 sys.exit(3)
462 """ % (interrupt,)
463 with spawn_python('-c', code) as process:
Christian Heimes8640e742008-02-23 16:23:06 +0000464 try:
Victor Stinner45273652011-06-22 22:15:51 +0200465 # wait until the child process is loaded and has started
466 first_line = process.stdout.readline()
467
Victor Stinner19e5bcd2011-07-01 15:59:54 +0200468 stdout, stderr = process.communicate(timeout=5.0)
Victor Stinnerd6284962011-06-20 23:28:09 +0200469 except subprocess.TimeoutExpired:
470 process.kill()
Christian Heimes8640e742008-02-23 16:23:06 +0000471 return False
Victor Stinnerd6284962011-06-20 23:28:09 +0200472 else:
Victor Stinner45273652011-06-22 22:15:51 +0200473 stdout = first_line + stdout
Victor Stinnerd6284962011-06-20 23:28:09 +0200474 exitcode = process.wait()
475 if exitcode not in (2, 3):
476 raise Exception("Child error (exit code %s): %s"
477 % (exitcode, stdout))
478 return (exitcode == 3)
Christian Heimes8640e742008-02-23 16:23:06 +0000479
480 def test_without_siginterrupt(self):
Victor Stinner3a7f0f02011-05-08 02:10:36 +0200481 # If a signal handler is installed and siginterrupt is not called
482 # at all, when that signal arrives, it interrupts a syscall that's in
483 # progress.
Victor Stinnerd6284962011-06-20 23:28:09 +0200484 interrupted = self.readpipe_interrupted(None)
485 self.assertTrue(interrupted)
Christian Heimes8640e742008-02-23 16:23:06 +0000486
487 def test_siginterrupt_on(self):
Victor Stinner3a7f0f02011-05-08 02:10:36 +0200488 # If a signal handler is installed and siginterrupt is called with
489 # a true value for the second argument, when that signal arrives, it
490 # interrupts a syscall that's in progress.
Victor Stinnerd6284962011-06-20 23:28:09 +0200491 interrupted = self.readpipe_interrupted(True)
492 self.assertTrue(interrupted)
Christian Heimes8640e742008-02-23 16:23:06 +0000493
494 def test_siginterrupt_off(self):
Victor Stinner3a7f0f02011-05-08 02:10:36 +0200495 # If a signal handler is installed and siginterrupt is called with
496 # a false value for the second argument, when that signal arrives, it
497 # does not interrupt a syscall that's in progress.
Victor Stinnerd6284962011-06-20 23:28:09 +0200498 interrupted = self.readpipe_interrupted(False)
499 self.assertFalse(interrupted)
Jean-Paul Calderone9c39bc72010-05-09 03:25:16 +0000500
501
Brian Curtin3f004b12010-08-06 19:34:52 +0000502@unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
Martin v. Löwis823725e2008-03-24 13:39:54 +0000503class ItimerTest(unittest.TestCase):
504 def setUp(self):
505 self.hndl_called = False
506 self.hndl_count = 0
507 self.itimer = None
Christian Heimescc47b052008-03-25 14:56:36 +0000508 self.old_alarm = signal.signal(signal.SIGALRM, self.sig_alrm)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000509
510 def tearDown(self):
Christian Heimescc47b052008-03-25 14:56:36 +0000511 signal.signal(signal.SIGALRM, self.old_alarm)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000512 if self.itimer is not None: # test_itimer_exc doesn't change this attr
513 # just ensure that itimer is stopped
514 signal.setitimer(self.itimer, 0)
515
516 def sig_alrm(self, *args):
517 self.hndl_called = True
Martin v. Löwis823725e2008-03-24 13:39:54 +0000518
519 def sig_vtalrm(self, *args):
520 self.hndl_called = True
521
522 if self.hndl_count > 3:
523 # it shouldn't be here, because it should have been disabled.
524 raise signal.ItimerError("setitimer didn't disable ITIMER_VIRTUAL "
525 "timer.")
526 elif self.hndl_count == 3:
527 # disable ITIMER_VIRTUAL, this function shouldn't be called anymore
528 signal.setitimer(signal.ITIMER_VIRTUAL, 0)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000529
530 self.hndl_count += 1
531
Martin v. Löwis823725e2008-03-24 13:39:54 +0000532 def sig_prof(self, *args):
533 self.hndl_called = True
534 signal.setitimer(signal.ITIMER_PROF, 0)
535
Martin v. Löwis823725e2008-03-24 13:39:54 +0000536 def test_itimer_exc(self):
537 # XXX I'm assuming -1 is an invalid itimer, but maybe some platform
538 # defines it ?
539 self.assertRaises(signal.ItimerError, signal.setitimer, -1, 0)
Christian Heimescc47b052008-03-25 14:56:36 +0000540 # Negative times are treated as zero on some platforms.
541 if 0:
542 self.assertRaises(signal.ItimerError,
543 signal.setitimer, signal.ITIMER_REAL, -1)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000544
545 def test_itimer_real(self):
546 self.itimer = signal.ITIMER_REAL
Martin v. Löwis823725e2008-03-24 13:39:54 +0000547 signal.setitimer(self.itimer, 1.0)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000548 signal.pause()
Martin v. Löwis823725e2008-03-24 13:39:54 +0000549 self.assertEqual(self.hndl_called, True)
550
R. David Murray44546f82010-04-21 01:59:28 +0000551 # Issue 3864, unknown if this affects earlier versions of freebsd also
Gregory P. Smith397cd8a2010-10-17 04:23:21 +0000552 @unittest.skipIf(sys.platform in ('freebsd6', 'netbsd5'),
553 'itimer not reliable (does not mix well with threading) on some BSDs.')
Martin v. Löwis823725e2008-03-24 13:39:54 +0000554 def test_itimer_virtual(self):
555 self.itimer = signal.ITIMER_VIRTUAL
556 signal.signal(signal.SIGVTALRM, self.sig_vtalrm)
557 signal.setitimer(self.itimer, 0.3, 0.2)
558
Mark Dickinson78373472009-10-31 10:39:21 +0000559 start_time = time.time()
Stefan Krahf1da973042010-04-20 08:15:14 +0000560 while time.time() - start_time < 60.0:
Mark Dickinson95078872009-10-04 18:47:48 +0000561 # use up some virtual time by doing real work
562 _ = pow(12345, 67890, 10000019)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000563 if signal.getitimer(self.itimer) == (0.0, 0.0):
564 break # sig_vtalrm handler stopped this itimer
Stefan Krahf1da973042010-04-20 08:15:14 +0000565 else: # Issue 8424
Benjamin Peterson9b140f62010-05-15 18:00:56 +0000566 self.skipTest("timeout: likely cause: machine too slow or load too "
567 "high")
Martin v. Löwis823725e2008-03-24 13:39:54 +0000568
569 # virtual itimer should be (0.0, 0.0) now
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000570 self.assertEqual(signal.getitimer(self.itimer), (0.0, 0.0))
Martin v. Löwis823725e2008-03-24 13:39:54 +0000571 # and the handler should have been called
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000572 self.assertEqual(self.hndl_called, True)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000573
R. David Murray44546f82010-04-21 01:59:28 +0000574 # Issue 3864, unknown if this affects earlier versions of freebsd also
575 @unittest.skipIf(sys.platform=='freebsd6',
576 'itimer not reliable (does not mix well with threading) on freebsd6')
Martin v. Löwis823725e2008-03-24 13:39:54 +0000577 def test_itimer_prof(self):
578 self.itimer = signal.ITIMER_PROF
579 signal.signal(signal.SIGPROF, self.sig_prof)
Neal Norwitzf5c7c2e2008-04-05 04:47:45 +0000580 signal.setitimer(self.itimer, 0.2, 0.2)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000581
Mark Dickinson78373472009-10-31 10:39:21 +0000582 start_time = time.time()
Stefan Krahf1da973042010-04-20 08:15:14 +0000583 while time.time() - start_time < 60.0:
Mark Dickinson78373472009-10-31 10:39:21 +0000584 # do some work
585 _ = pow(12345, 67890, 10000019)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000586 if signal.getitimer(self.itimer) == (0.0, 0.0):
587 break # sig_prof handler stopped this itimer
Stefan Krahf1da973042010-04-20 08:15:14 +0000588 else: # Issue 8424
Benjamin Peterson9b140f62010-05-15 18:00:56 +0000589 self.skipTest("timeout: likely cause: machine too slow or load too "
590 "high")
Martin v. Löwis823725e2008-03-24 13:39:54 +0000591
Neal Norwitzf5c7c2e2008-04-05 04:47:45 +0000592 # profiling itimer should be (0.0, 0.0) now
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000593 self.assertEqual(signal.getitimer(self.itimer), (0.0, 0.0))
Neal Norwitzf5c7c2e2008-04-05 04:47:45 +0000594 # and the handler should have been called
Martin v. Löwis823725e2008-03-24 13:39:54 +0000595 self.assertEqual(self.hndl_called, True)
596
Victor Stinnera9293352011-04-30 15:21:58 +0200597
Victor Stinner35b300c2011-05-04 13:20:35 +0200598class PendingSignalsTests(unittest.TestCase):
599 """
Victor Stinnerb3e72192011-05-08 01:46:11 +0200600 Test pthread_sigmask(), pthread_kill(), sigpending() and sigwait()
601 functions.
Victor Stinner35b300c2011-05-04 13:20:35 +0200602 """
Victor Stinnerb3e72192011-05-08 01:46:11 +0200603 @unittest.skipUnless(hasattr(signal, 'sigpending'),
604 'need signal.sigpending()')
605 def test_sigpending_empty(self):
606 self.assertEqual(signal.sigpending(), set())
607
608 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
609 'need signal.pthread_sigmask()')
610 @unittest.skipUnless(hasattr(signal, 'sigpending'),
611 'need signal.sigpending()')
612 def test_sigpending(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200613 code = """if 1:
614 import os
615 import signal
Victor Stinnerb3e72192011-05-08 01:46:11 +0200616
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200617 def handler(signum, frame):
618 1/0
Victor Stinnerb3e72192011-05-08 01:46:11 +0200619
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200620 signum = signal.SIGUSR1
621 signal.signal(signum, handler)
622
623 signal.pthread_sigmask(signal.SIG_BLOCK, [signum])
624 os.kill(os.getpid(), signum)
625 pending = signal.sigpending()
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +0200626 for sig in pending:
627 assert isinstance(sig, signal.Signals), repr(pending)
Victor Stinner0a01f132011-07-04 18:06:35 +0200628 if pending != {signum}:
629 raise Exception('%s != {%s}' % (pending, signum))
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200630 try:
631 signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum])
632 except ZeroDivisionError:
633 pass
634 else:
635 raise Exception("ZeroDivisionError not raised")
636 """
637 assert_python_ok('-c', code)
Victor Stinnerb3e72192011-05-08 01:46:11 +0200638
639 @unittest.skipUnless(hasattr(signal, 'pthread_kill'),
640 'need signal.pthread_kill()')
641 def test_pthread_kill(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200642 code = """if 1:
643 import signal
644 import threading
645 import sys
Victor Stinnerb3e72192011-05-08 01:46:11 +0200646
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200647 signum = signal.SIGUSR1
Victor Stinnerb3e72192011-05-08 01:46:11 +0200648
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200649 def handler(signum, frame):
650 1/0
651
652 signal.signal(signum, handler)
653
654 if sys.platform == 'freebsd6':
655 # Issue #12392 and #12469: send a signal to the main thread
656 # doesn't work before the creation of the first thread on
657 # FreeBSD 6
658 def noop():
659 pass
660 thread = threading.Thread(target=noop)
661 thread.start()
662 thread.join()
663
664 tid = threading.get_ident()
665 try:
666 signal.pthread_kill(tid, signum)
667 except ZeroDivisionError:
668 pass
669 else:
670 raise Exception("ZeroDivisionError not raised")
671 """
672 assert_python_ok('-c', code)
Victor Stinnerb3e72192011-05-08 01:46:11 +0200673
Victor Stinner7f294d12011-06-10 14:02:10 +0200674 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
675 'need signal.pthread_sigmask()')
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200676 def wait_helper(self, blocked, test):
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200677 """
678 test: body of the "def test(signum):" function.
679 blocked: number of the blocked signal
680 """
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200681 code = '''if 1:
682 import signal
683 import sys
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +0200684 from signal import Signals
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200685
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200686 def handler(signum, frame):
687 1/0
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200688
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200689 %s
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200690
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200691 blocked = %s
692 signum = signal.SIGALRM
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200693
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200694 # child: block and wait the signal
695 try:
696 signal.signal(signum, handler)
697 signal.pthread_sigmask(signal.SIG_BLOCK, [blocked])
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200698
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200699 # Do the tests
700 test(signum)
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200701
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200702 # The handler must not be called on unblock
703 try:
704 signal.pthread_sigmask(signal.SIG_UNBLOCK, [blocked])
705 except ZeroDivisionError:
706 print("the signal handler has been called",
707 file=sys.stderr)
708 sys.exit(1)
709 except BaseException as err:
710 print("error: {}".format(err), file=sys.stderr)
711 sys.stderr.flush()
712 sys.exit(1)
713 ''' % (test.strip(), blocked)
Victor Stinner415007e2011-06-13 16:19:06 +0200714
Ross Lagerwallbc808222011-06-25 12:13:40 +0200715 # sig*wait* must be called with the signal blocked: since the current
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200716 # process might have several threads running, use a subprocess to have
717 # a single thread.
718 assert_python_ok('-c', code)
Victor Stinneraf494602011-06-10 12:48:13 +0200719
Victor Stinnerb3e72192011-05-08 01:46:11 +0200720 @unittest.skipUnless(hasattr(signal, 'sigwait'),
721 'need signal.sigwait()')
Ross Lagerwallbc808222011-06-25 12:13:40 +0200722 def test_sigwait(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200723 self.wait_helper(signal.SIGALRM, '''
724 def test(signum):
Ross Lagerwallbc808222011-06-25 12:13:40 +0200725 signal.alarm(1)
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200726 received = signal.sigwait([signum])
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +0200727 assert isinstance(received, signal.Signals), received
Victor Stinner0a01f132011-07-04 18:06:35 +0200728 if received != signum:
729 raise Exception('received %s, not %s' % (received, signum))
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200730 ''')
Ross Lagerwallbc808222011-06-25 12:13:40 +0200731
732 @unittest.skipUnless(hasattr(signal, 'sigwaitinfo'),
733 'need signal.sigwaitinfo()')
734 def test_sigwaitinfo(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200735 self.wait_helper(signal.SIGALRM, '''
736 def test(signum):
Ross Lagerwallbc808222011-06-25 12:13:40 +0200737 signal.alarm(1)
738 info = signal.sigwaitinfo([signum])
Victor Stinner0a01f132011-07-04 18:06:35 +0200739 if info.si_signo != signum:
740 raise Exception("info.si_signo != %s" % signum)
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200741 ''')
Ross Lagerwallbc808222011-06-25 12:13:40 +0200742
743 @unittest.skipUnless(hasattr(signal, 'sigtimedwait'),
744 'need signal.sigtimedwait()')
745 def test_sigtimedwait(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200746 self.wait_helper(signal.SIGALRM, '''
747 def test(signum):
Ross Lagerwallbc808222011-06-25 12:13:40 +0200748 signal.alarm(1)
Victor Stinner643cd682012-03-02 22:54:03 +0100749 info = signal.sigtimedwait([signum], 10.1000)
Victor Stinner0a01f132011-07-04 18:06:35 +0200750 if info.si_signo != signum:
751 raise Exception('info.si_signo != %s' % signum)
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200752 ''')
Ross Lagerwallbc808222011-06-25 12:13:40 +0200753
Ross Lagerwallbc808222011-06-25 12:13:40 +0200754 @unittest.skipUnless(hasattr(signal, 'sigtimedwait'),
755 'need signal.sigtimedwait()')
756 def test_sigtimedwait_poll(self):
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200757 # check that polling with sigtimedwait works
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200758 self.wait_helper(signal.SIGALRM, '''
759 def test(signum):
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200760 import os
761 os.kill(os.getpid(), signum)
Victor Stinner643cd682012-03-02 22:54:03 +0100762 info = signal.sigtimedwait([signum], 0)
Victor Stinner0a01f132011-07-04 18:06:35 +0200763 if info.si_signo != signum:
764 raise Exception('info.si_signo != %s' % signum)
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200765 ''')
Ross Lagerwallbc808222011-06-25 12:13:40 +0200766
767 @unittest.skipUnless(hasattr(signal, 'sigtimedwait'),
768 'need signal.sigtimedwait()')
769 def test_sigtimedwait_timeout(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200770 self.wait_helper(signal.SIGALRM, '''
771 def test(signum):
Victor Stinner643cd682012-03-02 22:54:03 +0100772 received = signal.sigtimedwait([signum], 1.0)
Victor Stinner0a01f132011-07-04 18:06:35 +0200773 if received is not None:
774 raise Exception("received=%r" % (received,))
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200775 ''')
Ross Lagerwallbc808222011-06-25 12:13:40 +0200776
777 @unittest.skipUnless(hasattr(signal, 'sigtimedwait'),
778 'need signal.sigtimedwait()')
779 def test_sigtimedwait_negative_timeout(self):
780 signum = signal.SIGALRM
Victor Stinner643cd682012-03-02 22:54:03 +0100781 self.assertRaises(ValueError, signal.sigtimedwait, [signum], -1.0)
Ross Lagerwallbc808222011-06-25 12:13:40 +0200782
Ross Lagerwallbc808222011-06-25 12:13:40 +0200783 @unittest.skipUnless(hasattr(signal, 'sigwaitinfo'),
784 'need signal.sigwaitinfo()')
Victor Stinner91f9bdd2013-06-17 21:51:56 +0200785 # Issue #18238: sigwaitinfo() can be interrupted on Linux (raises
786 # InterruptedError), but not on AIX
787 @unittest.skipIf(sys.platform.startswith("aix"),
788 'signal.sigwaitinfo() cannot be interrupted on AIX')
Ross Lagerwallbc808222011-06-25 12:13:40 +0200789 def test_sigwaitinfo_interrupted(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200790 self.wait_helper(signal.SIGUSR1, '''
791 def test(signum):
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200792 import errno
793
794 hndl_called = True
795 def alarm_handler(signum, frame):
796 hndl_called = False
797
798 signal.signal(signal.SIGALRM, alarm_handler)
Ross Lagerwallbc808222011-06-25 12:13:40 +0200799 signal.alarm(1)
800 try:
801 signal.sigwaitinfo([signal.SIGUSR1])
802 except OSError as e:
803 if e.errno == errno.EINTR:
Victor Stinner0a01f132011-07-04 18:06:35 +0200804 if not hndl_called:
805 raise Exception("SIGALRM handler not called")
Ross Lagerwallbc808222011-06-25 12:13:40 +0200806 else:
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200807 raise Exception("Expected EINTR to be raised by sigwaitinfo")
Ross Lagerwallbc808222011-06-25 12:13:40 +0200808 else:
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200809 raise Exception("Expected EINTR to be raised by sigwaitinfo")
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200810 ''')
Ross Lagerwallbc808222011-06-25 12:13:40 +0200811
812 @unittest.skipUnless(hasattr(signal, 'sigwait'),
813 'need signal.sigwait()')
Victor Stinner415007e2011-06-13 16:19:06 +0200814 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
815 'need signal.pthread_sigmask()')
Victor Stinner10c30d62011-06-10 01:39:53 +0200816 @unittest.skipIf(threading is None, "test needs threading module")
817 def test_sigwait_thread(self):
Victor Stinner415007e2011-06-13 16:19:06 +0200818 # Check that calling sigwait() from a thread doesn't suspend the whole
819 # process. A new interpreter is spawned to avoid problems when mixing
820 # threads and fork(): only async-safe functions are allowed between
821 # fork() and exec().
822 assert_python_ok("-c", """if True:
823 import os, threading, sys, time, signal
Victor Stinner10c30d62011-06-10 01:39:53 +0200824
Victor Stinner415007e2011-06-13 16:19:06 +0200825 # the default handler terminates the process
826 signum = signal.SIGUSR1
827
828 def kill_later():
829 # wait until the main thread is waiting in sigwait()
830 time.sleep(1)
831 os.kill(os.getpid(), signum)
832
833 # the signal must be blocked by all the threads
834 signal.pthread_sigmask(signal.SIG_BLOCK, [signum])
835 killer = threading.Thread(target=kill_later)
Victor Stinneraf494602011-06-10 12:48:13 +0200836 killer.start()
837 received = signal.sigwait([signum])
838 if received != signum:
839 print("sigwait() received %s, not %s" % (received, signum),
840 file=sys.stderr)
Victor Stinner415007e2011-06-13 16:19:06 +0200841 sys.exit(1)
Victor Stinner10c30d62011-06-10 01:39:53 +0200842 killer.join()
Victor Stinner415007e2011-06-13 16:19:06 +0200843 # unblock the signal, which should have been cleared by sigwait()
844 signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum])
845 """)
Victor Stinneraf494602011-06-10 12:48:13 +0200846
Victor Stinnerb3e72192011-05-08 01:46:11 +0200847 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
848 'need signal.pthread_sigmask()')
849 def test_pthread_sigmask_arguments(self):
850 self.assertRaises(TypeError, signal.pthread_sigmask)
851 self.assertRaises(TypeError, signal.pthread_sigmask, 1)
852 self.assertRaises(TypeError, signal.pthread_sigmask, 1, 2, 3)
853 self.assertRaises(OSError, signal.pthread_sigmask, 1700, [])
854
855 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
856 'need signal.pthread_sigmask()')
857 def test_pthread_sigmask(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200858 code = """if 1:
859 import signal
860 import os; import threading
861
862 def handler(signum, frame):
863 1/0
864
865 def kill(signum):
866 os.kill(os.getpid(), signum)
867
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +0200868 def check_mask(mask):
869 for sig in mask:
870 assert isinstance(sig, signal.Signals), repr(sig)
871
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200872 def read_sigmask():
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +0200873 sigmask = signal.pthread_sigmask(signal.SIG_BLOCK, [])
874 check_mask(sigmask)
875 return sigmask
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200876
Victor Stinnerb3e72192011-05-08 01:46:11 +0200877 signum = signal.SIGUSR1
Victor Stinner6fd49e12011-05-04 12:38:03 +0200878
Victor Stinnerd0e516d2011-05-03 14:57:12 +0200879 # Install our signal handler
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200880 old_handler = signal.signal(signum, handler)
Victor Stinnera9293352011-04-30 15:21:58 +0200881
Victor Stinnerd0e516d2011-05-03 14:57:12 +0200882 # Unblock SIGUSR1 (and copy the old mask) to test our signal handler
Victor Stinnera9293352011-04-30 15:21:58 +0200883 old_mask = signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum])
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +0200884 check_mask(old_mask)
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200885 try:
886 kill(signum)
887 except ZeroDivisionError:
888 pass
889 else:
890 raise Exception("ZeroDivisionError not raised")
Victor Stinnera9293352011-04-30 15:21:58 +0200891
Victor Stinnerd0e516d2011-05-03 14:57:12 +0200892 # Block and then raise SIGUSR1. The signal is blocked: the signal
893 # handler is not called, and the signal is now pending
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +0200894 mask = signal.pthread_sigmask(signal.SIG_BLOCK, [signum])
895 check_mask(mask)
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200896 kill(signum)
Victor Stinnera9293352011-04-30 15:21:58 +0200897
Victor Stinnerd0e516d2011-05-03 14:57:12 +0200898 # Check the new mask
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200899 blocked = read_sigmask()
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +0200900 check_mask(blocked)
Victor Stinner0a01f132011-07-04 18:06:35 +0200901 if signum not in blocked:
902 raise Exception("%s not in %s" % (signum, blocked))
903 if old_mask ^ blocked != {signum}:
904 raise Exception("%s ^ %s != {%s}" % (old_mask, blocked, signum))
Victor Stinnera9293352011-04-30 15:21:58 +0200905
Victor Stinnerd0e516d2011-05-03 14:57:12 +0200906 # Unblock SIGUSR1
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200907 try:
R David Murrayfc069992013-12-13 20:52:19 -0500908 # unblock the pending signal calls immediately the signal handler
Victor Stinnerd0e516d2011-05-03 14:57:12 +0200909 signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum])
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200910 except ZeroDivisionError:
911 pass
912 else:
913 raise Exception("ZeroDivisionError not raised")
914 try:
915 kill(signum)
916 except ZeroDivisionError:
917 pass
918 else:
919 raise Exception("ZeroDivisionError not raised")
Victor Stinnera9293352011-04-30 15:21:58 +0200920
Victor Stinnerd0e516d2011-05-03 14:57:12 +0200921 # Check the new mask
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200922 unblocked = read_sigmask()
Victor Stinner0a01f132011-07-04 18:06:35 +0200923 if signum in unblocked:
924 raise Exception("%s in %s" % (signum, unblocked))
925 if blocked ^ unblocked != {signum}:
926 raise Exception("%s ^ %s != {%s}" % (blocked, unblocked, signum))
927 if old_mask != unblocked:
928 raise Exception("%s != %s" % (old_mask, unblocked))
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200929 """
930 assert_python_ok('-c', code)
931
932 @unittest.skipIf(sys.platform == 'freebsd6',
933 "issue #12392: send a signal to the main thread doesn't work "
934 "before the creation of the first thread on FreeBSD 6")
935 @unittest.skipUnless(hasattr(signal, 'pthread_kill'),
936 'need signal.pthread_kill()')
937 def test_pthread_kill_main_thread(self):
938 # Test that a signal can be sent to the main thread with pthread_kill()
939 # before any other thread has been created (see issue #12392).
940 code = """if True:
941 import threading
942 import signal
943 import sys
944
945 def handler(signum, frame):
946 sys.exit(3)
947
948 signal.signal(signal.SIGUSR1, handler)
949 signal.pthread_kill(threading.get_ident(), signal.SIGUSR1)
950 sys.exit(2)
951 """
952
953 with spawn_python('-c', code) as process:
954 stdout, stderr = process.communicate()
955 exitcode = process.wait()
956 if exitcode != 3:
957 raise Exception("Child error (exit code %s): %s" %
958 (exitcode, stdout))
Victor Stinnera9293352011-04-30 15:21:58 +0200959
960
Thomas Woutersed03b412007-08-28 21:37:11 +0000961def test_main():
Antoine Pitrou8189ab82011-03-20 17:35:32 +0100962 try:
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +0200963 support.run_unittest(GenericTests, PosixTests, InterProcessSignalTests,
Benjamin Petersonc68a4a02013-01-18 00:10:24 -0500964 WakeupFDTests, WakeupSignalTests,
965 SiginterruptTest, ItimerTest, WindowsSignalTests,
Victor Stinner35b300c2011-05-04 13:20:35 +0200966 PendingSignalsTests)
Antoine Pitrou8189ab82011-03-20 17:35:32 +0100967 finally:
968 support.reap_children()
Thomas Woutersed03b412007-08-28 21:37:11 +0000969
970
971if __name__ == "__main__":
972 test_main()