blob: f17123c3bb50d1b2123821c3b707829b09fe314f [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
Antoine Pitroua6a4dc82017-09-07 18:56:24 +02008import threading
Victor Stinnerd6debb22017-03-27 16:05:26 +02009import time
10import unittest
11from test import support
Berker Peksagce643912015-05-06 06:33:17 +030012from test.support.script_helper import assert_python_ok, spawn_python
Victor Stinnerb3e72192011-05-08 01:46:11 +020013try:
Victor Stinner56e8c292014-07-21 12:30:22 +020014 import _testcapi
15except ImportError:
16 _testcapi = None
Christian Heimesc06950e2008-02-28 21:17:00 +000017
Guido van Rossumcc5a91d1997-04-16 00:29:15 +000018
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +020019class GenericTests(unittest.TestCase):
20
21 def test_enums(self):
22 for name in dir(signal):
23 sig = getattr(signal, name)
24 if name in {'SIG_DFL', 'SIG_IGN'}:
25 self.assertIsInstance(sig, signal.Handlers)
26 elif name in {'SIG_BLOCK', 'SIG_UNBLOCK', 'SIG_SETMASK'}:
27 self.assertIsInstance(sig, signal.Sigmasks)
28 elif name.startswith('SIG') and not name.startswith('SIG_'):
29 self.assertIsInstance(sig, signal.Signals)
30 elif name.startswith('CTRL_'):
31 self.assertIsInstance(sig, signal.Signals)
32 self.assertEqual(sys.platform, "win32")
33
34
Brian Curtin3f004b12010-08-06 19:34:52 +000035@unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
Victor Stinnerb3e72192011-05-08 01:46:11 +020036class PosixTests(unittest.TestCase):
Christian Heimes4fbc72b2008-03-22 00:47:35 +000037 def trivial_signal_handler(self, *args):
38 pass
39
Thomas Woutersed03b412007-08-28 21:37:11 +000040 def test_out_of_range_signal_number_raises_error(self):
41 self.assertRaises(ValueError, signal.getsignal, 4242)
42
Thomas Woutersed03b412007-08-28 21:37:11 +000043 self.assertRaises(ValueError, signal.signal, 4242,
Christian Heimes4fbc72b2008-03-22 00:47:35 +000044 self.trivial_signal_handler)
Thomas Woutersed03b412007-08-28 21:37:11 +000045
46 def test_setting_signal_handler_to_none_raises_error(self):
47 self.assertRaises(TypeError, signal.signal,
48 signal.SIGUSR1, None)
49
Christian Heimes4fbc72b2008-03-22 00:47:35 +000050 def test_getsignal(self):
51 hup = signal.signal(signal.SIGHUP, self.trivial_signal_handler)
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +020052 self.assertIsInstance(hup, signal.Handlers)
Ezio Melotti19f2aeb2010-11-21 01:30:29 +000053 self.assertEqual(signal.getsignal(signal.SIGHUP),
54 self.trivial_signal_handler)
Christian Heimes4fbc72b2008-03-22 00:47:35 +000055 signal.signal(signal.SIGHUP, hup)
Ezio Melotti19f2aeb2010-11-21 01:30:29 +000056 self.assertEqual(signal.getsignal(signal.SIGHUP), hup)
Christian Heimes4fbc72b2008-03-22 00:47:35 +000057
Victor Stinner32eb8402016-03-15 11:12:35 +010058 # Issue 3864, unknown if this affects earlier versions of freebsd also
59 @unittest.skipIf(sys.platform=='freebsd6',
60 'inter process signals not reliable (do not mix well with threading) '
61 'on freebsd6')
62 def test_interprocess_signal(self):
63 dirname = os.path.dirname(__file__)
64 script = os.path.join(dirname, 'signalinterproctester.py')
65 assert_python_ok(script)
66
Christian Heimes4fbc72b2008-03-22 00:47:35 +000067
Brian Curtin3f004b12010-08-06 19:34:52 +000068@unittest.skipUnless(sys.platform == "win32", "Windows specific")
69class WindowsSignalTests(unittest.TestCase):
70 def test_issue9324(self):
Brian Curtineccd4d92010-10-01 15:09:53 +000071 # Updated for issue #10003, adding SIGBREAK
Brian Curtin3f004b12010-08-06 19:34:52 +000072 handler = lambda x, y: None
Nick Coghlan60b3ac72013-08-03 22:56:30 +100073 checked = set()
Brian Curtineccd4d92010-10-01 15:09:53 +000074 for sig in (signal.SIGABRT, signal.SIGBREAK, signal.SIGFPE,
75 signal.SIGILL, signal.SIGINT, signal.SIGSEGV,
76 signal.SIGTERM):
Nick Coghlan60b3ac72013-08-03 22:56:30 +100077 # Set and then reset a handler for signals that work on windows.
78 # Issue #18396, only for signals without a C-level handler.
79 if signal.getsignal(sig) is not None:
80 signal.signal(sig, signal.signal(sig, handler))
81 checked.add(sig)
82 # Issue #18396: Ensure the above loop at least tested *something*
83 self.assertTrue(checked)
Brian Curtin3f004b12010-08-06 19:34:52 +000084
85 with self.assertRaises(ValueError):
86 signal.signal(-1, handler)
Brian Curtin80cd4bf2010-08-07 03:52:38 +000087
88 with self.assertRaises(ValueError):
89 signal.signal(7, handler)
Brian Curtin3f004b12010-08-06 19:34:52 +000090
91
Benjamin Petersonc68a4a02013-01-18 00:10:24 -050092class WakeupFDTests(unittest.TestCase):
93
Nathaniel J. Smith902ab802017-12-17 20:10:18 -080094 def test_invalid_call(self):
95 # First parameter is positional-only
96 with self.assertRaises(TypeError):
97 signal.set_wakeup_fd(signum=signal.SIGINT)
98
99 # warn_on_full_buffer is a keyword-only parameter
100 with self.assertRaises(TypeError):
101 signal.set_wakeup_fd(signal.SIGINT, False)
102
Benjamin Petersonc68a4a02013-01-18 00:10:24 -0500103 def test_invalid_fd(self):
Victor Stinner1d8948e2014-07-24 22:51:05 +0200104 fd = support.make_bad_fd()
Victor Stinnera7d03d92014-07-21 17:17:28 +0200105 self.assertRaises((ValueError, OSError),
106 signal.set_wakeup_fd, fd)
Benjamin Petersonc68a4a02013-01-18 00:10:24 -0500107
Victor Stinner11517102014-07-29 23:31:34 +0200108 def test_invalid_socket(self):
109 sock = socket.socket()
110 fd = sock.fileno()
111 sock.close()
112 self.assertRaises((ValueError, OSError),
113 signal.set_wakeup_fd, fd)
114
Victor Stinnerd18ccd12014-07-24 21:58:53 +0200115 def test_set_wakeup_fd_result(self):
Victor Stinner1d8948e2014-07-24 22:51:05 +0200116 r1, w1 = os.pipe()
117 self.addCleanup(os.close, r1)
118 self.addCleanup(os.close, w1)
119 r2, w2 = os.pipe()
120 self.addCleanup(os.close, r2)
121 self.addCleanup(os.close, w2)
Victor Stinnerd18ccd12014-07-24 21:58:53 +0200122
Victor Stinner7cea44d2014-08-27 14:02:36 +0200123 if hasattr(os, 'set_blocking'):
124 os.set_blocking(w1, False)
125 os.set_blocking(w2, False)
Victor Stinner38227602014-08-27 12:59:44 +0200126
Victor Stinner1d8948e2014-07-24 22:51:05 +0200127 signal.set_wakeup_fd(w1)
Victor Stinnerc82a1792014-07-24 22:55:12 +0200128 self.assertEqual(signal.set_wakeup_fd(w2), w1)
129 self.assertEqual(signal.set_wakeup_fd(-1), w2)
130 self.assertEqual(signal.set_wakeup_fd(-1), -1)
Victor Stinner56e8c292014-07-21 12:30:22 +0200131
Victor Stinner11517102014-07-29 23:31:34 +0200132 def test_set_wakeup_fd_socket_result(self):
133 sock1 = socket.socket()
134 self.addCleanup(sock1.close)
Victor Stinner38227602014-08-27 12:59:44 +0200135 sock1.setblocking(False)
Victor Stinner11517102014-07-29 23:31:34 +0200136 fd1 = sock1.fileno()
137
138 sock2 = socket.socket()
139 self.addCleanup(sock2.close)
Victor Stinner38227602014-08-27 12:59:44 +0200140 sock2.setblocking(False)
Victor Stinner11517102014-07-29 23:31:34 +0200141 fd2 = sock2.fileno()
142
143 signal.set_wakeup_fd(fd1)
Victor Stinnerda565a72014-07-30 10:03:03 +0200144 self.assertEqual(signal.set_wakeup_fd(fd2), fd1)
145 self.assertEqual(signal.set_wakeup_fd(-1), fd2)
146 self.assertEqual(signal.set_wakeup_fd(-1), -1)
Victor Stinner11517102014-07-29 23:31:34 +0200147
Victor Stinner38227602014-08-27 12:59:44 +0200148 # On Windows, files are always blocking and Windows does not provide a
149 # function to test if a socket is in non-blocking mode.
150 @unittest.skipIf(sys.platform == "win32", "tests specific to POSIX")
151 def test_set_wakeup_fd_blocking(self):
152 rfd, wfd = os.pipe()
153 self.addCleanup(os.close, rfd)
154 self.addCleanup(os.close, wfd)
155
156 # fd must be non-blocking
157 os.set_blocking(wfd, True)
158 with self.assertRaises(ValueError) as cm:
159 signal.set_wakeup_fd(wfd)
160 self.assertEqual(str(cm.exception),
161 "the fd %s must be in non-blocking mode" % wfd)
162
163 # non-blocking is ok
164 os.set_blocking(wfd, False)
165 signal.set_wakeup_fd(wfd)
166 signal.set_wakeup_fd(-1)
167
Benjamin Petersonc68a4a02013-01-18 00:10:24 -0500168
Brian Curtin3f004b12010-08-06 19:34:52 +0000169@unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000170class WakeupSignalTests(unittest.TestCase):
Victor Stinner56e8c292014-07-21 12:30:22 +0200171 @unittest.skipIf(_testcapi is None, 'need _testcapi')
Charles-François Natali027f9a32011-10-02 18:36:05 +0200172 def check_wakeup(self, test_body, *signals, ordered=True):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200173 # use a subprocess to have only one thread
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200174 code = """if 1:
Victor Stinner56e8c292014-07-21 12:30:22 +0200175 import _testcapi
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200176 import os
177 import signal
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200178 import struct
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000179
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200180 signals = {!r}
Victor Stinnerc13ef662011-05-25 02:35:58 +0200181
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200182 def handler(signum, frame):
183 pass
184
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200185 def check_signum(signals):
186 data = os.read(read, len(signals)+1)
187 raised = struct.unpack('%uB' % len(data), data)
Charles-François Natali027f9a32011-10-02 18:36:05 +0200188 if not {!r}:
189 raised = set(raised)
190 signals = set(signals)
Victor Stinner0a01f132011-07-04 18:06:35 +0200191 if raised != signals:
192 raise Exception("%r != %r" % (raised, signals))
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200193
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200194 {}
195
196 signal.signal(signal.SIGALRM, handler)
197 read, write = os.pipe()
Victor Stinner1db9e7b2014-07-29 22:32:47 +0200198 os.set_blocking(write, False)
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200199 signal.set_wakeup_fd(write)
200
201 test()
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200202 check_signum(signals)
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200203
204 os.close(read)
205 os.close(write)
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +0200206 """.format(tuple(map(int, signals)), ordered, test_body)
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200207
208 assert_python_ok('-c', code)
Victor Stinnerd49b1f12011-05-08 02:03:15 +0200209
Victor Stinner56e8c292014-07-21 12:30:22 +0200210 @unittest.skipIf(_testcapi is None, 'need _testcapi')
Antoine Pitrou6f6ec372013-08-17 20:27:56 +0200211 def test_wakeup_write_error(self):
212 # Issue #16105: write() errors in the C signal handler should not
213 # pass silently.
214 # Use a subprocess to have only one thread.
215 code = """if 1:
Victor Stinner56e8c292014-07-21 12:30:22 +0200216 import _testcapi
Antoine Pitrou6f6ec372013-08-17 20:27:56 +0200217 import errno
Antoine Pitrou6f6ec372013-08-17 20:27:56 +0200218 import os
219 import signal
220 import sys
Antoine Pitrou6f6ec372013-08-17 20:27:56 +0200221 from test.support import captured_stderr
222
223 def handler(signum, frame):
224 1/0
225
226 signal.signal(signal.SIGALRM, handler)
227 r, w = os.pipe()
Victor Stinner1db9e7b2014-07-29 22:32:47 +0200228 os.set_blocking(r, False)
Antoine Pitrou6f6ec372013-08-17 20:27:56 +0200229
230 # Set wakeup_fd a read-only file descriptor to trigger the error
231 signal.set_wakeup_fd(r)
232 try:
233 with captured_stderr() as err:
Victor Stinner56e8c292014-07-21 12:30:22 +0200234 _testcapi.raise_signal(signal.SIGALRM)
Antoine Pitrou6f6ec372013-08-17 20:27:56 +0200235 except ZeroDivisionError:
236 # An ignored exception should have been printed out on stderr
237 err = err.getvalue()
238 if ('Exception ignored when trying to write to the signal wakeup fd'
239 not in err):
240 raise AssertionError(err)
241 if ('OSError: [Errno %d]' % errno.EBADF) not in err:
242 raise AssertionError(err)
243 else:
244 raise AssertionError("ZeroDivisionError not raised")
Victor Stinner56e8c292014-07-21 12:30:22 +0200245
246 os.close(r)
247 os.close(w)
Antoine Pitrou6f6ec372013-08-17 20:27:56 +0200248 """
Antoine Pitrou8f0bdda2013-08-17 21:43:47 +0200249 r, w = os.pipe()
250 try:
251 os.write(r, b'x')
252 except OSError:
253 pass
254 else:
255 self.skipTest("OS doesn't report write() error on the read end of a pipe")
256 finally:
257 os.close(r)
258 os.close(w)
Antoine Pitrou6f6ec372013-08-17 20:27:56 +0200259
260 assert_python_ok('-c', code)
261
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000262 def test_wakeup_fd_early(self):
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200263 self.check_wakeup("""def test():
264 import select
265 import time
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000266
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200267 TIMEOUT_FULL = 10
268 TIMEOUT_HALF = 5
269
Victor Stinner749a6a82015-03-30 22:09:14 +0200270 class InterruptSelect(Exception):
271 pass
272
273 def handler(signum, frame):
274 raise InterruptSelect
275 signal.signal(signal.SIGALRM, handler)
276
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200277 signal.alarm(1)
Victor Stinner79d68f92015-03-19 21:54:09 +0100278
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200279 # We attempt to get a signal during the sleep,
280 # before select is called
Victor Stinner79d68f92015-03-19 21:54:09 +0100281 try:
282 select.select([], [], [], TIMEOUT_FULL)
Victor Stinner749a6a82015-03-30 22:09:14 +0200283 except InterruptSelect:
Victor Stinner79d68f92015-03-19 21:54:09 +0100284 pass
285 else:
286 raise Exception("select() was not interrupted")
287
288 before_time = time.monotonic()
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200289 select.select([read], [], [], TIMEOUT_FULL)
Victor Stinner79d68f92015-03-19 21:54:09 +0100290 after_time = time.monotonic()
291 dt = after_time - before_time
Victor Stinner0a01f132011-07-04 18:06:35 +0200292 if dt >= TIMEOUT_HALF:
293 raise Exception("%s >= %s" % (dt, TIMEOUT_HALF))
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200294 """, signal.SIGALRM)
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000295
296 def test_wakeup_fd_during(self):
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200297 self.check_wakeup("""def test():
298 import select
299 import time
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000300
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200301 TIMEOUT_FULL = 10
302 TIMEOUT_HALF = 5
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000303
Victor Stinner749a6a82015-03-30 22:09:14 +0200304 class InterruptSelect(Exception):
305 pass
306
307 def handler(signum, frame):
308 raise InterruptSelect
309 signal.signal(signal.SIGALRM, handler)
310
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200311 signal.alarm(1)
Victor Stinner79d68f92015-03-19 21:54:09 +0100312 before_time = time.monotonic()
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200313 # We attempt to get a signal during the select call
314 try:
315 select.select([read], [], [], TIMEOUT_FULL)
Victor Stinner749a6a82015-03-30 22:09:14 +0200316 except InterruptSelect:
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200317 pass
318 else:
Victor Stinner749a6a82015-03-30 22:09:14 +0200319 raise Exception("select() was not interrupted")
Victor Stinner79d68f92015-03-19 21:54:09 +0100320 after_time = time.monotonic()
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200321 dt = after_time - before_time
Victor Stinner0a01f132011-07-04 18:06:35 +0200322 if dt >= TIMEOUT_HALF:
323 raise Exception("%s >= %s" % (dt, TIMEOUT_HALF))
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200324 """, signal.SIGALRM)
Victor Stinnerd49b1f12011-05-08 02:03:15 +0200325
326 def test_signum(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200327 self.check_wakeup("""def test():
Victor Stinner56e8c292014-07-21 12:30:22 +0200328 import _testcapi
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200329 signal.signal(signal.SIGUSR1, handler)
Victor Stinner56e8c292014-07-21 12:30:22 +0200330 _testcapi.raise_signal(signal.SIGUSR1)
331 _testcapi.raise_signal(signal.SIGALRM)
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200332 """, signal.SIGUSR1, signal.SIGALRM)
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000333
Victor Stinnerc13ef662011-05-25 02:35:58 +0200334 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
335 'need signal.pthread_sigmask()')
Victor Stinnerc13ef662011-05-25 02:35:58 +0200336 def test_pending(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200337 self.check_wakeup("""def test():
338 signum1 = signal.SIGUSR1
339 signum2 = signal.SIGUSR2
Victor Stinnerc13ef662011-05-25 02:35:58 +0200340
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200341 signal.signal(signum1, handler)
342 signal.signal(signum2, handler)
Victor Stinnerc13ef662011-05-25 02:35:58 +0200343
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200344 signal.pthread_sigmask(signal.SIG_BLOCK, (signum1, signum2))
Victor Stinner56e8c292014-07-21 12:30:22 +0200345 _testcapi.raise_signal(signum1)
346 _testcapi.raise_signal(signum2)
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200347 # Unblocking the 2 signals calls the C signal handler twice
348 signal.pthread_sigmask(signal.SIG_UNBLOCK, (signum1, signum2))
Charles-François Natali027f9a32011-10-02 18:36:05 +0200349 """, signal.SIGUSR1, signal.SIGUSR2, ordered=False)
Victor Stinnerc13ef662011-05-25 02:35:58 +0200350
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000351
Victor Stinner11517102014-07-29 23:31:34 +0200352@unittest.skipUnless(hasattr(socket, 'socketpair'), 'need socket.socketpair')
353class WakeupSocketSignalTests(unittest.TestCase):
354
355 @unittest.skipIf(_testcapi is None, 'need _testcapi')
356 def test_socket(self):
357 # use a subprocess to have only one thread
358 code = """if 1:
359 import signal
360 import socket
361 import struct
362 import _testcapi
363
364 signum = signal.SIGINT
365 signals = (signum,)
366
367 def handler(signum, frame):
368 pass
369
370 signal.signal(signum, handler)
371
372 read, write = socket.socketpair()
373 read.setblocking(False)
374 write.setblocking(False)
375 signal.set_wakeup_fd(write.fileno())
376
377 _testcapi.raise_signal(signum)
378
379 data = read.recv(1)
380 if not data:
381 raise Exception("no signum written")
382 raised = struct.unpack('B', data)
383 if raised != signals:
384 raise Exception("%r != %r" % (raised, signals))
385
386 read.close()
387 write.close()
388 """
389
390 assert_python_ok('-c', code)
391
392 @unittest.skipIf(_testcapi is None, 'need _testcapi')
393 def test_send_error(self):
394 # Use a subprocess to have only one thread.
395 if os.name == 'nt':
396 action = 'send'
397 else:
398 action = 'write'
399 code = """if 1:
400 import errno
401 import signal
402 import socket
403 import sys
404 import time
405 import _testcapi
406 from test.support import captured_stderr
407
408 signum = signal.SIGINT
409
410 def handler(signum, frame):
411 pass
412
413 signal.signal(signum, handler)
414
415 read, write = socket.socketpair()
416 read.setblocking(False)
417 write.setblocking(False)
418
419 signal.set_wakeup_fd(write.fileno())
420
421 # Close sockets: send() will fail
422 read.close()
423 write.close()
424
425 with captured_stderr() as err:
426 _testcapi.raise_signal(signum)
427
428 err = err.getvalue()
429 if ('Exception ignored when trying to {action} to the signal wakeup fd'
430 not in err):
431 raise AssertionError(err)
432 """.format(action=action)
433 assert_python_ok('-c', code)
434
Nathaniel J. Smith902ab802017-12-17 20:10:18 -0800435 @unittest.skipIf(_testcapi is None, 'need _testcapi')
436 def test_warn_on_full_buffer(self):
437 # Use a subprocess to have only one thread.
438 if os.name == 'nt':
439 action = 'send'
440 else:
441 action = 'write'
442 code = """if 1:
443 import errno
444 import signal
445 import socket
446 import sys
447 import time
448 import _testcapi
449 from test.support import captured_stderr
450
451 signum = signal.SIGINT
452
453 # This handler will be called, but we intentionally won't read from
454 # the wakeup fd.
455 def handler(signum, frame):
456 pass
457
458 signal.signal(signum, handler)
459
460 read, write = socket.socketpair()
461 read.setblocking(False)
462 write.setblocking(False)
463
464 # Fill the send buffer
465 try:
466 while True:
467 write.send(b"x")
468 except BlockingIOError:
469 pass
470
471 # By default, we get a warning when a signal arrives
472 signal.set_wakeup_fd(write.fileno())
473
474 with captured_stderr() as err:
475 _testcapi.raise_signal(signum)
476
477 err = err.getvalue()
478 if ('Exception ignored when trying to {action} to the signal wakeup fd'
479 not in err):
480 raise AssertionError(err)
481
482 # And also if warn_on_full_buffer=True
483 signal.set_wakeup_fd(write.fileno(), warn_on_full_buffer=True)
484
485 with captured_stderr() as err:
486 _testcapi.raise_signal(signum)
487
488 err = err.getvalue()
489 if ('Exception ignored when trying to {action} to the signal wakeup fd'
490 not in err):
491 raise AssertionError(err)
492
493 # But not if warn_on_full_buffer=False
494 signal.set_wakeup_fd(write.fileno(), warn_on_full_buffer=False)
495
496 with captured_stderr() as err:
497 _testcapi.raise_signal(signum)
498
499 err = err.getvalue()
500 if err != "":
501 raise AssertionError("got unexpected output %r" % (err,))
502
503 # And then check the default again, to make sure warn_on_full_buffer
504 # settings don't leak across calls.
505 signal.set_wakeup_fd(write.fileno())
506
507 with captured_stderr() as err:
508 _testcapi.raise_signal(signum)
509
510 err = err.getvalue()
511 if ('Exception ignored when trying to {action} to the signal wakeup fd'
512 not in err):
513 raise AssertionError(err)
514
515 """.format(action=action)
516 assert_python_ok('-c', code)
517
Victor Stinner11517102014-07-29 23:31:34 +0200518
Brian Curtin3f004b12010-08-06 19:34:52 +0000519@unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
Christian Heimes8640e742008-02-23 16:23:06 +0000520class SiginterruptTest(unittest.TestCase):
Jean-Paul Calderone9c39bc72010-05-09 03:25:16 +0000521
Victor Stinnerd6284962011-06-20 23:28:09 +0200522 def readpipe_interrupted(self, interrupt):
Jean-Paul Calderone9c39bc72010-05-09 03:25:16 +0000523 """Perform a read during which a signal will arrive. Return True if the
524 read is interrupted by the signal and raises an exception. Return False
525 if it returns normally.
526 """
Victor Stinnerd6284962011-06-20 23:28:09 +0200527 # use a subprocess to have only one thread, to have a timeout on the
528 # blocking read and to not touch signal handling in this process
529 code = """if 1:
530 import errno
531 import os
532 import signal
533 import sys
Jean-Paul Calderone9c39bc72010-05-09 03:25:16 +0000534
Victor Stinnerd6284962011-06-20 23:28:09 +0200535 interrupt = %r
536 r, w = os.pipe()
Christian Heimes8640e742008-02-23 16:23:06 +0000537
Victor Stinnerd6284962011-06-20 23:28:09 +0200538 def handler(signum, frame):
Charles-François Natali6e6c59b2015-02-07 13:27:50 +0000539 1 / 0
Victor Stinnerd6284962011-06-20 23:28:09 +0200540
541 signal.signal(signal.SIGALRM, handler)
542 if interrupt is not None:
543 signal.siginterrupt(signal.SIGALRM, interrupt)
544
Victor Stinnerdfde0d42011-07-01 15:58:39 +0200545 print("ready")
546 sys.stdout.flush()
547
Victor Stinnerd6284962011-06-20 23:28:09 +0200548 # run the test twice
Victor Stinner56e8c292014-07-21 12:30:22 +0200549 try:
550 for loop in range(2):
551 # send a SIGALRM in a second (during the read)
552 signal.alarm(1)
553 try:
554 # blocking call: read from a pipe without data
555 os.read(r, 1)
Charles-François Natali6e6c59b2015-02-07 13:27:50 +0000556 except ZeroDivisionError:
557 pass
Victor Stinner56e8c292014-07-21 12:30:22 +0200558 else:
559 sys.exit(2)
560 sys.exit(3)
561 finally:
562 os.close(r)
563 os.close(w)
Victor Stinnerd6284962011-06-20 23:28:09 +0200564 """ % (interrupt,)
565 with spawn_python('-c', code) as process:
Christian Heimes8640e742008-02-23 16:23:06 +0000566 try:
Victor Stinner45273652011-06-22 22:15:51 +0200567 # wait until the child process is loaded and has started
568 first_line = process.stdout.readline()
569
Victor Stinner19e5bcd2011-07-01 15:59:54 +0200570 stdout, stderr = process.communicate(timeout=5.0)
Victor Stinnerd6284962011-06-20 23:28:09 +0200571 except subprocess.TimeoutExpired:
572 process.kill()
Christian Heimes8640e742008-02-23 16:23:06 +0000573 return False
Victor Stinnerd6284962011-06-20 23:28:09 +0200574 else:
Victor Stinner45273652011-06-22 22:15:51 +0200575 stdout = first_line + stdout
Victor Stinnerd6284962011-06-20 23:28:09 +0200576 exitcode = process.wait()
577 if exitcode not in (2, 3):
Antoine Pitroudab4e8a2014-05-11 19:05:23 +0200578 raise Exception("Child error (exit code %s): %r"
Victor Stinnerd6284962011-06-20 23:28:09 +0200579 % (exitcode, stdout))
580 return (exitcode == 3)
Christian Heimes8640e742008-02-23 16:23:06 +0000581
582 def test_without_siginterrupt(self):
Victor Stinner3a7f0f02011-05-08 02:10:36 +0200583 # If a signal handler is installed and siginterrupt is not called
584 # at all, when that signal arrives, it interrupts a syscall that's in
585 # progress.
Victor Stinnerd6284962011-06-20 23:28:09 +0200586 interrupted = self.readpipe_interrupted(None)
587 self.assertTrue(interrupted)
Christian Heimes8640e742008-02-23 16:23:06 +0000588
589 def test_siginterrupt_on(self):
Victor Stinner3a7f0f02011-05-08 02:10:36 +0200590 # If a signal handler is installed and siginterrupt is called with
591 # a true value for the second argument, when that signal arrives, it
592 # interrupts a syscall that's in progress.
Victor Stinnerd6284962011-06-20 23:28:09 +0200593 interrupted = self.readpipe_interrupted(True)
594 self.assertTrue(interrupted)
Christian Heimes8640e742008-02-23 16:23:06 +0000595
596 def test_siginterrupt_off(self):
Victor Stinner3a7f0f02011-05-08 02:10:36 +0200597 # If a signal handler is installed and siginterrupt is called with
598 # a false value for the second argument, when that signal arrives, it
599 # does not interrupt a syscall that's in progress.
Victor Stinnerd6284962011-06-20 23:28:09 +0200600 interrupted = self.readpipe_interrupted(False)
601 self.assertFalse(interrupted)
Jean-Paul Calderone9c39bc72010-05-09 03:25:16 +0000602
603
Brian Curtin3f004b12010-08-06 19:34:52 +0000604@unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
Martin v. Löwis823725e2008-03-24 13:39:54 +0000605class ItimerTest(unittest.TestCase):
606 def setUp(self):
607 self.hndl_called = False
608 self.hndl_count = 0
609 self.itimer = None
Christian Heimescc47b052008-03-25 14:56:36 +0000610 self.old_alarm = signal.signal(signal.SIGALRM, self.sig_alrm)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000611
612 def tearDown(self):
Christian Heimescc47b052008-03-25 14:56:36 +0000613 signal.signal(signal.SIGALRM, self.old_alarm)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000614 if self.itimer is not None: # test_itimer_exc doesn't change this attr
615 # just ensure that itimer is stopped
616 signal.setitimer(self.itimer, 0)
617
618 def sig_alrm(self, *args):
619 self.hndl_called = True
Martin v. Löwis823725e2008-03-24 13:39:54 +0000620
621 def sig_vtalrm(self, *args):
622 self.hndl_called = True
623
624 if self.hndl_count > 3:
625 # it shouldn't be here, because it should have been disabled.
626 raise signal.ItimerError("setitimer didn't disable ITIMER_VIRTUAL "
627 "timer.")
628 elif self.hndl_count == 3:
629 # disable ITIMER_VIRTUAL, this function shouldn't be called anymore
630 signal.setitimer(signal.ITIMER_VIRTUAL, 0)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000631
632 self.hndl_count += 1
633
Martin v. Löwis823725e2008-03-24 13:39:54 +0000634 def sig_prof(self, *args):
635 self.hndl_called = True
636 signal.setitimer(signal.ITIMER_PROF, 0)
637
Martin v. Löwis823725e2008-03-24 13:39:54 +0000638 def test_itimer_exc(self):
639 # XXX I'm assuming -1 is an invalid itimer, but maybe some platform
640 # defines it ?
641 self.assertRaises(signal.ItimerError, signal.setitimer, -1, 0)
Christian Heimescc47b052008-03-25 14:56:36 +0000642 # Negative times are treated as zero on some platforms.
643 if 0:
644 self.assertRaises(signal.ItimerError,
645 signal.setitimer, signal.ITIMER_REAL, -1)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000646
647 def test_itimer_real(self):
648 self.itimer = signal.ITIMER_REAL
Martin v. Löwis823725e2008-03-24 13:39:54 +0000649 signal.setitimer(self.itimer, 1.0)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000650 signal.pause()
Martin v. Löwis823725e2008-03-24 13:39:54 +0000651 self.assertEqual(self.hndl_called, True)
652
R. David Murray44546f82010-04-21 01:59:28 +0000653 # Issue 3864, unknown if this affects earlier versions of freebsd also
Gregory P. Smith397cd8a2010-10-17 04:23:21 +0000654 @unittest.skipIf(sys.platform in ('freebsd6', 'netbsd5'),
655 'itimer not reliable (does not mix well with threading) on some BSDs.')
Martin v. Löwis823725e2008-03-24 13:39:54 +0000656 def test_itimer_virtual(self):
657 self.itimer = signal.ITIMER_VIRTUAL
658 signal.signal(signal.SIGVTALRM, self.sig_vtalrm)
659 signal.setitimer(self.itimer, 0.3, 0.2)
660
Victor Stinner79d68f92015-03-19 21:54:09 +0100661 start_time = time.monotonic()
662 while time.monotonic() - start_time < 60.0:
Mark Dickinson95078872009-10-04 18:47:48 +0000663 # use up some virtual time by doing real work
664 _ = pow(12345, 67890, 10000019)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000665 if signal.getitimer(self.itimer) == (0.0, 0.0):
666 break # sig_vtalrm handler stopped this itimer
Stefan Krahf1da973042010-04-20 08:15:14 +0000667 else: # Issue 8424
Benjamin Peterson9b140f62010-05-15 18:00:56 +0000668 self.skipTest("timeout: likely cause: machine too slow or load too "
669 "high")
Martin v. Löwis823725e2008-03-24 13:39:54 +0000670
671 # virtual itimer should be (0.0, 0.0) now
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000672 self.assertEqual(signal.getitimer(self.itimer), (0.0, 0.0))
Martin v. Löwis823725e2008-03-24 13:39:54 +0000673 # and the handler should have been called
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000674 self.assertEqual(self.hndl_called, True)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000675
R. David Murray44546f82010-04-21 01:59:28 +0000676 # Issue 3864, unknown if this affects earlier versions of freebsd also
677 @unittest.skipIf(sys.platform=='freebsd6',
678 'itimer not reliable (does not mix well with threading) on freebsd6')
Martin v. Löwis823725e2008-03-24 13:39:54 +0000679 def test_itimer_prof(self):
680 self.itimer = signal.ITIMER_PROF
681 signal.signal(signal.SIGPROF, self.sig_prof)
Neal Norwitzf5c7c2e2008-04-05 04:47:45 +0000682 signal.setitimer(self.itimer, 0.2, 0.2)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000683
Victor Stinner79d68f92015-03-19 21:54:09 +0100684 start_time = time.monotonic()
685 while time.monotonic() - start_time < 60.0:
Mark Dickinson78373472009-10-31 10:39:21 +0000686 # do some work
687 _ = pow(12345, 67890, 10000019)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000688 if signal.getitimer(self.itimer) == (0.0, 0.0):
689 break # sig_prof handler stopped this itimer
Stefan Krahf1da973042010-04-20 08:15:14 +0000690 else: # Issue 8424
Benjamin Peterson9b140f62010-05-15 18:00:56 +0000691 self.skipTest("timeout: likely cause: machine too slow or load too "
692 "high")
Martin v. Löwis823725e2008-03-24 13:39:54 +0000693
Neal Norwitzf5c7c2e2008-04-05 04:47:45 +0000694 # profiling itimer should be (0.0, 0.0) now
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000695 self.assertEqual(signal.getitimer(self.itimer), (0.0, 0.0))
Neal Norwitzf5c7c2e2008-04-05 04:47:45 +0000696 # and the handler should have been called
Martin v. Löwis823725e2008-03-24 13:39:54 +0000697 self.assertEqual(self.hndl_called, True)
698
Antoine Pitrou729780a2017-06-30 10:01:05 +0200699 def test_setitimer_tiny(self):
700 # bpo-30807: C setitimer() takes a microsecond-resolution interval.
701 # Check that float -> timeval conversion doesn't round
702 # the interval down to zero, which would disable the timer.
703 self.itimer = signal.ITIMER_REAL
704 signal.setitimer(self.itimer, 1e-6)
705 time.sleep(1)
706 self.assertEqual(self.hndl_called, True)
707
Victor Stinnera9293352011-04-30 15:21:58 +0200708
Victor Stinner35b300c2011-05-04 13:20:35 +0200709class PendingSignalsTests(unittest.TestCase):
710 """
Victor Stinnerb3e72192011-05-08 01:46:11 +0200711 Test pthread_sigmask(), pthread_kill(), sigpending() and sigwait()
712 functions.
Victor Stinner35b300c2011-05-04 13:20:35 +0200713 """
Victor Stinnerb3e72192011-05-08 01:46:11 +0200714 @unittest.skipUnless(hasattr(signal, 'sigpending'),
715 'need signal.sigpending()')
716 def test_sigpending_empty(self):
717 self.assertEqual(signal.sigpending(), set())
718
719 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
720 'need signal.pthread_sigmask()')
721 @unittest.skipUnless(hasattr(signal, 'sigpending'),
722 'need signal.sigpending()')
723 def test_sigpending(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200724 code = """if 1:
725 import os
726 import signal
Victor Stinnerb3e72192011-05-08 01:46:11 +0200727
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200728 def handler(signum, frame):
729 1/0
Victor Stinnerb3e72192011-05-08 01:46:11 +0200730
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200731 signum = signal.SIGUSR1
732 signal.signal(signum, handler)
733
734 signal.pthread_sigmask(signal.SIG_BLOCK, [signum])
735 os.kill(os.getpid(), signum)
736 pending = signal.sigpending()
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +0200737 for sig in pending:
738 assert isinstance(sig, signal.Signals), repr(pending)
Victor Stinner0a01f132011-07-04 18:06:35 +0200739 if pending != {signum}:
740 raise Exception('%s != {%s}' % (pending, signum))
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200741 try:
742 signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum])
743 except ZeroDivisionError:
744 pass
745 else:
746 raise Exception("ZeroDivisionError not raised")
747 """
748 assert_python_ok('-c', code)
Victor Stinnerb3e72192011-05-08 01:46:11 +0200749
750 @unittest.skipUnless(hasattr(signal, 'pthread_kill'),
751 'need signal.pthread_kill()')
752 def test_pthread_kill(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200753 code = """if 1:
754 import signal
755 import threading
756 import sys
Victor Stinnerb3e72192011-05-08 01:46:11 +0200757
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200758 signum = signal.SIGUSR1
Victor Stinnerb3e72192011-05-08 01:46:11 +0200759
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200760 def handler(signum, frame):
761 1/0
762
763 signal.signal(signum, handler)
764
765 if sys.platform == 'freebsd6':
766 # Issue #12392 and #12469: send a signal to the main thread
767 # doesn't work before the creation of the first thread on
768 # FreeBSD 6
769 def noop():
770 pass
771 thread = threading.Thread(target=noop)
772 thread.start()
773 thread.join()
774
775 tid = threading.get_ident()
776 try:
777 signal.pthread_kill(tid, signum)
778 except ZeroDivisionError:
779 pass
780 else:
781 raise Exception("ZeroDivisionError not raised")
782 """
783 assert_python_ok('-c', code)
Victor Stinnerb3e72192011-05-08 01:46:11 +0200784
Victor Stinner7f294d12011-06-10 14:02:10 +0200785 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
786 'need signal.pthread_sigmask()')
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200787 def wait_helper(self, blocked, test):
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200788 """
789 test: body of the "def test(signum):" function.
790 blocked: number of the blocked signal
791 """
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200792 code = '''if 1:
793 import signal
794 import sys
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +0200795 from signal import Signals
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200796
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200797 def handler(signum, frame):
798 1/0
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200799
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200800 %s
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200801
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200802 blocked = %s
803 signum = signal.SIGALRM
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200804
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200805 # child: block and wait the signal
806 try:
807 signal.signal(signum, handler)
808 signal.pthread_sigmask(signal.SIG_BLOCK, [blocked])
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200809
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200810 # Do the tests
811 test(signum)
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200812
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200813 # The handler must not be called on unblock
814 try:
815 signal.pthread_sigmask(signal.SIG_UNBLOCK, [blocked])
816 except ZeroDivisionError:
817 print("the signal handler has been called",
818 file=sys.stderr)
819 sys.exit(1)
820 except BaseException as err:
821 print("error: {}".format(err), file=sys.stderr)
822 sys.stderr.flush()
823 sys.exit(1)
824 ''' % (test.strip(), blocked)
Victor Stinner415007e2011-06-13 16:19:06 +0200825
Ross Lagerwallbc808222011-06-25 12:13:40 +0200826 # sig*wait* must be called with the signal blocked: since the current
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200827 # process might have several threads running, use a subprocess to have
828 # a single thread.
829 assert_python_ok('-c', code)
Victor Stinneraf494602011-06-10 12:48:13 +0200830
Victor Stinnerb3e72192011-05-08 01:46:11 +0200831 @unittest.skipUnless(hasattr(signal, 'sigwait'),
832 'need signal.sigwait()')
Ross Lagerwallbc808222011-06-25 12:13:40 +0200833 def test_sigwait(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200834 self.wait_helper(signal.SIGALRM, '''
835 def test(signum):
Ross Lagerwallbc808222011-06-25 12:13:40 +0200836 signal.alarm(1)
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200837 received = signal.sigwait([signum])
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +0200838 assert isinstance(received, signal.Signals), received
Victor Stinner0a01f132011-07-04 18:06:35 +0200839 if received != signum:
840 raise Exception('received %s, not %s' % (received, signum))
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200841 ''')
Ross Lagerwallbc808222011-06-25 12:13:40 +0200842
843 @unittest.skipUnless(hasattr(signal, 'sigwaitinfo'),
844 'need signal.sigwaitinfo()')
845 def test_sigwaitinfo(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200846 self.wait_helper(signal.SIGALRM, '''
847 def test(signum):
Ross Lagerwallbc808222011-06-25 12:13:40 +0200848 signal.alarm(1)
849 info = signal.sigwaitinfo([signum])
Victor Stinner0a01f132011-07-04 18:06:35 +0200850 if info.si_signo != signum:
851 raise Exception("info.si_signo != %s" % signum)
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200852 ''')
Ross Lagerwallbc808222011-06-25 12:13:40 +0200853
854 @unittest.skipUnless(hasattr(signal, 'sigtimedwait'),
855 'need signal.sigtimedwait()')
856 def test_sigtimedwait(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200857 self.wait_helper(signal.SIGALRM, '''
858 def test(signum):
Ross Lagerwallbc808222011-06-25 12:13:40 +0200859 signal.alarm(1)
Victor Stinner643cd682012-03-02 22:54:03 +0100860 info = signal.sigtimedwait([signum], 10.1000)
Victor Stinner0a01f132011-07-04 18:06:35 +0200861 if info.si_signo != signum:
862 raise Exception('info.si_signo != %s' % signum)
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200863 ''')
Ross Lagerwallbc808222011-06-25 12:13:40 +0200864
Ross Lagerwallbc808222011-06-25 12:13:40 +0200865 @unittest.skipUnless(hasattr(signal, 'sigtimedwait'),
866 'need signal.sigtimedwait()')
867 def test_sigtimedwait_poll(self):
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200868 # check that polling with sigtimedwait works
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200869 self.wait_helper(signal.SIGALRM, '''
870 def test(signum):
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200871 import os
872 os.kill(os.getpid(), signum)
Victor Stinner643cd682012-03-02 22:54:03 +0100873 info = signal.sigtimedwait([signum], 0)
Victor Stinner0a01f132011-07-04 18:06:35 +0200874 if info.si_signo != signum:
875 raise Exception('info.si_signo != %s' % signum)
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200876 ''')
Ross Lagerwallbc808222011-06-25 12:13:40 +0200877
878 @unittest.skipUnless(hasattr(signal, 'sigtimedwait'),
879 'need signal.sigtimedwait()')
880 def test_sigtimedwait_timeout(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200881 self.wait_helper(signal.SIGALRM, '''
882 def test(signum):
Victor Stinner643cd682012-03-02 22:54:03 +0100883 received = signal.sigtimedwait([signum], 1.0)
Victor Stinner0a01f132011-07-04 18:06:35 +0200884 if received is not None:
885 raise Exception("received=%r" % (received,))
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200886 ''')
Ross Lagerwallbc808222011-06-25 12:13:40 +0200887
888 @unittest.skipUnless(hasattr(signal, 'sigtimedwait'),
889 'need signal.sigtimedwait()')
890 def test_sigtimedwait_negative_timeout(self):
891 signum = signal.SIGALRM
Victor Stinner643cd682012-03-02 22:54:03 +0100892 self.assertRaises(ValueError, signal.sigtimedwait, [signum], -1.0)
Ross Lagerwallbc808222011-06-25 12:13:40 +0200893
Ross Lagerwallbc808222011-06-25 12:13:40 +0200894 @unittest.skipUnless(hasattr(signal, 'sigwait'),
895 'need signal.sigwait()')
Victor Stinner415007e2011-06-13 16:19:06 +0200896 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
897 'need signal.pthread_sigmask()')
Victor Stinner10c30d62011-06-10 01:39:53 +0200898 def test_sigwait_thread(self):
Victor Stinner415007e2011-06-13 16:19:06 +0200899 # Check that calling sigwait() from a thread doesn't suspend the whole
900 # process. A new interpreter is spawned to avoid problems when mixing
901 # threads and fork(): only async-safe functions are allowed between
902 # fork() and exec().
903 assert_python_ok("-c", """if True:
904 import os, threading, sys, time, signal
Victor Stinner10c30d62011-06-10 01:39:53 +0200905
Victor Stinner415007e2011-06-13 16:19:06 +0200906 # the default handler terminates the process
907 signum = signal.SIGUSR1
908
909 def kill_later():
910 # wait until the main thread is waiting in sigwait()
911 time.sleep(1)
912 os.kill(os.getpid(), signum)
913
914 # the signal must be blocked by all the threads
915 signal.pthread_sigmask(signal.SIG_BLOCK, [signum])
916 killer = threading.Thread(target=kill_later)
Victor Stinneraf494602011-06-10 12:48:13 +0200917 killer.start()
918 received = signal.sigwait([signum])
919 if received != signum:
920 print("sigwait() received %s, not %s" % (received, signum),
921 file=sys.stderr)
Victor Stinner415007e2011-06-13 16:19:06 +0200922 sys.exit(1)
Victor Stinner10c30d62011-06-10 01:39:53 +0200923 killer.join()
Victor Stinner415007e2011-06-13 16:19:06 +0200924 # unblock the signal, which should have been cleared by sigwait()
925 signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum])
926 """)
Victor Stinneraf494602011-06-10 12:48:13 +0200927
Victor Stinnerb3e72192011-05-08 01:46:11 +0200928 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
929 'need signal.pthread_sigmask()')
930 def test_pthread_sigmask_arguments(self):
931 self.assertRaises(TypeError, signal.pthread_sigmask)
932 self.assertRaises(TypeError, signal.pthread_sigmask, 1)
933 self.assertRaises(TypeError, signal.pthread_sigmask, 1, 2, 3)
934 self.assertRaises(OSError, signal.pthread_sigmask, 1700, [])
935
936 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
937 'need signal.pthread_sigmask()')
938 def test_pthread_sigmask(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200939 code = """if 1:
940 import signal
941 import os; import threading
942
943 def handler(signum, frame):
944 1/0
945
946 def kill(signum):
947 os.kill(os.getpid(), signum)
948
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +0200949 def check_mask(mask):
950 for sig in mask:
951 assert isinstance(sig, signal.Signals), repr(sig)
952
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200953 def read_sigmask():
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +0200954 sigmask = signal.pthread_sigmask(signal.SIG_BLOCK, [])
955 check_mask(sigmask)
956 return sigmask
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200957
Victor Stinnerb3e72192011-05-08 01:46:11 +0200958 signum = signal.SIGUSR1
Victor Stinner6fd49e12011-05-04 12:38:03 +0200959
Victor Stinnerd0e516d2011-05-03 14:57:12 +0200960 # Install our signal handler
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200961 old_handler = signal.signal(signum, handler)
Victor Stinnera9293352011-04-30 15:21:58 +0200962
Victor Stinnerd0e516d2011-05-03 14:57:12 +0200963 # Unblock SIGUSR1 (and copy the old mask) to test our signal handler
Victor Stinnera9293352011-04-30 15:21:58 +0200964 old_mask = signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum])
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +0200965 check_mask(old_mask)
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200966 try:
967 kill(signum)
968 except ZeroDivisionError:
969 pass
970 else:
971 raise Exception("ZeroDivisionError not raised")
Victor Stinnera9293352011-04-30 15:21:58 +0200972
Victor Stinnerd0e516d2011-05-03 14:57:12 +0200973 # Block and then raise SIGUSR1. The signal is blocked: the signal
974 # handler is not called, and the signal is now pending
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +0200975 mask = signal.pthread_sigmask(signal.SIG_BLOCK, [signum])
976 check_mask(mask)
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200977 kill(signum)
Victor Stinnera9293352011-04-30 15:21:58 +0200978
Victor Stinnerd0e516d2011-05-03 14:57:12 +0200979 # Check the new mask
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200980 blocked = read_sigmask()
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +0200981 check_mask(blocked)
Victor Stinner0a01f132011-07-04 18:06:35 +0200982 if signum not in blocked:
983 raise Exception("%s not in %s" % (signum, blocked))
984 if old_mask ^ blocked != {signum}:
985 raise Exception("%s ^ %s != {%s}" % (old_mask, blocked, signum))
Victor Stinnera9293352011-04-30 15:21:58 +0200986
Victor Stinnerd0e516d2011-05-03 14:57:12 +0200987 # Unblock SIGUSR1
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200988 try:
R David Murrayfc069992013-12-13 20:52:19 -0500989 # unblock the pending signal calls immediately the signal handler
Victor Stinnerd0e516d2011-05-03 14:57:12 +0200990 signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum])
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200991 except ZeroDivisionError:
992 pass
993 else:
994 raise Exception("ZeroDivisionError not raised")
995 try:
996 kill(signum)
997 except ZeroDivisionError:
998 pass
999 else:
1000 raise Exception("ZeroDivisionError not raised")
Victor Stinnera9293352011-04-30 15:21:58 +02001001
Victor Stinnerd0e516d2011-05-03 14:57:12 +02001002 # Check the new mask
Victor Stinnerd554cdf2011-07-04 17:49:40 +02001003 unblocked = read_sigmask()
Victor Stinner0a01f132011-07-04 18:06:35 +02001004 if signum in unblocked:
1005 raise Exception("%s in %s" % (signum, unblocked))
1006 if blocked ^ unblocked != {signum}:
1007 raise Exception("%s ^ %s != {%s}" % (blocked, unblocked, signum))
1008 if old_mask != unblocked:
1009 raise Exception("%s != %s" % (old_mask, unblocked))
Victor Stinnerd554cdf2011-07-04 17:49:40 +02001010 """
1011 assert_python_ok('-c', code)
1012
1013 @unittest.skipIf(sys.platform == 'freebsd6',
1014 "issue #12392: send a signal to the main thread doesn't work "
1015 "before the creation of the first thread on FreeBSD 6")
1016 @unittest.skipUnless(hasattr(signal, 'pthread_kill'),
1017 'need signal.pthread_kill()')
1018 def test_pthread_kill_main_thread(self):
1019 # Test that a signal can be sent to the main thread with pthread_kill()
1020 # before any other thread has been created (see issue #12392).
1021 code = """if True:
1022 import threading
1023 import signal
1024 import sys
1025
1026 def handler(signum, frame):
1027 sys.exit(3)
1028
1029 signal.signal(signal.SIGUSR1, handler)
1030 signal.pthread_kill(threading.get_ident(), signal.SIGUSR1)
1031 sys.exit(2)
1032 """
1033
1034 with spawn_python('-c', code) as process:
1035 stdout, stderr = process.communicate()
1036 exitcode = process.wait()
1037 if exitcode != 3:
1038 raise Exception("Child error (exit code %s): %s" %
1039 (exitcode, stdout))
Victor Stinnera9293352011-04-30 15:21:58 +02001040
1041
Antoine Pitrouc08177a2017-06-28 23:29:29 +02001042class StressTest(unittest.TestCase):
1043 """
1044 Stress signal delivery, especially when a signal arrives in
1045 the middle of recomputing the signal state or executing
1046 previously tripped signal handlers.
1047 """
1048
Antoine Pitrouf7d090c2017-06-29 16:40:14 +02001049 def setsig(self, signum, handler):
1050 old_handler = signal.signal(signum, handler)
1051 self.addCleanup(signal.signal, signum, old_handler)
1052
1053 def measure_itimer_resolution(self):
1054 N = 20
1055 times = []
1056
1057 def handler(signum=None, frame=None):
1058 if len(times) < N:
1059 times.append(time.perf_counter())
1060 # 1 µs is the smallest possible timer interval,
1061 # we want to measure what the concrete duration
1062 # will be on this platform
1063 signal.setitimer(signal.ITIMER_REAL, 1e-6)
1064
1065 self.addCleanup(signal.setitimer, signal.ITIMER_REAL, 0)
1066 self.setsig(signal.SIGALRM, handler)
1067 handler()
1068 while len(times) < N:
1069 time.sleep(1e-3)
1070
1071 durations = [times[i+1] - times[i] for i in range(len(times) - 1)]
1072 med = statistics.median(durations)
1073 if support.verbose:
1074 print("detected median itimer() resolution: %.6f s." % (med,))
1075 return med
1076
1077 def decide_itimer_count(self):
1078 # Some systems have poor setitimer() resolution (for example
1079 # measured around 20 ms. on FreeBSD 9), so decide on a reasonable
1080 # number of sequential timers based on that.
1081 reso = self.measure_itimer_resolution()
1082 if reso <= 1e-4:
1083 return 10000
1084 elif reso <= 1e-2:
1085 return 100
1086 else:
1087 self.skipTest("detected itimer resolution (%.3f s.) too high "
1088 "(> 10 ms.) on this platform (or system too busy)"
1089 % (reso,))
1090
Antoine Pitrouc08177a2017-06-28 23:29:29 +02001091 @unittest.skipUnless(hasattr(signal, "setitimer"),
1092 "test needs setitimer()")
1093 def test_stress_delivery_dependent(self):
1094 """
1095 This test uses dependent signal handlers.
1096 """
Antoine Pitrouf7d090c2017-06-29 16:40:14 +02001097 N = self.decide_itimer_count()
Antoine Pitrouc08177a2017-06-28 23:29:29 +02001098 sigs = []
1099
1100 def first_handler(signum, frame):
1101 # 1e-6 is the minimum non-zero value for `setitimer()`.
1102 # Choose a random delay so as to improve chances of
1103 # triggering a race condition. Ideally the signal is received
1104 # when inside critical signal-handling routines such as
1105 # Py_MakePendingCalls().
1106 signal.setitimer(signal.ITIMER_REAL, 1e-6 + random.random() * 1e-5)
1107
1108 def second_handler(signum=None, frame=None):
1109 sigs.append(signum)
1110
Antoine Pitrouc08177a2017-06-28 23:29:29 +02001111 # Here on Linux, SIGPROF > SIGALRM > SIGUSR1. By using both
1112 # ascending and descending sequences (SIGUSR1 then SIGALRM,
1113 # SIGPROF then SIGALRM), we maximize chances of hitting a bug.
Antoine Pitrouf7d090c2017-06-29 16:40:14 +02001114 self.setsig(signal.SIGPROF, first_handler)
1115 self.setsig(signal.SIGUSR1, first_handler)
1116 self.setsig(signal.SIGALRM, second_handler) # for ITIMER_REAL
Antoine Pitrouc08177a2017-06-28 23:29:29 +02001117
1118 expected_sigs = 0
1119 deadline = time.time() + 15.0
1120
1121 while expected_sigs < N:
1122 os.kill(os.getpid(), signal.SIGPROF)
1123 expected_sigs += 1
1124 # Wait for handlers to run to avoid signal coalescing
1125 while len(sigs) < expected_sigs and time.time() < deadline:
1126 time.sleep(1e-5)
1127
1128 os.kill(os.getpid(), signal.SIGUSR1)
1129 expected_sigs += 1
1130 while len(sigs) < expected_sigs and time.time() < deadline:
1131 time.sleep(1e-5)
1132
1133 # All ITIMER_REAL signals should have been delivered to the
1134 # Python handler
1135 self.assertEqual(len(sigs), N, "Some signals were lost")
1136
1137 @unittest.skipUnless(hasattr(signal, "setitimer"),
1138 "test needs setitimer()")
1139 def test_stress_delivery_simultaneous(self):
1140 """
1141 This test uses simultaneous signal handlers.
1142 """
Antoine Pitrouf7d090c2017-06-29 16:40:14 +02001143 N = self.decide_itimer_count()
Antoine Pitrouc08177a2017-06-28 23:29:29 +02001144 sigs = []
1145
1146 def handler(signum, frame):
1147 sigs.append(signum)
1148
Antoine Pitrouf7d090c2017-06-29 16:40:14 +02001149 self.setsig(signal.SIGUSR1, handler)
1150 self.setsig(signal.SIGALRM, handler) # for ITIMER_REAL
Antoine Pitrouc08177a2017-06-28 23:29:29 +02001151
1152 expected_sigs = 0
1153 deadline = time.time() + 15.0
1154
1155 while expected_sigs < N:
1156 # Hopefully the SIGALRM will be received somewhere during
1157 # initial processing of SIGUSR1.
1158 signal.setitimer(signal.ITIMER_REAL, 1e-6 + random.random() * 1e-5)
1159 os.kill(os.getpid(), signal.SIGUSR1)
1160
1161 expected_sigs += 2
1162 # Wait for handlers to run to avoid signal coalescing
1163 while len(sigs) < expected_sigs and time.time() < deadline:
1164 time.sleep(1e-5)
1165
1166 # All ITIMER_REAL signals should have been delivered to the
1167 # Python handler
1168 self.assertEqual(len(sigs), N, "Some signals were lost")
1169
1170
Zachary Ware38c707e2015-04-13 15:00:43 -05001171def tearDownModule():
1172 support.reap_children()
Thomas Woutersed03b412007-08-28 21:37:11 +00001173
1174if __name__ == "__main__":
Zachary Ware38c707e2015-04-13 15:00:43 -05001175 unittest.main()