blob: 0e1d06706d65eaa1080339c23a948fa9393402df [file] [log] [blame]
Victor Stinnerd6debb22017-03-27 16:05:26 +02001import os
Antoine Pitrouc08177a2017-06-28 23:29:29 +02002import random
Guido van Rossum4f17e3e1995-03-16 15:07:38 +00003import signal
Victor Stinner11517102014-07-29 23:31:34 +02004import socket
Antoine Pitrouf7d090c2017-06-29 16:40:14 +02005import statistics
Christian Heimes4fbc72b2008-03-22 00:47:35 +00006import subprocess
Victor Stinnerd6debb22017-03-27 16:05:26 +02007import sys
8import time
9import unittest
10from test import support
Berker Peksagce643912015-05-06 06:33:17 +030011from test.support.script_helper import assert_python_ok, spawn_python
Victor Stinnerb3e72192011-05-08 01:46:11 +020012try:
13 import threading
14except ImportError:
15 threading = None
Victor Stinner56e8c292014-07-21 12:30:22 +020016try:
17 import _testcapi
18except ImportError:
19 _testcapi = None
Christian Heimesc06950e2008-02-28 21:17:00 +000020
Guido van Rossumcc5a91d1997-04-16 00:29:15 +000021
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +020022class GenericTests(unittest.TestCase):
23
Stefan Krah63c4b242014-04-15 22:40:06 +020024 @unittest.skipIf(threading is None, "test needs threading module")
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +020025 def test_enums(self):
26 for name in dir(signal):
27 sig = getattr(signal, name)
28 if name in {'SIG_DFL', 'SIG_IGN'}:
29 self.assertIsInstance(sig, signal.Handlers)
30 elif name in {'SIG_BLOCK', 'SIG_UNBLOCK', 'SIG_SETMASK'}:
31 self.assertIsInstance(sig, signal.Sigmasks)
32 elif name.startswith('SIG') and not name.startswith('SIG_'):
33 self.assertIsInstance(sig, signal.Signals)
34 elif name.startswith('CTRL_'):
35 self.assertIsInstance(sig, signal.Signals)
36 self.assertEqual(sys.platform, "win32")
37
38
Brian Curtin3f004b12010-08-06 19:34:52 +000039@unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
Victor Stinnerb3e72192011-05-08 01:46:11 +020040class PosixTests(unittest.TestCase):
Christian Heimes4fbc72b2008-03-22 00:47:35 +000041 def trivial_signal_handler(self, *args):
42 pass
43
Thomas Woutersed03b412007-08-28 21:37:11 +000044 def test_out_of_range_signal_number_raises_error(self):
45 self.assertRaises(ValueError, signal.getsignal, 4242)
46
Thomas Woutersed03b412007-08-28 21:37:11 +000047 self.assertRaises(ValueError, signal.signal, 4242,
Christian Heimes4fbc72b2008-03-22 00:47:35 +000048 self.trivial_signal_handler)
Thomas Woutersed03b412007-08-28 21:37:11 +000049
50 def test_setting_signal_handler_to_none_raises_error(self):
51 self.assertRaises(TypeError, signal.signal,
52 signal.SIGUSR1, None)
53
Christian Heimes4fbc72b2008-03-22 00:47:35 +000054 def test_getsignal(self):
55 hup = signal.signal(signal.SIGHUP, self.trivial_signal_handler)
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +020056 self.assertIsInstance(hup, signal.Handlers)
Ezio Melotti19f2aeb2010-11-21 01:30:29 +000057 self.assertEqual(signal.getsignal(signal.SIGHUP),
58 self.trivial_signal_handler)
Christian Heimes4fbc72b2008-03-22 00:47:35 +000059 signal.signal(signal.SIGHUP, hup)
Ezio Melotti19f2aeb2010-11-21 01:30:29 +000060 self.assertEqual(signal.getsignal(signal.SIGHUP), hup)
Christian Heimes4fbc72b2008-03-22 00:47:35 +000061
Victor Stinner32eb8402016-03-15 11:12:35 +010062 # Issue 3864, unknown if this affects earlier versions of freebsd also
63 @unittest.skipIf(sys.platform=='freebsd6',
64 'inter process signals not reliable (do not mix well with threading) '
65 'on freebsd6')
66 def test_interprocess_signal(self):
67 dirname = os.path.dirname(__file__)
68 script = os.path.join(dirname, 'signalinterproctester.py')
69 assert_python_ok(script)
70
Christian Heimes4fbc72b2008-03-22 00:47:35 +000071
Brian Curtin3f004b12010-08-06 19:34:52 +000072@unittest.skipUnless(sys.platform == "win32", "Windows specific")
73class WindowsSignalTests(unittest.TestCase):
74 def test_issue9324(self):
Brian Curtineccd4d92010-10-01 15:09:53 +000075 # Updated for issue #10003, adding SIGBREAK
Brian Curtin3f004b12010-08-06 19:34:52 +000076 handler = lambda x, y: None
Nick Coghlan60b3ac72013-08-03 22:56:30 +100077 checked = set()
Brian Curtineccd4d92010-10-01 15:09:53 +000078 for sig in (signal.SIGABRT, signal.SIGBREAK, signal.SIGFPE,
79 signal.SIGILL, signal.SIGINT, signal.SIGSEGV,
80 signal.SIGTERM):
Nick Coghlan60b3ac72013-08-03 22:56:30 +100081 # Set and then reset a handler for signals that work on windows.
82 # Issue #18396, only for signals without a C-level handler.
83 if signal.getsignal(sig) is not None:
84 signal.signal(sig, signal.signal(sig, handler))
85 checked.add(sig)
86 # Issue #18396: Ensure the above loop at least tested *something*
87 self.assertTrue(checked)
Brian Curtin3f004b12010-08-06 19:34:52 +000088
89 with self.assertRaises(ValueError):
90 signal.signal(-1, handler)
Brian Curtin80cd4bf2010-08-07 03:52:38 +000091
92 with self.assertRaises(ValueError):
93 signal.signal(7, handler)
Brian Curtin3f004b12010-08-06 19:34:52 +000094
95
Benjamin Petersonc68a4a02013-01-18 00:10:24 -050096class WakeupFDTests(unittest.TestCase):
97
98 def test_invalid_fd(self):
Victor Stinner1d8948e2014-07-24 22:51:05 +020099 fd = support.make_bad_fd()
Victor Stinnera7d03d92014-07-21 17:17:28 +0200100 self.assertRaises((ValueError, OSError),
101 signal.set_wakeup_fd, fd)
Benjamin Petersonc68a4a02013-01-18 00:10:24 -0500102
Victor Stinner11517102014-07-29 23:31:34 +0200103 def test_invalid_socket(self):
104 sock = socket.socket()
105 fd = sock.fileno()
106 sock.close()
107 self.assertRaises((ValueError, OSError),
108 signal.set_wakeup_fd, fd)
109
Victor Stinnerd18ccd12014-07-24 21:58:53 +0200110 def test_set_wakeup_fd_result(self):
Victor Stinner1d8948e2014-07-24 22:51:05 +0200111 r1, w1 = os.pipe()
112 self.addCleanup(os.close, r1)
113 self.addCleanup(os.close, w1)
114 r2, w2 = os.pipe()
115 self.addCleanup(os.close, r2)
116 self.addCleanup(os.close, w2)
Victor Stinnerd18ccd12014-07-24 21:58:53 +0200117
Victor Stinner7cea44d2014-08-27 14:02:36 +0200118 if hasattr(os, 'set_blocking'):
119 os.set_blocking(w1, False)
120 os.set_blocking(w2, False)
Victor Stinner38227602014-08-27 12:59:44 +0200121
Victor Stinner1d8948e2014-07-24 22:51:05 +0200122 signal.set_wakeup_fd(w1)
Victor Stinnerc82a1792014-07-24 22:55:12 +0200123 self.assertEqual(signal.set_wakeup_fd(w2), w1)
124 self.assertEqual(signal.set_wakeup_fd(-1), w2)
125 self.assertEqual(signal.set_wakeup_fd(-1), -1)
Victor Stinner56e8c292014-07-21 12:30:22 +0200126
Victor Stinner11517102014-07-29 23:31:34 +0200127 def test_set_wakeup_fd_socket_result(self):
128 sock1 = socket.socket()
129 self.addCleanup(sock1.close)
Victor Stinner38227602014-08-27 12:59:44 +0200130 sock1.setblocking(False)
Victor Stinner11517102014-07-29 23:31:34 +0200131 fd1 = sock1.fileno()
132
133 sock2 = socket.socket()
134 self.addCleanup(sock2.close)
Victor Stinner38227602014-08-27 12:59:44 +0200135 sock2.setblocking(False)
Victor Stinner11517102014-07-29 23:31:34 +0200136 fd2 = sock2.fileno()
137
138 signal.set_wakeup_fd(fd1)
Victor Stinnerda565a72014-07-30 10:03:03 +0200139 self.assertEqual(signal.set_wakeup_fd(fd2), fd1)
140 self.assertEqual(signal.set_wakeup_fd(-1), fd2)
141 self.assertEqual(signal.set_wakeup_fd(-1), -1)
Victor Stinner11517102014-07-29 23:31:34 +0200142
Victor Stinner38227602014-08-27 12:59:44 +0200143 # On Windows, files are always blocking and Windows does not provide a
144 # function to test if a socket is in non-blocking mode.
145 @unittest.skipIf(sys.platform == "win32", "tests specific to POSIX")
146 def test_set_wakeup_fd_blocking(self):
147 rfd, wfd = os.pipe()
148 self.addCleanup(os.close, rfd)
149 self.addCleanup(os.close, wfd)
150
151 # fd must be non-blocking
152 os.set_blocking(wfd, True)
153 with self.assertRaises(ValueError) as cm:
154 signal.set_wakeup_fd(wfd)
155 self.assertEqual(str(cm.exception),
156 "the fd %s must be in non-blocking mode" % wfd)
157
158 # non-blocking is ok
159 os.set_blocking(wfd, False)
160 signal.set_wakeup_fd(wfd)
161 signal.set_wakeup_fd(-1)
162
Benjamin Petersonc68a4a02013-01-18 00:10:24 -0500163
Brian Curtin3f004b12010-08-06 19:34:52 +0000164@unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000165class WakeupSignalTests(unittest.TestCase):
Victor Stinner56e8c292014-07-21 12:30:22 +0200166 @unittest.skipIf(_testcapi is None, 'need _testcapi')
Charles-François Natali027f9a32011-10-02 18:36:05 +0200167 def check_wakeup(self, test_body, *signals, ordered=True):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200168 # use a subprocess to have only one thread
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200169 code = """if 1:
Victor Stinner56e8c292014-07-21 12:30:22 +0200170 import _testcapi
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200171 import os
172 import signal
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200173 import struct
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000174
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200175 signals = {!r}
Victor Stinnerc13ef662011-05-25 02:35:58 +0200176
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200177 def handler(signum, frame):
178 pass
179
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200180 def check_signum(signals):
181 data = os.read(read, len(signals)+1)
182 raised = struct.unpack('%uB' % len(data), data)
Charles-François Natali027f9a32011-10-02 18:36:05 +0200183 if not {!r}:
184 raised = set(raised)
185 signals = set(signals)
Victor Stinner0a01f132011-07-04 18:06:35 +0200186 if raised != signals:
187 raise Exception("%r != %r" % (raised, signals))
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200188
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200189 {}
190
191 signal.signal(signal.SIGALRM, handler)
192 read, write = os.pipe()
Victor Stinner1db9e7b2014-07-29 22:32:47 +0200193 os.set_blocking(write, False)
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200194 signal.set_wakeup_fd(write)
195
196 test()
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200197 check_signum(signals)
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200198
199 os.close(read)
200 os.close(write)
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +0200201 """.format(tuple(map(int, signals)), ordered, test_body)
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200202
203 assert_python_ok('-c', code)
Victor Stinnerd49b1f12011-05-08 02:03:15 +0200204
Victor Stinner56e8c292014-07-21 12:30:22 +0200205 @unittest.skipIf(_testcapi is None, 'need _testcapi')
Antoine Pitrou6f6ec372013-08-17 20:27:56 +0200206 def test_wakeup_write_error(self):
207 # Issue #16105: write() errors in the C signal handler should not
208 # pass silently.
209 # Use a subprocess to have only one thread.
210 code = """if 1:
Victor Stinner56e8c292014-07-21 12:30:22 +0200211 import _testcapi
Antoine Pitrou6f6ec372013-08-17 20:27:56 +0200212 import errno
Antoine Pitrou6f6ec372013-08-17 20:27:56 +0200213 import os
214 import signal
215 import sys
Antoine Pitrou6f6ec372013-08-17 20:27:56 +0200216 from test.support import captured_stderr
217
218 def handler(signum, frame):
219 1/0
220
221 signal.signal(signal.SIGALRM, handler)
222 r, w = os.pipe()
Victor Stinner1db9e7b2014-07-29 22:32:47 +0200223 os.set_blocking(r, False)
Antoine Pitrou6f6ec372013-08-17 20:27:56 +0200224
225 # Set wakeup_fd a read-only file descriptor to trigger the error
226 signal.set_wakeup_fd(r)
227 try:
228 with captured_stderr() as err:
Victor Stinner56e8c292014-07-21 12:30:22 +0200229 _testcapi.raise_signal(signal.SIGALRM)
Antoine Pitrou6f6ec372013-08-17 20:27:56 +0200230 except ZeroDivisionError:
231 # An ignored exception should have been printed out on stderr
232 err = err.getvalue()
233 if ('Exception ignored when trying to write to the signal wakeup fd'
234 not in err):
235 raise AssertionError(err)
236 if ('OSError: [Errno %d]' % errno.EBADF) not in err:
237 raise AssertionError(err)
238 else:
239 raise AssertionError("ZeroDivisionError not raised")
Victor Stinner56e8c292014-07-21 12:30:22 +0200240
241 os.close(r)
242 os.close(w)
Antoine Pitrou6f6ec372013-08-17 20:27:56 +0200243 """
Antoine Pitrou8f0bdda2013-08-17 21:43:47 +0200244 r, w = os.pipe()
245 try:
246 os.write(r, b'x')
247 except OSError:
248 pass
249 else:
250 self.skipTest("OS doesn't report write() error on the read end of a pipe")
251 finally:
252 os.close(r)
253 os.close(w)
Antoine Pitrou6f6ec372013-08-17 20:27:56 +0200254
255 assert_python_ok('-c', code)
256
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000257 def test_wakeup_fd_early(self):
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200258 self.check_wakeup("""def test():
259 import select
260 import time
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000261
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200262 TIMEOUT_FULL = 10
263 TIMEOUT_HALF = 5
264
Victor Stinner749a6a82015-03-30 22:09:14 +0200265 class InterruptSelect(Exception):
266 pass
267
268 def handler(signum, frame):
269 raise InterruptSelect
270 signal.signal(signal.SIGALRM, handler)
271
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200272 signal.alarm(1)
Victor Stinner79d68f92015-03-19 21:54:09 +0100273
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200274 # We attempt to get a signal during the sleep,
275 # before select is called
Victor Stinner79d68f92015-03-19 21:54:09 +0100276 try:
277 select.select([], [], [], TIMEOUT_FULL)
Victor Stinner749a6a82015-03-30 22:09:14 +0200278 except InterruptSelect:
Victor Stinner79d68f92015-03-19 21:54:09 +0100279 pass
280 else:
281 raise Exception("select() was not interrupted")
282
283 before_time = time.monotonic()
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200284 select.select([read], [], [], TIMEOUT_FULL)
Victor Stinner79d68f92015-03-19 21:54:09 +0100285 after_time = time.monotonic()
286 dt = after_time - before_time
Victor Stinner0a01f132011-07-04 18:06:35 +0200287 if dt >= TIMEOUT_HALF:
288 raise Exception("%s >= %s" % (dt, TIMEOUT_HALF))
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200289 """, signal.SIGALRM)
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000290
291 def test_wakeup_fd_during(self):
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200292 self.check_wakeup("""def test():
293 import select
294 import time
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000295
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200296 TIMEOUT_FULL = 10
297 TIMEOUT_HALF = 5
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000298
Victor Stinner749a6a82015-03-30 22:09:14 +0200299 class InterruptSelect(Exception):
300 pass
301
302 def handler(signum, frame):
303 raise InterruptSelect
304 signal.signal(signal.SIGALRM, handler)
305
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200306 signal.alarm(1)
Victor Stinner79d68f92015-03-19 21:54:09 +0100307 before_time = time.monotonic()
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200308 # We attempt to get a signal during the select call
309 try:
310 select.select([read], [], [], TIMEOUT_FULL)
Victor Stinner749a6a82015-03-30 22:09:14 +0200311 except InterruptSelect:
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200312 pass
313 else:
Victor Stinner749a6a82015-03-30 22:09:14 +0200314 raise Exception("select() was not interrupted")
Victor Stinner79d68f92015-03-19 21:54:09 +0100315 after_time = time.monotonic()
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200316 dt = after_time - before_time
Victor Stinner0a01f132011-07-04 18:06:35 +0200317 if dt >= TIMEOUT_HALF:
318 raise Exception("%s >= %s" % (dt, TIMEOUT_HALF))
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200319 """, signal.SIGALRM)
Victor Stinnerd49b1f12011-05-08 02:03:15 +0200320
321 def test_signum(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200322 self.check_wakeup("""def test():
Victor Stinner56e8c292014-07-21 12:30:22 +0200323 import _testcapi
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200324 signal.signal(signal.SIGUSR1, handler)
Victor Stinner56e8c292014-07-21 12:30:22 +0200325 _testcapi.raise_signal(signal.SIGUSR1)
326 _testcapi.raise_signal(signal.SIGALRM)
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200327 """, signal.SIGUSR1, signal.SIGALRM)
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000328
Victor Stinnerc13ef662011-05-25 02:35:58 +0200329 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
330 'need signal.pthread_sigmask()')
Victor Stinnerc13ef662011-05-25 02:35:58 +0200331 def test_pending(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200332 self.check_wakeup("""def test():
333 signum1 = signal.SIGUSR1
334 signum2 = signal.SIGUSR2
Victor Stinnerc13ef662011-05-25 02:35:58 +0200335
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200336 signal.signal(signum1, handler)
337 signal.signal(signum2, handler)
Victor Stinnerc13ef662011-05-25 02:35:58 +0200338
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200339 signal.pthread_sigmask(signal.SIG_BLOCK, (signum1, signum2))
Victor Stinner56e8c292014-07-21 12:30:22 +0200340 _testcapi.raise_signal(signum1)
341 _testcapi.raise_signal(signum2)
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200342 # Unblocking the 2 signals calls the C signal handler twice
343 signal.pthread_sigmask(signal.SIG_UNBLOCK, (signum1, signum2))
Charles-François Natali027f9a32011-10-02 18:36:05 +0200344 """, signal.SIGUSR1, signal.SIGUSR2, ordered=False)
Victor Stinnerc13ef662011-05-25 02:35:58 +0200345
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000346
Victor Stinner11517102014-07-29 23:31:34 +0200347@unittest.skipUnless(hasattr(socket, 'socketpair'), 'need socket.socketpair')
348class WakeupSocketSignalTests(unittest.TestCase):
349
350 @unittest.skipIf(_testcapi is None, 'need _testcapi')
351 def test_socket(self):
352 # use a subprocess to have only one thread
353 code = """if 1:
354 import signal
355 import socket
356 import struct
357 import _testcapi
358
359 signum = signal.SIGINT
360 signals = (signum,)
361
362 def handler(signum, frame):
363 pass
364
365 signal.signal(signum, handler)
366
367 read, write = socket.socketpair()
368 read.setblocking(False)
369 write.setblocking(False)
370 signal.set_wakeup_fd(write.fileno())
371
372 _testcapi.raise_signal(signum)
373
374 data = read.recv(1)
375 if not data:
376 raise Exception("no signum written")
377 raised = struct.unpack('B', data)
378 if raised != signals:
379 raise Exception("%r != %r" % (raised, signals))
380
381 read.close()
382 write.close()
383 """
384
385 assert_python_ok('-c', code)
386
387 @unittest.skipIf(_testcapi is None, 'need _testcapi')
388 def test_send_error(self):
389 # Use a subprocess to have only one thread.
390 if os.name == 'nt':
391 action = 'send'
392 else:
393 action = 'write'
394 code = """if 1:
395 import errno
396 import signal
397 import socket
398 import sys
399 import time
400 import _testcapi
401 from test.support import captured_stderr
402
403 signum = signal.SIGINT
404
405 def handler(signum, frame):
406 pass
407
408 signal.signal(signum, handler)
409
410 read, write = socket.socketpair()
411 read.setblocking(False)
412 write.setblocking(False)
413
414 signal.set_wakeup_fd(write.fileno())
415
416 # Close sockets: send() will fail
417 read.close()
418 write.close()
419
420 with captured_stderr() as err:
421 _testcapi.raise_signal(signum)
422
423 err = err.getvalue()
424 if ('Exception ignored when trying to {action} to the signal wakeup fd'
425 not in err):
426 raise AssertionError(err)
427 """.format(action=action)
428 assert_python_ok('-c', code)
429
430
Brian Curtin3f004b12010-08-06 19:34:52 +0000431@unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
Christian Heimes8640e742008-02-23 16:23:06 +0000432class SiginterruptTest(unittest.TestCase):
Jean-Paul Calderone9c39bc72010-05-09 03:25:16 +0000433
Victor Stinnerd6284962011-06-20 23:28:09 +0200434 def readpipe_interrupted(self, interrupt):
Jean-Paul Calderone9c39bc72010-05-09 03:25:16 +0000435 """Perform a read during which a signal will arrive. Return True if the
436 read is interrupted by the signal and raises an exception. Return False
437 if it returns normally.
438 """
Victor Stinnerd6284962011-06-20 23:28:09 +0200439 # use a subprocess to have only one thread, to have a timeout on the
440 # blocking read and to not touch signal handling in this process
441 code = """if 1:
442 import errno
443 import os
444 import signal
445 import sys
Jean-Paul Calderone9c39bc72010-05-09 03:25:16 +0000446
Victor Stinnerd6284962011-06-20 23:28:09 +0200447 interrupt = %r
448 r, w = os.pipe()
Christian Heimes8640e742008-02-23 16:23:06 +0000449
Victor Stinnerd6284962011-06-20 23:28:09 +0200450 def handler(signum, frame):
Charles-François Natali6e6c59b2015-02-07 13:27:50 +0000451 1 / 0
Victor Stinnerd6284962011-06-20 23:28:09 +0200452
453 signal.signal(signal.SIGALRM, handler)
454 if interrupt is not None:
455 signal.siginterrupt(signal.SIGALRM, interrupt)
456
Victor Stinnerdfde0d42011-07-01 15:58:39 +0200457 print("ready")
458 sys.stdout.flush()
459
Victor Stinnerd6284962011-06-20 23:28:09 +0200460 # run the test twice
Victor Stinner56e8c292014-07-21 12:30:22 +0200461 try:
462 for loop in range(2):
463 # send a SIGALRM in a second (during the read)
464 signal.alarm(1)
465 try:
466 # blocking call: read from a pipe without data
467 os.read(r, 1)
Charles-François Natali6e6c59b2015-02-07 13:27:50 +0000468 except ZeroDivisionError:
469 pass
Victor Stinner56e8c292014-07-21 12:30:22 +0200470 else:
471 sys.exit(2)
472 sys.exit(3)
473 finally:
474 os.close(r)
475 os.close(w)
Victor Stinnerd6284962011-06-20 23:28:09 +0200476 """ % (interrupt,)
477 with spawn_python('-c', code) as process:
Christian Heimes8640e742008-02-23 16:23:06 +0000478 try:
Victor Stinner45273652011-06-22 22:15:51 +0200479 # wait until the child process is loaded and has started
480 first_line = process.stdout.readline()
481
Victor Stinner19e5bcd2011-07-01 15:59:54 +0200482 stdout, stderr = process.communicate(timeout=5.0)
Victor Stinnerd6284962011-06-20 23:28:09 +0200483 except subprocess.TimeoutExpired:
484 process.kill()
Christian Heimes8640e742008-02-23 16:23:06 +0000485 return False
Victor Stinnerd6284962011-06-20 23:28:09 +0200486 else:
Victor Stinner45273652011-06-22 22:15:51 +0200487 stdout = first_line + stdout
Victor Stinnerd6284962011-06-20 23:28:09 +0200488 exitcode = process.wait()
489 if exitcode not in (2, 3):
Antoine Pitroudab4e8a2014-05-11 19:05:23 +0200490 raise Exception("Child error (exit code %s): %r"
Victor Stinnerd6284962011-06-20 23:28:09 +0200491 % (exitcode, stdout))
492 return (exitcode == 3)
Christian Heimes8640e742008-02-23 16:23:06 +0000493
494 def test_without_siginterrupt(self):
Victor Stinner3a7f0f02011-05-08 02:10:36 +0200495 # If a signal handler is installed and siginterrupt is not called
496 # at all, when that signal arrives, it interrupts a syscall that's in
497 # progress.
Victor Stinnerd6284962011-06-20 23:28:09 +0200498 interrupted = self.readpipe_interrupted(None)
499 self.assertTrue(interrupted)
Christian Heimes8640e742008-02-23 16:23:06 +0000500
501 def test_siginterrupt_on(self):
Victor Stinner3a7f0f02011-05-08 02:10:36 +0200502 # If a signal handler is installed and siginterrupt is called with
503 # a true value for the second argument, when that signal arrives, it
504 # interrupts a syscall that's in progress.
Victor Stinnerd6284962011-06-20 23:28:09 +0200505 interrupted = self.readpipe_interrupted(True)
506 self.assertTrue(interrupted)
Christian Heimes8640e742008-02-23 16:23:06 +0000507
508 def test_siginterrupt_off(self):
Victor Stinner3a7f0f02011-05-08 02:10:36 +0200509 # If a signal handler is installed and siginterrupt is called with
510 # a false value for the second argument, when that signal arrives, it
511 # does not interrupt a syscall that's in progress.
Victor Stinnerd6284962011-06-20 23:28:09 +0200512 interrupted = self.readpipe_interrupted(False)
513 self.assertFalse(interrupted)
Jean-Paul Calderone9c39bc72010-05-09 03:25:16 +0000514
515
Brian Curtin3f004b12010-08-06 19:34:52 +0000516@unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
Martin v. Löwis823725e2008-03-24 13:39:54 +0000517class ItimerTest(unittest.TestCase):
518 def setUp(self):
519 self.hndl_called = False
520 self.hndl_count = 0
521 self.itimer = None
Christian Heimescc47b052008-03-25 14:56:36 +0000522 self.old_alarm = signal.signal(signal.SIGALRM, self.sig_alrm)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000523
524 def tearDown(self):
Christian Heimescc47b052008-03-25 14:56:36 +0000525 signal.signal(signal.SIGALRM, self.old_alarm)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000526 if self.itimer is not None: # test_itimer_exc doesn't change this attr
527 # just ensure that itimer is stopped
528 signal.setitimer(self.itimer, 0)
529
530 def sig_alrm(self, *args):
531 self.hndl_called = True
Martin v. Löwis823725e2008-03-24 13:39:54 +0000532
533 def sig_vtalrm(self, *args):
534 self.hndl_called = True
535
536 if self.hndl_count > 3:
537 # it shouldn't be here, because it should have been disabled.
538 raise signal.ItimerError("setitimer didn't disable ITIMER_VIRTUAL "
539 "timer.")
540 elif self.hndl_count == 3:
541 # disable ITIMER_VIRTUAL, this function shouldn't be called anymore
542 signal.setitimer(signal.ITIMER_VIRTUAL, 0)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000543
544 self.hndl_count += 1
545
Martin v. Löwis823725e2008-03-24 13:39:54 +0000546 def sig_prof(self, *args):
547 self.hndl_called = True
548 signal.setitimer(signal.ITIMER_PROF, 0)
549
Martin v. Löwis823725e2008-03-24 13:39:54 +0000550 def test_itimer_exc(self):
551 # XXX I'm assuming -1 is an invalid itimer, but maybe some platform
552 # defines it ?
553 self.assertRaises(signal.ItimerError, signal.setitimer, -1, 0)
Christian Heimescc47b052008-03-25 14:56:36 +0000554 # Negative times are treated as zero on some platforms.
555 if 0:
556 self.assertRaises(signal.ItimerError,
557 signal.setitimer, signal.ITIMER_REAL, -1)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000558
559 def test_itimer_real(self):
560 self.itimer = signal.ITIMER_REAL
Martin v. Löwis823725e2008-03-24 13:39:54 +0000561 signal.setitimer(self.itimer, 1.0)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000562 signal.pause()
Martin v. Löwis823725e2008-03-24 13:39:54 +0000563 self.assertEqual(self.hndl_called, True)
564
R. David Murray44546f82010-04-21 01:59:28 +0000565 # Issue 3864, unknown if this affects earlier versions of freebsd also
Gregory P. Smith397cd8a2010-10-17 04:23:21 +0000566 @unittest.skipIf(sys.platform in ('freebsd6', 'netbsd5'),
567 'itimer not reliable (does not mix well with threading) on some BSDs.')
Martin v. Löwis823725e2008-03-24 13:39:54 +0000568 def test_itimer_virtual(self):
569 self.itimer = signal.ITIMER_VIRTUAL
570 signal.signal(signal.SIGVTALRM, self.sig_vtalrm)
571 signal.setitimer(self.itimer, 0.3, 0.2)
572
Victor Stinner79d68f92015-03-19 21:54:09 +0100573 start_time = time.monotonic()
574 while time.monotonic() - start_time < 60.0:
Mark Dickinson95078872009-10-04 18:47:48 +0000575 # use up some virtual time by doing real work
576 _ = pow(12345, 67890, 10000019)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000577 if signal.getitimer(self.itimer) == (0.0, 0.0):
578 break # sig_vtalrm handler stopped this itimer
Stefan Krahf1da973042010-04-20 08:15:14 +0000579 else: # Issue 8424
Benjamin Peterson9b140f62010-05-15 18:00:56 +0000580 self.skipTest("timeout: likely cause: machine too slow or load too "
581 "high")
Martin v. Löwis823725e2008-03-24 13:39:54 +0000582
583 # virtual itimer should be (0.0, 0.0) now
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000584 self.assertEqual(signal.getitimer(self.itimer), (0.0, 0.0))
Martin v. Löwis823725e2008-03-24 13:39:54 +0000585 # and the handler should have been called
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000586 self.assertEqual(self.hndl_called, True)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000587
R. David Murray44546f82010-04-21 01:59:28 +0000588 # Issue 3864, unknown if this affects earlier versions of freebsd also
589 @unittest.skipIf(sys.platform=='freebsd6',
590 'itimer not reliable (does not mix well with threading) on freebsd6')
Martin v. Löwis823725e2008-03-24 13:39:54 +0000591 def test_itimer_prof(self):
592 self.itimer = signal.ITIMER_PROF
593 signal.signal(signal.SIGPROF, self.sig_prof)
Neal Norwitzf5c7c2e2008-04-05 04:47:45 +0000594 signal.setitimer(self.itimer, 0.2, 0.2)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000595
Victor Stinner79d68f92015-03-19 21:54:09 +0100596 start_time = time.monotonic()
597 while time.monotonic() - start_time < 60.0:
Mark Dickinson78373472009-10-31 10:39:21 +0000598 # do some work
599 _ = pow(12345, 67890, 10000019)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000600 if signal.getitimer(self.itimer) == (0.0, 0.0):
601 break # sig_prof handler stopped this itimer
Stefan Krahf1da973042010-04-20 08:15:14 +0000602 else: # Issue 8424
Benjamin Peterson9b140f62010-05-15 18:00:56 +0000603 self.skipTest("timeout: likely cause: machine too slow or load too "
604 "high")
Martin v. Löwis823725e2008-03-24 13:39:54 +0000605
Neal Norwitzf5c7c2e2008-04-05 04:47:45 +0000606 # profiling itimer should be (0.0, 0.0) now
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000607 self.assertEqual(signal.getitimer(self.itimer), (0.0, 0.0))
Neal Norwitzf5c7c2e2008-04-05 04:47:45 +0000608 # and the handler should have been called
Martin v. Löwis823725e2008-03-24 13:39:54 +0000609 self.assertEqual(self.hndl_called, True)
610
Antoine Pitrou729780a2017-06-30 10:01:05 +0200611 def test_setitimer_tiny(self):
612 # bpo-30807: C setitimer() takes a microsecond-resolution interval.
613 # Check that float -> timeval conversion doesn't round
614 # the interval down to zero, which would disable the timer.
615 self.itimer = signal.ITIMER_REAL
616 signal.setitimer(self.itimer, 1e-6)
617 time.sleep(1)
618 self.assertEqual(self.hndl_called, True)
619
Victor Stinnera9293352011-04-30 15:21:58 +0200620
Victor Stinner35b300c2011-05-04 13:20:35 +0200621class PendingSignalsTests(unittest.TestCase):
622 """
Victor Stinnerb3e72192011-05-08 01:46:11 +0200623 Test pthread_sigmask(), pthread_kill(), sigpending() and sigwait()
624 functions.
Victor Stinner35b300c2011-05-04 13:20:35 +0200625 """
Victor Stinnerb3e72192011-05-08 01:46:11 +0200626 @unittest.skipUnless(hasattr(signal, 'sigpending'),
627 'need signal.sigpending()')
628 def test_sigpending_empty(self):
629 self.assertEqual(signal.sigpending(), set())
630
631 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
632 'need signal.pthread_sigmask()')
633 @unittest.skipUnless(hasattr(signal, 'sigpending'),
634 'need signal.sigpending()')
635 def test_sigpending(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200636 code = """if 1:
637 import os
638 import signal
Victor Stinnerb3e72192011-05-08 01:46:11 +0200639
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200640 def handler(signum, frame):
641 1/0
Victor Stinnerb3e72192011-05-08 01:46:11 +0200642
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200643 signum = signal.SIGUSR1
644 signal.signal(signum, handler)
645
646 signal.pthread_sigmask(signal.SIG_BLOCK, [signum])
647 os.kill(os.getpid(), signum)
648 pending = signal.sigpending()
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +0200649 for sig in pending:
650 assert isinstance(sig, signal.Signals), repr(pending)
Victor Stinner0a01f132011-07-04 18:06:35 +0200651 if pending != {signum}:
652 raise Exception('%s != {%s}' % (pending, signum))
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200653 try:
654 signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum])
655 except ZeroDivisionError:
656 pass
657 else:
658 raise Exception("ZeroDivisionError not raised")
659 """
660 assert_python_ok('-c', code)
Victor Stinnerb3e72192011-05-08 01:46:11 +0200661
662 @unittest.skipUnless(hasattr(signal, 'pthread_kill'),
663 'need signal.pthread_kill()')
664 def test_pthread_kill(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200665 code = """if 1:
666 import signal
667 import threading
668 import sys
Victor Stinnerb3e72192011-05-08 01:46:11 +0200669
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200670 signum = signal.SIGUSR1
Victor Stinnerb3e72192011-05-08 01:46:11 +0200671
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200672 def handler(signum, frame):
673 1/0
674
675 signal.signal(signum, handler)
676
677 if sys.platform == 'freebsd6':
678 # Issue #12392 and #12469: send a signal to the main thread
679 # doesn't work before the creation of the first thread on
680 # FreeBSD 6
681 def noop():
682 pass
683 thread = threading.Thread(target=noop)
684 thread.start()
685 thread.join()
686
687 tid = threading.get_ident()
688 try:
689 signal.pthread_kill(tid, signum)
690 except ZeroDivisionError:
691 pass
692 else:
693 raise Exception("ZeroDivisionError not raised")
694 """
695 assert_python_ok('-c', code)
Victor Stinnerb3e72192011-05-08 01:46:11 +0200696
Victor Stinner7f294d12011-06-10 14:02:10 +0200697 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
698 'need signal.pthread_sigmask()')
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200699 def wait_helper(self, blocked, test):
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200700 """
701 test: body of the "def test(signum):" function.
702 blocked: number of the blocked signal
703 """
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200704 code = '''if 1:
705 import signal
706 import sys
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +0200707 from signal import Signals
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200708
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200709 def handler(signum, frame):
710 1/0
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200711
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200712 %s
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200713
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200714 blocked = %s
715 signum = signal.SIGALRM
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200716
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200717 # child: block and wait the signal
718 try:
719 signal.signal(signum, handler)
720 signal.pthread_sigmask(signal.SIG_BLOCK, [blocked])
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200721
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200722 # Do the tests
723 test(signum)
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200724
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200725 # The handler must not be called on unblock
726 try:
727 signal.pthread_sigmask(signal.SIG_UNBLOCK, [blocked])
728 except ZeroDivisionError:
729 print("the signal handler has been called",
730 file=sys.stderr)
731 sys.exit(1)
732 except BaseException as err:
733 print("error: {}".format(err), file=sys.stderr)
734 sys.stderr.flush()
735 sys.exit(1)
736 ''' % (test.strip(), blocked)
Victor Stinner415007e2011-06-13 16:19:06 +0200737
Ross Lagerwallbc808222011-06-25 12:13:40 +0200738 # sig*wait* must be called with the signal blocked: since the current
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200739 # process might have several threads running, use a subprocess to have
740 # a single thread.
741 assert_python_ok('-c', code)
Victor Stinneraf494602011-06-10 12:48:13 +0200742
Victor Stinnerb3e72192011-05-08 01:46:11 +0200743 @unittest.skipUnless(hasattr(signal, 'sigwait'),
744 'need signal.sigwait()')
Ross Lagerwallbc808222011-06-25 12:13:40 +0200745 def test_sigwait(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 Stinner9e8b82f2011-06-29 10:43:02 +0200749 received = signal.sigwait([signum])
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +0200750 assert isinstance(received, signal.Signals), received
Victor Stinner0a01f132011-07-04 18:06:35 +0200751 if received != signum:
752 raise Exception('received %s, not %s' % (received, signum))
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200753 ''')
Ross Lagerwallbc808222011-06-25 12:13:40 +0200754
755 @unittest.skipUnless(hasattr(signal, 'sigwaitinfo'),
756 'need signal.sigwaitinfo()')
757 def test_sigwaitinfo(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200758 self.wait_helper(signal.SIGALRM, '''
759 def test(signum):
Ross Lagerwallbc808222011-06-25 12:13:40 +0200760 signal.alarm(1)
761 info = signal.sigwaitinfo([signum])
Victor Stinner0a01f132011-07-04 18:06:35 +0200762 if info.si_signo != signum:
763 raise Exception("info.si_signo != %s" % signum)
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200764 ''')
Ross Lagerwallbc808222011-06-25 12:13:40 +0200765
766 @unittest.skipUnless(hasattr(signal, 'sigtimedwait'),
767 'need signal.sigtimedwait()')
768 def test_sigtimedwait(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200769 self.wait_helper(signal.SIGALRM, '''
770 def test(signum):
Ross Lagerwallbc808222011-06-25 12:13:40 +0200771 signal.alarm(1)
Victor Stinner643cd682012-03-02 22:54:03 +0100772 info = signal.sigtimedwait([signum], 10.1000)
Victor Stinner0a01f132011-07-04 18:06:35 +0200773 if info.si_signo != signum:
774 raise Exception('info.si_signo != %s' % signum)
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200775 ''')
Ross Lagerwallbc808222011-06-25 12:13:40 +0200776
Ross Lagerwallbc808222011-06-25 12:13:40 +0200777 @unittest.skipUnless(hasattr(signal, 'sigtimedwait'),
778 'need signal.sigtimedwait()')
779 def test_sigtimedwait_poll(self):
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200780 # check that polling with sigtimedwait works
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200781 self.wait_helper(signal.SIGALRM, '''
782 def test(signum):
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200783 import os
784 os.kill(os.getpid(), signum)
Victor Stinner643cd682012-03-02 22:54:03 +0100785 info = signal.sigtimedwait([signum], 0)
Victor Stinner0a01f132011-07-04 18:06:35 +0200786 if info.si_signo != signum:
787 raise Exception('info.si_signo != %s' % signum)
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200788 ''')
Ross Lagerwallbc808222011-06-25 12:13:40 +0200789
790 @unittest.skipUnless(hasattr(signal, 'sigtimedwait'),
791 'need signal.sigtimedwait()')
792 def test_sigtimedwait_timeout(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200793 self.wait_helper(signal.SIGALRM, '''
794 def test(signum):
Victor Stinner643cd682012-03-02 22:54:03 +0100795 received = signal.sigtimedwait([signum], 1.0)
Victor Stinner0a01f132011-07-04 18:06:35 +0200796 if received is not None:
797 raise Exception("received=%r" % (received,))
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200798 ''')
Ross Lagerwallbc808222011-06-25 12:13:40 +0200799
800 @unittest.skipUnless(hasattr(signal, 'sigtimedwait'),
801 'need signal.sigtimedwait()')
802 def test_sigtimedwait_negative_timeout(self):
803 signum = signal.SIGALRM
Victor Stinner643cd682012-03-02 22:54:03 +0100804 self.assertRaises(ValueError, signal.sigtimedwait, [signum], -1.0)
Ross Lagerwallbc808222011-06-25 12:13:40 +0200805
Ross Lagerwallbc808222011-06-25 12:13:40 +0200806 @unittest.skipUnless(hasattr(signal, 'sigwait'),
807 'need signal.sigwait()')
Victor Stinner415007e2011-06-13 16:19:06 +0200808 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
809 'need signal.pthread_sigmask()')
Victor Stinner10c30d62011-06-10 01:39:53 +0200810 @unittest.skipIf(threading is None, "test needs threading module")
811 def test_sigwait_thread(self):
Victor Stinner415007e2011-06-13 16:19:06 +0200812 # Check that calling sigwait() from a thread doesn't suspend the whole
813 # process. A new interpreter is spawned to avoid problems when mixing
814 # threads and fork(): only async-safe functions are allowed between
815 # fork() and exec().
816 assert_python_ok("-c", """if True:
817 import os, threading, sys, time, signal
Victor Stinner10c30d62011-06-10 01:39:53 +0200818
Victor Stinner415007e2011-06-13 16:19:06 +0200819 # the default handler terminates the process
820 signum = signal.SIGUSR1
821
822 def kill_later():
823 # wait until the main thread is waiting in sigwait()
824 time.sleep(1)
825 os.kill(os.getpid(), signum)
826
827 # the signal must be blocked by all the threads
828 signal.pthread_sigmask(signal.SIG_BLOCK, [signum])
829 killer = threading.Thread(target=kill_later)
Victor Stinneraf494602011-06-10 12:48:13 +0200830 killer.start()
831 received = signal.sigwait([signum])
832 if received != signum:
833 print("sigwait() received %s, not %s" % (received, signum),
834 file=sys.stderr)
Victor Stinner415007e2011-06-13 16:19:06 +0200835 sys.exit(1)
Victor Stinner10c30d62011-06-10 01:39:53 +0200836 killer.join()
Victor Stinner415007e2011-06-13 16:19:06 +0200837 # unblock the signal, which should have been cleared by sigwait()
838 signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum])
839 """)
Victor Stinneraf494602011-06-10 12:48:13 +0200840
Victor Stinnerb3e72192011-05-08 01:46:11 +0200841 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
842 'need signal.pthread_sigmask()')
843 def test_pthread_sigmask_arguments(self):
844 self.assertRaises(TypeError, signal.pthread_sigmask)
845 self.assertRaises(TypeError, signal.pthread_sigmask, 1)
846 self.assertRaises(TypeError, signal.pthread_sigmask, 1, 2, 3)
847 self.assertRaises(OSError, signal.pthread_sigmask, 1700, [])
848
849 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
850 'need signal.pthread_sigmask()')
851 def test_pthread_sigmask(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200852 code = """if 1:
853 import signal
854 import os; import threading
855
856 def handler(signum, frame):
857 1/0
858
859 def kill(signum):
860 os.kill(os.getpid(), signum)
861
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +0200862 def check_mask(mask):
863 for sig in mask:
864 assert isinstance(sig, signal.Signals), repr(sig)
865
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200866 def read_sigmask():
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +0200867 sigmask = signal.pthread_sigmask(signal.SIG_BLOCK, [])
868 check_mask(sigmask)
869 return sigmask
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200870
Victor Stinnerb3e72192011-05-08 01:46:11 +0200871 signum = signal.SIGUSR1
Victor Stinner6fd49e12011-05-04 12:38:03 +0200872
Victor Stinnerd0e516d2011-05-03 14:57:12 +0200873 # Install our signal handler
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200874 old_handler = signal.signal(signum, handler)
Victor Stinnera9293352011-04-30 15:21:58 +0200875
Victor Stinnerd0e516d2011-05-03 14:57:12 +0200876 # Unblock SIGUSR1 (and copy the old mask) to test our signal handler
Victor Stinnera9293352011-04-30 15:21:58 +0200877 old_mask = signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum])
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +0200878 check_mask(old_mask)
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200879 try:
880 kill(signum)
881 except ZeroDivisionError:
882 pass
883 else:
884 raise Exception("ZeroDivisionError not raised")
Victor Stinnera9293352011-04-30 15:21:58 +0200885
Victor Stinnerd0e516d2011-05-03 14:57:12 +0200886 # Block and then raise SIGUSR1. The signal is blocked: the signal
887 # handler is not called, and the signal is now pending
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +0200888 mask = signal.pthread_sigmask(signal.SIG_BLOCK, [signum])
889 check_mask(mask)
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200890 kill(signum)
Victor Stinnera9293352011-04-30 15:21:58 +0200891
Victor Stinnerd0e516d2011-05-03 14:57:12 +0200892 # Check the new mask
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200893 blocked = read_sigmask()
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +0200894 check_mask(blocked)
Victor Stinner0a01f132011-07-04 18:06:35 +0200895 if signum not in blocked:
896 raise Exception("%s not in %s" % (signum, blocked))
897 if old_mask ^ blocked != {signum}:
898 raise Exception("%s ^ %s != {%s}" % (old_mask, blocked, signum))
Victor Stinnera9293352011-04-30 15:21:58 +0200899
Victor Stinnerd0e516d2011-05-03 14:57:12 +0200900 # Unblock SIGUSR1
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200901 try:
R David Murrayfc069992013-12-13 20:52:19 -0500902 # unblock the pending signal calls immediately the signal handler
Victor Stinnerd0e516d2011-05-03 14:57:12 +0200903 signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum])
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200904 except ZeroDivisionError:
905 pass
906 else:
907 raise Exception("ZeroDivisionError not raised")
908 try:
909 kill(signum)
910 except ZeroDivisionError:
911 pass
912 else:
913 raise Exception("ZeroDivisionError not raised")
Victor Stinnera9293352011-04-30 15:21:58 +0200914
Victor Stinnerd0e516d2011-05-03 14:57:12 +0200915 # Check the new mask
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200916 unblocked = read_sigmask()
Victor Stinner0a01f132011-07-04 18:06:35 +0200917 if signum in unblocked:
918 raise Exception("%s in %s" % (signum, unblocked))
919 if blocked ^ unblocked != {signum}:
920 raise Exception("%s ^ %s != {%s}" % (blocked, unblocked, signum))
921 if old_mask != unblocked:
922 raise Exception("%s != %s" % (old_mask, unblocked))
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200923 """
924 assert_python_ok('-c', code)
925
926 @unittest.skipIf(sys.platform == 'freebsd6',
927 "issue #12392: send a signal to the main thread doesn't work "
928 "before the creation of the first thread on FreeBSD 6")
929 @unittest.skipUnless(hasattr(signal, 'pthread_kill'),
930 'need signal.pthread_kill()')
931 def test_pthread_kill_main_thread(self):
932 # Test that a signal can be sent to the main thread with pthread_kill()
933 # before any other thread has been created (see issue #12392).
934 code = """if True:
935 import threading
936 import signal
937 import sys
938
939 def handler(signum, frame):
940 sys.exit(3)
941
942 signal.signal(signal.SIGUSR1, handler)
943 signal.pthread_kill(threading.get_ident(), signal.SIGUSR1)
944 sys.exit(2)
945 """
946
947 with spawn_python('-c', code) as process:
948 stdout, stderr = process.communicate()
949 exitcode = process.wait()
950 if exitcode != 3:
951 raise Exception("Child error (exit code %s): %s" %
952 (exitcode, stdout))
Victor Stinnera9293352011-04-30 15:21:58 +0200953
954
Antoine Pitrouc08177a2017-06-28 23:29:29 +0200955class StressTest(unittest.TestCase):
956 """
957 Stress signal delivery, especially when a signal arrives in
958 the middle of recomputing the signal state or executing
959 previously tripped signal handlers.
960 """
961
Antoine Pitrouf7d090c2017-06-29 16:40:14 +0200962 def setsig(self, signum, handler):
963 old_handler = signal.signal(signum, handler)
964 self.addCleanup(signal.signal, signum, old_handler)
965
966 def measure_itimer_resolution(self):
967 N = 20
968 times = []
969
970 def handler(signum=None, frame=None):
971 if len(times) < N:
972 times.append(time.perf_counter())
973 # 1 µs is the smallest possible timer interval,
974 # we want to measure what the concrete duration
975 # will be on this platform
976 signal.setitimer(signal.ITIMER_REAL, 1e-6)
977
978 self.addCleanup(signal.setitimer, signal.ITIMER_REAL, 0)
979 self.setsig(signal.SIGALRM, handler)
980 handler()
981 while len(times) < N:
982 time.sleep(1e-3)
983
984 durations = [times[i+1] - times[i] for i in range(len(times) - 1)]
985 med = statistics.median(durations)
986 if support.verbose:
987 print("detected median itimer() resolution: %.6f s." % (med,))
988 return med
989
990 def decide_itimer_count(self):
991 # Some systems have poor setitimer() resolution (for example
992 # measured around 20 ms. on FreeBSD 9), so decide on a reasonable
993 # number of sequential timers based on that.
994 reso = self.measure_itimer_resolution()
995 if reso <= 1e-4:
996 return 10000
997 elif reso <= 1e-2:
998 return 100
999 else:
1000 self.skipTest("detected itimer resolution (%.3f s.) too high "
1001 "(> 10 ms.) on this platform (or system too busy)"
1002 % (reso,))
1003
Antoine Pitrouc08177a2017-06-28 23:29:29 +02001004 @unittest.skipUnless(hasattr(signal, "setitimer"),
1005 "test needs setitimer()")
1006 def test_stress_delivery_dependent(self):
1007 """
1008 This test uses dependent signal handlers.
1009 """
Antoine Pitrouf7d090c2017-06-29 16:40:14 +02001010 N = self.decide_itimer_count()
Antoine Pitrouc08177a2017-06-28 23:29:29 +02001011 sigs = []
1012
1013 def first_handler(signum, frame):
1014 # 1e-6 is the minimum non-zero value for `setitimer()`.
1015 # Choose a random delay so as to improve chances of
1016 # triggering a race condition. Ideally the signal is received
1017 # when inside critical signal-handling routines such as
1018 # Py_MakePendingCalls().
1019 signal.setitimer(signal.ITIMER_REAL, 1e-6 + random.random() * 1e-5)
1020
1021 def second_handler(signum=None, frame=None):
1022 sigs.append(signum)
1023
Antoine Pitrouc08177a2017-06-28 23:29:29 +02001024 # Here on Linux, SIGPROF > SIGALRM > SIGUSR1. By using both
1025 # ascending and descending sequences (SIGUSR1 then SIGALRM,
1026 # SIGPROF then SIGALRM), we maximize chances of hitting a bug.
Antoine Pitrouf7d090c2017-06-29 16:40:14 +02001027 self.setsig(signal.SIGPROF, first_handler)
1028 self.setsig(signal.SIGUSR1, first_handler)
1029 self.setsig(signal.SIGALRM, second_handler) # for ITIMER_REAL
Antoine Pitrouc08177a2017-06-28 23:29:29 +02001030
1031 expected_sigs = 0
1032 deadline = time.time() + 15.0
1033
1034 while expected_sigs < N:
1035 os.kill(os.getpid(), signal.SIGPROF)
1036 expected_sigs += 1
1037 # Wait for handlers to run to avoid signal coalescing
1038 while len(sigs) < expected_sigs and time.time() < deadline:
1039 time.sleep(1e-5)
1040
1041 os.kill(os.getpid(), signal.SIGUSR1)
1042 expected_sigs += 1
1043 while len(sigs) < expected_sigs and time.time() < deadline:
1044 time.sleep(1e-5)
1045
1046 # All ITIMER_REAL signals should have been delivered to the
1047 # Python handler
1048 self.assertEqual(len(sigs), N, "Some signals were lost")
1049
1050 @unittest.skipUnless(hasattr(signal, "setitimer"),
1051 "test needs setitimer()")
1052 def test_stress_delivery_simultaneous(self):
1053 """
1054 This test uses simultaneous signal handlers.
1055 """
Antoine Pitrouf7d090c2017-06-29 16:40:14 +02001056 N = self.decide_itimer_count()
Antoine Pitrouc08177a2017-06-28 23:29:29 +02001057 sigs = []
1058
1059 def handler(signum, frame):
1060 sigs.append(signum)
1061
Antoine Pitrouf7d090c2017-06-29 16:40:14 +02001062 self.setsig(signal.SIGUSR1, handler)
1063 self.setsig(signal.SIGALRM, handler) # for ITIMER_REAL
Antoine Pitrouc08177a2017-06-28 23:29:29 +02001064
1065 expected_sigs = 0
1066 deadline = time.time() + 15.0
1067
1068 while expected_sigs < N:
1069 # Hopefully the SIGALRM will be received somewhere during
1070 # initial processing of SIGUSR1.
1071 signal.setitimer(signal.ITIMER_REAL, 1e-6 + random.random() * 1e-5)
1072 os.kill(os.getpid(), signal.SIGUSR1)
1073
1074 expected_sigs += 2
1075 # Wait for handlers to run to avoid signal coalescing
1076 while len(sigs) < expected_sigs and time.time() < deadline:
1077 time.sleep(1e-5)
1078
1079 # All ITIMER_REAL signals should have been delivered to the
1080 # Python handler
1081 self.assertEqual(len(sigs), N, "Some signals were lost")
1082
1083
Zachary Ware38c707e2015-04-13 15:00:43 -05001084def tearDownModule():
1085 support.reap_children()
Thomas Woutersed03b412007-08-28 21:37:11 +00001086
1087if __name__ == "__main__":
Zachary Ware38c707e2015-04-13 15:00:43 -05001088 unittest.main()