blob: f973d4fe08be319e36c874512cad16c8c3cae082 [file] [log] [blame]
Vladimir Matveevc24c6c22019-01-08 01:58:25 -08001import errno
Victor Stinnerd6debb22017-03-27 16:05:26 +02002import os
Antoine Pitrouc08177a2017-06-28 23:29:29 +02003import random
Guido van Rossum4f17e3e1995-03-16 15:07:38 +00004import signal
Victor Stinner11517102014-07-29 23:31:34 +02005import socket
Antoine Pitrouf7d090c2017-06-29 16:40:14 +02006import statistics
Christian Heimes4fbc72b2008-03-22 00:47:35 +00007import subprocess
Victor Stinnerd6debb22017-03-27 16:05:26 +02008import sys
Antoine Pitrou68245b72021-03-05 10:32:50 +01009import threading
Victor Stinnerd6debb22017-03-27 16:05:26 +020010import time
11import unittest
12from test import support
Hai Shia7f5d932020-08-04 00:41:24 +080013from test.support import os_helper
Berker Peksagce643912015-05-06 06:33:17 +030014from test.support.script_helper import assert_python_ok, spawn_python
Victor Stinnerb3e72192011-05-08 01:46:11 +020015try:
Victor Stinner56e8c292014-07-21 12:30:22 +020016 import _testcapi
17except ImportError:
18 _testcapi = None
Christian Heimesc06950e2008-02-28 21:17:00 +000019
Guido van Rossumcc5a91d1997-04-16 00:29:15 +000020
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +020021class GenericTests(unittest.TestCase):
22
23 def test_enums(self):
24 for name in dir(signal):
25 sig = getattr(signal, name)
26 if name in {'SIG_DFL', 'SIG_IGN'}:
27 self.assertIsInstance(sig, signal.Handlers)
28 elif name in {'SIG_BLOCK', 'SIG_UNBLOCK', 'SIG_SETMASK'}:
29 self.assertIsInstance(sig, signal.Sigmasks)
30 elif name.startswith('SIG') and not name.startswith('SIG_'):
31 self.assertIsInstance(sig, signal.Signals)
32 elif name.startswith('CTRL_'):
33 self.assertIsInstance(sig, signal.Signals)
34 self.assertEqual(sys.platform, "win32")
35
36
Brian Curtin3f004b12010-08-06 19:34:52 +000037@unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
Victor Stinnerb3e72192011-05-08 01:46:11 +020038class PosixTests(unittest.TestCase):
Christian Heimes4fbc72b2008-03-22 00:47:35 +000039 def trivial_signal_handler(self, *args):
40 pass
41
Thomas Woutersed03b412007-08-28 21:37:11 +000042 def test_out_of_range_signal_number_raises_error(self):
43 self.assertRaises(ValueError, signal.getsignal, 4242)
44
Thomas Woutersed03b412007-08-28 21:37:11 +000045 self.assertRaises(ValueError, signal.signal, 4242,
Christian Heimes4fbc72b2008-03-22 00:47:35 +000046 self.trivial_signal_handler)
Thomas Woutersed03b412007-08-28 21:37:11 +000047
Antoine Pietri5d2a27d2018-03-12 14:42:34 +010048 self.assertRaises(ValueError, signal.strsignal, 4242)
49
Thomas Woutersed03b412007-08-28 21:37:11 +000050 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
Antoine Pietri5d2a27d2018-03-12 14:42:34 +010062 def test_strsignal(self):
Antoine Pietri019f5b32018-03-12 20:03:14 +010063 self.assertIn("Interrupt", signal.strsignal(signal.SIGINT))
64 self.assertIn("Terminated", signal.strsignal(signal.SIGTERM))
Michael Osipov48ce4892018-08-23 15:27:19 +020065 self.assertIn("Hangup", signal.strsignal(signal.SIGHUP))
Antoine Pietri5d2a27d2018-03-12 14:42:34 +010066
Victor Stinner32eb8402016-03-15 11:12:35 +010067 # Issue 3864, unknown if this affects earlier versions of freebsd also
Victor Stinner32eb8402016-03-15 11:12:35 +010068 def test_interprocess_signal(self):
69 dirname = os.path.dirname(__file__)
70 script = os.path.join(dirname, 'signalinterproctester.py')
71 assert_python_ok(script)
72
Antoine Pitrou9d3627e2018-05-04 13:00:50 +020073 def test_valid_signals(self):
74 s = signal.valid_signals()
75 self.assertIsInstance(s, set)
76 self.assertIn(signal.Signals.SIGINT, s)
77 self.assertIn(signal.Signals.SIGALRM, s)
78 self.assertNotIn(0, s)
79 self.assertNotIn(signal.NSIG, s)
80 self.assertLess(len(s), signal.NSIG)
81
Gregory P. Smith38f11cc2019-02-16 12:57:40 -080082 @unittest.skipUnless(sys.executable, "sys.executable required.")
83 def test_keyboard_interrupt_exit_code(self):
84 """KeyboardInterrupt triggers exit via SIGINT."""
85 process = subprocess.run(
86 [sys.executable, "-c",
Gregory P. Smith414c6252019-02-16 17:22:39 -080087 "import os, signal, time\n"
88 "os.kill(os.getpid(), signal.SIGINT)\n"
89 "for _ in range(999): time.sleep(0.01)"],
Gregory P. Smith38f11cc2019-02-16 12:57:40 -080090 stderr=subprocess.PIPE)
91 self.assertIn(b"KeyboardInterrupt", process.stderr)
92 self.assertEqual(process.returncode, -signal.SIGINT)
Gregory P. Smith414c6252019-02-16 17:22:39 -080093 # Caveat: The exit code is insufficient to guarantee we actually died
94 # via a signal. POSIX shells do more than look at the 8 bit value.
95 # Writing an automation friendly test of an interactive shell
96 # to confirm that our process died via a SIGINT proved too complex.
Gregory P. Smith38f11cc2019-02-16 12:57:40 -080097
Christian Heimes4fbc72b2008-03-22 00:47:35 +000098
Brian Curtin3f004b12010-08-06 19:34:52 +000099@unittest.skipUnless(sys.platform == "win32", "Windows specific")
100class WindowsSignalTests(unittest.TestCase):
Antoine Pitrou9d3627e2018-05-04 13:00:50 +0200101
102 def test_valid_signals(self):
103 s = signal.valid_signals()
104 self.assertIsInstance(s, set)
105 self.assertGreaterEqual(len(s), 6)
106 self.assertIn(signal.Signals.SIGINT, s)
107 self.assertNotIn(0, s)
108 self.assertNotIn(signal.NSIG, s)
109 self.assertLess(len(s), signal.NSIG)
110
Brian Curtin3f004b12010-08-06 19:34:52 +0000111 def test_issue9324(self):
Brian Curtineccd4d92010-10-01 15:09:53 +0000112 # Updated for issue #10003, adding SIGBREAK
Brian Curtin3f004b12010-08-06 19:34:52 +0000113 handler = lambda x, y: None
Nick Coghlan60b3ac72013-08-03 22:56:30 +1000114 checked = set()
Brian Curtineccd4d92010-10-01 15:09:53 +0000115 for sig in (signal.SIGABRT, signal.SIGBREAK, signal.SIGFPE,
116 signal.SIGILL, signal.SIGINT, signal.SIGSEGV,
117 signal.SIGTERM):
Nick Coghlan60b3ac72013-08-03 22:56:30 +1000118 # Set and then reset a handler for signals that work on windows.
119 # Issue #18396, only for signals without a C-level handler.
120 if signal.getsignal(sig) is not None:
121 signal.signal(sig, signal.signal(sig, handler))
122 checked.add(sig)
123 # Issue #18396: Ensure the above loop at least tested *something*
124 self.assertTrue(checked)
Brian Curtin3f004b12010-08-06 19:34:52 +0000125
126 with self.assertRaises(ValueError):
127 signal.signal(-1, handler)
Brian Curtin80cd4bf2010-08-07 03:52:38 +0000128
129 with self.assertRaises(ValueError):
130 signal.signal(7, handler)
Brian Curtin3f004b12010-08-06 19:34:52 +0000131
Gregory P. Smith38f11cc2019-02-16 12:57:40 -0800132 @unittest.skipUnless(sys.executable, "sys.executable required.")
133 def test_keyboard_interrupt_exit_code(self):
134 """KeyboardInterrupt triggers an exit using STATUS_CONTROL_C_EXIT."""
135 # We don't test via os.kill(os.getpid(), signal.CTRL_C_EVENT) here
136 # as that requires setting up a console control handler in a child
137 # in its own process group. Doable, but quite complicated. (see
138 # @eryksun on https://github.com/python/cpython/pull/11862)
139 process = subprocess.run(
140 [sys.executable, "-c", "raise KeyboardInterrupt"],
141 stderr=subprocess.PIPE)
142 self.assertIn(b"KeyboardInterrupt", process.stderr)
143 STATUS_CONTROL_C_EXIT = 0xC000013A
144 self.assertEqual(process.returncode, STATUS_CONTROL_C_EXIT)
145
Brian Curtin3f004b12010-08-06 19:34:52 +0000146
Benjamin Petersonc68a4a02013-01-18 00:10:24 -0500147class WakeupFDTests(unittest.TestCase):
148
Nathaniel J. Smith902ab802017-12-17 20:10:18 -0800149 def test_invalid_call(self):
150 # First parameter is positional-only
151 with self.assertRaises(TypeError):
152 signal.set_wakeup_fd(signum=signal.SIGINT)
153
154 # warn_on_full_buffer is a keyword-only parameter
155 with self.assertRaises(TypeError):
156 signal.set_wakeup_fd(signal.SIGINT, False)
157
Benjamin Petersonc68a4a02013-01-18 00:10:24 -0500158 def test_invalid_fd(self):
Hai Shia7f5d932020-08-04 00:41:24 +0800159 fd = os_helper.make_bad_fd()
Victor Stinnera7d03d92014-07-21 17:17:28 +0200160 self.assertRaises((ValueError, OSError),
161 signal.set_wakeup_fd, fd)
Benjamin Petersonc68a4a02013-01-18 00:10:24 -0500162
Victor Stinner11517102014-07-29 23:31:34 +0200163 def test_invalid_socket(self):
164 sock = socket.socket()
165 fd = sock.fileno()
166 sock.close()
167 self.assertRaises((ValueError, OSError),
168 signal.set_wakeup_fd, fd)
169
Victor Stinnerd18ccd12014-07-24 21:58:53 +0200170 def test_set_wakeup_fd_result(self):
Victor Stinner1d8948e2014-07-24 22:51:05 +0200171 r1, w1 = os.pipe()
172 self.addCleanup(os.close, r1)
173 self.addCleanup(os.close, w1)
174 r2, w2 = os.pipe()
175 self.addCleanup(os.close, r2)
176 self.addCleanup(os.close, w2)
Victor Stinnerd18ccd12014-07-24 21:58:53 +0200177
Victor Stinner7cea44d2014-08-27 14:02:36 +0200178 if hasattr(os, 'set_blocking'):
179 os.set_blocking(w1, False)
180 os.set_blocking(w2, False)
Victor Stinner38227602014-08-27 12:59:44 +0200181
Victor Stinner1d8948e2014-07-24 22:51:05 +0200182 signal.set_wakeup_fd(w1)
Victor Stinnerc82a1792014-07-24 22:55:12 +0200183 self.assertEqual(signal.set_wakeup_fd(w2), w1)
184 self.assertEqual(signal.set_wakeup_fd(-1), w2)
185 self.assertEqual(signal.set_wakeup_fd(-1), -1)
Victor Stinner56e8c292014-07-21 12:30:22 +0200186
Victor Stinner11517102014-07-29 23:31:34 +0200187 def test_set_wakeup_fd_socket_result(self):
188 sock1 = socket.socket()
189 self.addCleanup(sock1.close)
Victor Stinner38227602014-08-27 12:59:44 +0200190 sock1.setblocking(False)
Victor Stinner11517102014-07-29 23:31:34 +0200191 fd1 = sock1.fileno()
192
193 sock2 = socket.socket()
194 self.addCleanup(sock2.close)
Victor Stinner38227602014-08-27 12:59:44 +0200195 sock2.setblocking(False)
Victor Stinner11517102014-07-29 23:31:34 +0200196 fd2 = sock2.fileno()
197
198 signal.set_wakeup_fd(fd1)
Victor Stinnerda565a72014-07-30 10:03:03 +0200199 self.assertEqual(signal.set_wakeup_fd(fd2), fd1)
200 self.assertEqual(signal.set_wakeup_fd(-1), fd2)
201 self.assertEqual(signal.set_wakeup_fd(-1), -1)
Victor Stinner11517102014-07-29 23:31:34 +0200202
Victor Stinner38227602014-08-27 12:59:44 +0200203 # On Windows, files are always blocking and Windows does not provide a
204 # function to test if a socket is in non-blocking mode.
205 @unittest.skipIf(sys.platform == "win32", "tests specific to POSIX")
206 def test_set_wakeup_fd_blocking(self):
207 rfd, wfd = os.pipe()
208 self.addCleanup(os.close, rfd)
209 self.addCleanup(os.close, wfd)
210
211 # fd must be non-blocking
212 os.set_blocking(wfd, True)
213 with self.assertRaises(ValueError) as cm:
214 signal.set_wakeup_fd(wfd)
215 self.assertEqual(str(cm.exception),
216 "the fd %s must be in non-blocking mode" % wfd)
217
218 # non-blocking is ok
219 os.set_blocking(wfd, False)
220 signal.set_wakeup_fd(wfd)
221 signal.set_wakeup_fd(-1)
222
Benjamin Petersonc68a4a02013-01-18 00:10:24 -0500223
Brian Curtin3f004b12010-08-06 19:34:52 +0000224@unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000225class WakeupSignalTests(unittest.TestCase):
Victor Stinner56e8c292014-07-21 12:30:22 +0200226 @unittest.skipIf(_testcapi is None, 'need _testcapi')
Charles-François Natali027f9a32011-10-02 18:36:05 +0200227 def check_wakeup(self, test_body, *signals, ordered=True):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200228 # use a subprocess to have only one thread
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200229 code = """if 1:
Victor Stinner56e8c292014-07-21 12:30:22 +0200230 import _testcapi
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200231 import os
232 import signal
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200233 import struct
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000234
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200235 signals = {!r}
Victor Stinnerc13ef662011-05-25 02:35:58 +0200236
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200237 def handler(signum, frame):
238 pass
239
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200240 def check_signum(signals):
241 data = os.read(read, len(signals)+1)
242 raised = struct.unpack('%uB' % len(data), data)
Charles-François Natali027f9a32011-10-02 18:36:05 +0200243 if not {!r}:
244 raised = set(raised)
245 signals = set(signals)
Victor Stinner0a01f132011-07-04 18:06:35 +0200246 if raised != signals:
247 raise Exception("%r != %r" % (raised, signals))
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200248
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200249 {}
250
251 signal.signal(signal.SIGALRM, handler)
252 read, write = os.pipe()
Victor Stinner1db9e7b2014-07-29 22:32:47 +0200253 os.set_blocking(write, False)
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200254 signal.set_wakeup_fd(write)
255
256 test()
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200257 check_signum(signals)
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200258
259 os.close(read)
260 os.close(write)
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +0200261 """.format(tuple(map(int, signals)), ordered, test_body)
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200262
263 assert_python_ok('-c', code)
Victor Stinnerd49b1f12011-05-08 02:03:15 +0200264
Victor Stinner56e8c292014-07-21 12:30:22 +0200265 @unittest.skipIf(_testcapi is None, 'need _testcapi')
Antoine Pitrou6f6ec372013-08-17 20:27:56 +0200266 def test_wakeup_write_error(self):
267 # Issue #16105: write() errors in the C signal handler should not
268 # pass silently.
269 # Use a subprocess to have only one thread.
270 code = """if 1:
Victor Stinner56e8c292014-07-21 12:30:22 +0200271 import _testcapi
Antoine Pitrou6f6ec372013-08-17 20:27:56 +0200272 import errno
Antoine Pitrou6f6ec372013-08-17 20:27:56 +0200273 import os
274 import signal
275 import sys
Antoine Pitrou6f6ec372013-08-17 20:27:56 +0200276 from test.support import captured_stderr
277
278 def handler(signum, frame):
279 1/0
280
281 signal.signal(signal.SIGALRM, handler)
282 r, w = os.pipe()
Victor Stinner1db9e7b2014-07-29 22:32:47 +0200283 os.set_blocking(r, False)
Antoine Pitrou6f6ec372013-08-17 20:27:56 +0200284
285 # Set wakeup_fd a read-only file descriptor to trigger the error
286 signal.set_wakeup_fd(r)
287 try:
288 with captured_stderr() as err:
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800289 signal.raise_signal(signal.SIGALRM)
Antoine Pitrou6f6ec372013-08-17 20:27:56 +0200290 except ZeroDivisionError:
291 # An ignored exception should have been printed out on stderr
292 err = err.getvalue()
293 if ('Exception ignored when trying to write to the signal wakeup fd'
294 not in err):
295 raise AssertionError(err)
296 if ('OSError: [Errno %d]' % errno.EBADF) not in err:
297 raise AssertionError(err)
298 else:
299 raise AssertionError("ZeroDivisionError not raised")
Victor Stinner56e8c292014-07-21 12:30:22 +0200300
301 os.close(r)
302 os.close(w)
Antoine Pitrou6f6ec372013-08-17 20:27:56 +0200303 """
Antoine Pitrou8f0bdda2013-08-17 21:43:47 +0200304 r, w = os.pipe()
305 try:
306 os.write(r, b'x')
307 except OSError:
308 pass
309 else:
310 self.skipTest("OS doesn't report write() error on the read end of a pipe")
311 finally:
312 os.close(r)
313 os.close(w)
Antoine Pitrou6f6ec372013-08-17 20:27:56 +0200314
315 assert_python_ok('-c', code)
316
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000317 def test_wakeup_fd_early(self):
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200318 self.check_wakeup("""def test():
319 import select
320 import time
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000321
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200322 TIMEOUT_FULL = 10
323 TIMEOUT_HALF = 5
324
Victor Stinner749a6a82015-03-30 22:09:14 +0200325 class InterruptSelect(Exception):
326 pass
327
328 def handler(signum, frame):
329 raise InterruptSelect
330 signal.signal(signal.SIGALRM, handler)
331
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200332 signal.alarm(1)
Victor Stinner79d68f92015-03-19 21:54:09 +0100333
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200334 # We attempt to get a signal during the sleep,
335 # before select is called
Victor Stinner79d68f92015-03-19 21:54:09 +0100336 try:
337 select.select([], [], [], TIMEOUT_FULL)
Victor Stinner749a6a82015-03-30 22:09:14 +0200338 except InterruptSelect:
Victor Stinner79d68f92015-03-19 21:54:09 +0100339 pass
340 else:
341 raise Exception("select() was not interrupted")
342
343 before_time = time.monotonic()
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200344 select.select([read], [], [], TIMEOUT_FULL)
Victor Stinner79d68f92015-03-19 21:54:09 +0100345 after_time = time.monotonic()
346 dt = after_time - before_time
Victor Stinner0a01f132011-07-04 18:06:35 +0200347 if dt >= TIMEOUT_HALF:
348 raise Exception("%s >= %s" % (dt, TIMEOUT_HALF))
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200349 """, signal.SIGALRM)
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000350
351 def test_wakeup_fd_during(self):
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200352 self.check_wakeup("""def test():
353 import select
354 import time
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000355
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200356 TIMEOUT_FULL = 10
357 TIMEOUT_HALF = 5
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000358
Victor Stinner749a6a82015-03-30 22:09:14 +0200359 class InterruptSelect(Exception):
360 pass
361
362 def handler(signum, frame):
363 raise InterruptSelect
364 signal.signal(signal.SIGALRM, handler)
365
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200366 signal.alarm(1)
Victor Stinner79d68f92015-03-19 21:54:09 +0100367 before_time = time.monotonic()
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200368 # We attempt to get a signal during the select call
369 try:
370 select.select([read], [], [], TIMEOUT_FULL)
Victor Stinner749a6a82015-03-30 22:09:14 +0200371 except InterruptSelect:
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200372 pass
373 else:
Victor Stinner749a6a82015-03-30 22:09:14 +0200374 raise Exception("select() was not interrupted")
Victor Stinner79d68f92015-03-19 21:54:09 +0100375 after_time = time.monotonic()
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200376 dt = after_time - before_time
Victor Stinner0a01f132011-07-04 18:06:35 +0200377 if dt >= TIMEOUT_HALF:
378 raise Exception("%s >= %s" % (dt, TIMEOUT_HALF))
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200379 """, signal.SIGALRM)
Victor Stinnerd49b1f12011-05-08 02:03:15 +0200380
381 def test_signum(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200382 self.check_wakeup("""def test():
383 signal.signal(signal.SIGUSR1, handler)
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800384 signal.raise_signal(signal.SIGUSR1)
385 signal.raise_signal(signal.SIGALRM)
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200386 """, signal.SIGUSR1, signal.SIGALRM)
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000387
Victor Stinnerc13ef662011-05-25 02:35:58 +0200388 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
389 'need signal.pthread_sigmask()')
Victor Stinnerc13ef662011-05-25 02:35:58 +0200390 def test_pending(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200391 self.check_wakeup("""def test():
392 signum1 = signal.SIGUSR1
393 signum2 = signal.SIGUSR2
Victor Stinnerc13ef662011-05-25 02:35:58 +0200394
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200395 signal.signal(signum1, handler)
396 signal.signal(signum2, handler)
Victor Stinnerc13ef662011-05-25 02:35:58 +0200397
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200398 signal.pthread_sigmask(signal.SIG_BLOCK, (signum1, signum2))
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800399 signal.raise_signal(signum1)
400 signal.raise_signal(signum2)
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200401 # Unblocking the 2 signals calls the C signal handler twice
402 signal.pthread_sigmask(signal.SIG_UNBLOCK, (signum1, signum2))
Charles-François Natali027f9a32011-10-02 18:36:05 +0200403 """, signal.SIGUSR1, signal.SIGUSR2, ordered=False)
Victor Stinnerc13ef662011-05-25 02:35:58 +0200404
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000405
Victor Stinner11517102014-07-29 23:31:34 +0200406@unittest.skipUnless(hasattr(socket, 'socketpair'), 'need socket.socketpair')
407class WakeupSocketSignalTests(unittest.TestCase):
408
409 @unittest.skipIf(_testcapi is None, 'need _testcapi')
410 def test_socket(self):
411 # use a subprocess to have only one thread
412 code = """if 1:
413 import signal
414 import socket
415 import struct
416 import _testcapi
417
418 signum = signal.SIGINT
419 signals = (signum,)
420
421 def handler(signum, frame):
422 pass
423
424 signal.signal(signum, handler)
425
426 read, write = socket.socketpair()
Victor Stinner11517102014-07-29 23:31:34 +0200427 write.setblocking(False)
428 signal.set_wakeup_fd(write.fileno())
429
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800430 signal.raise_signal(signum)
Victor Stinner11517102014-07-29 23:31:34 +0200431
432 data = read.recv(1)
433 if not data:
434 raise Exception("no signum written")
435 raised = struct.unpack('B', data)
436 if raised != signals:
437 raise Exception("%r != %r" % (raised, signals))
438
439 read.close()
440 write.close()
441 """
442
443 assert_python_ok('-c', code)
444
445 @unittest.skipIf(_testcapi is None, 'need _testcapi')
446 def test_send_error(self):
447 # Use a subprocess to have only one thread.
448 if os.name == 'nt':
449 action = 'send'
450 else:
451 action = 'write'
452 code = """if 1:
453 import errno
454 import signal
455 import socket
456 import sys
457 import time
458 import _testcapi
459 from test.support import captured_stderr
460
461 signum = signal.SIGINT
462
463 def handler(signum, frame):
464 pass
465
466 signal.signal(signum, handler)
467
468 read, write = socket.socketpair()
469 read.setblocking(False)
470 write.setblocking(False)
471
472 signal.set_wakeup_fd(write.fileno())
473
474 # Close sockets: send() will fail
475 read.close()
476 write.close()
477
478 with captured_stderr() as err:
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800479 signal.raise_signal(signum)
Victor Stinner11517102014-07-29 23:31:34 +0200480
481 err = err.getvalue()
482 if ('Exception ignored when trying to {action} to the signal wakeup fd'
483 not in err):
484 raise AssertionError(err)
485 """.format(action=action)
486 assert_python_ok('-c', code)
487
Nathaniel J. Smith902ab802017-12-17 20:10:18 -0800488 @unittest.skipIf(_testcapi is None, 'need _testcapi')
489 def test_warn_on_full_buffer(self):
490 # Use a subprocess to have only one thread.
491 if os.name == 'nt':
492 action = 'send'
493 else:
494 action = 'write'
495 code = """if 1:
496 import errno
497 import signal
498 import socket
499 import sys
500 import time
501 import _testcapi
502 from test.support import captured_stderr
503
504 signum = signal.SIGINT
505
506 # This handler will be called, but we intentionally won't read from
507 # the wakeup fd.
508 def handler(signum, frame):
509 pass
510
511 signal.signal(signum, handler)
512
513 read, write = socket.socketpair()
Nathaniel J. Smith902ab802017-12-17 20:10:18 -0800514
Victor Stinner686b4b52018-07-18 18:29:54 +0200515 # Fill the socketpair buffer
516 if sys.platform == 'win32':
517 # bpo-34130: On Windows, sometimes non-blocking send fails to fill
518 # the full socketpair buffer, so use a timeout of 50 ms instead.
519 write.settimeout(0.050)
520 else:
521 write.setblocking(False)
522
Victor Stinner686b4b52018-07-18 18:29:54 +0200523 written = 0
pxinwr1244c812020-12-01 05:48:33 +0800524 if sys.platform == "vxworks":
525 CHUNK_SIZES = (1,)
526 else:
527 # Start with large chunk size to reduce the
528 # number of send needed to fill the buffer.
529 CHUNK_SIZES = (2 ** 16, 2 ** 8, 1)
530 for chunk_size in CHUNK_SIZES:
Victor Stinner686b4b52018-07-18 18:29:54 +0200531 chunk = b"x" * chunk_size
532 try:
533 while True:
534 write.send(chunk)
535 written += chunk_size
Christian Heimes03c8ddd2020-11-20 09:26:07 +0100536 except (BlockingIOError, TimeoutError):
Victor Stinner686b4b52018-07-18 18:29:54 +0200537 pass
538
539 print(f"%s bytes written into the socketpair" % written, flush=True)
540
541 write.setblocking(False)
Nathaniel J. Smith902ab802017-12-17 20:10:18 -0800542 try:
Victor Stinner686b4b52018-07-18 18:29:54 +0200543 write.send(b"x")
Nathaniel J. Smith902ab802017-12-17 20:10:18 -0800544 except BlockingIOError:
Victor Stinner686b4b52018-07-18 18:29:54 +0200545 # The socketpair buffer seems full
Nathaniel J. Smith902ab802017-12-17 20:10:18 -0800546 pass
Victor Stinner686b4b52018-07-18 18:29:54 +0200547 else:
548 raise AssertionError("%s bytes failed to fill the socketpair "
549 "buffer" % written)
Nathaniel J. Smith902ab802017-12-17 20:10:18 -0800550
551 # By default, we get a warning when a signal arrives
Victor Stinner686b4b52018-07-18 18:29:54 +0200552 msg = ('Exception ignored when trying to {action} '
553 'to the signal wakeup fd')
Nathaniel J. Smith902ab802017-12-17 20:10:18 -0800554 signal.set_wakeup_fd(write.fileno())
555
556 with captured_stderr() as err:
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800557 signal.raise_signal(signum)
Nathaniel J. Smith902ab802017-12-17 20:10:18 -0800558
559 err = err.getvalue()
Victor Stinner686b4b52018-07-18 18:29:54 +0200560 if msg not in err:
561 raise AssertionError("first set_wakeup_fd() test failed, "
562 "stderr: %r" % err)
Nathaniel J. Smith902ab802017-12-17 20:10:18 -0800563
564 # And also if warn_on_full_buffer=True
565 signal.set_wakeup_fd(write.fileno(), warn_on_full_buffer=True)
566
567 with captured_stderr() as err:
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800568 signal.raise_signal(signum)
Nathaniel J. Smith902ab802017-12-17 20:10:18 -0800569
570 err = err.getvalue()
Victor Stinner686b4b52018-07-18 18:29:54 +0200571 if msg not in err:
572 raise AssertionError("set_wakeup_fd(warn_on_full_buffer=True) "
573 "test failed, stderr: %r" % err)
Nathaniel J. Smith902ab802017-12-17 20:10:18 -0800574
575 # But not if warn_on_full_buffer=False
576 signal.set_wakeup_fd(write.fileno(), warn_on_full_buffer=False)
577
578 with captured_stderr() as err:
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800579 signal.raise_signal(signum)
Nathaniel J. Smith902ab802017-12-17 20:10:18 -0800580
581 err = err.getvalue()
582 if err != "":
Victor Stinner686b4b52018-07-18 18:29:54 +0200583 raise AssertionError("set_wakeup_fd(warn_on_full_buffer=False) "
584 "test failed, stderr: %r" % err)
Nathaniel J. Smith902ab802017-12-17 20:10:18 -0800585
586 # And then check the default again, to make sure warn_on_full_buffer
587 # settings don't leak across calls.
588 signal.set_wakeup_fd(write.fileno())
589
590 with captured_stderr() as err:
Vladimir Matveevc24c6c22019-01-08 01:58:25 -0800591 signal.raise_signal(signum)
Nathaniel J. Smith902ab802017-12-17 20:10:18 -0800592
593 err = err.getvalue()
Victor Stinner686b4b52018-07-18 18:29:54 +0200594 if msg not in err:
595 raise AssertionError("second set_wakeup_fd() test failed, "
596 "stderr: %r" % err)
Nathaniel J. Smith902ab802017-12-17 20:10:18 -0800597
598 """.format(action=action)
599 assert_python_ok('-c', code)
600
Victor Stinner11517102014-07-29 23:31:34 +0200601
Brian Curtin3f004b12010-08-06 19:34:52 +0000602@unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
pxinwr1244c812020-12-01 05:48:33 +0800603@unittest.skipUnless(hasattr(signal, 'siginterrupt'), "needs signal.siginterrupt()")
Christian Heimes8640e742008-02-23 16:23:06 +0000604class SiginterruptTest(unittest.TestCase):
Jean-Paul Calderone9c39bc72010-05-09 03:25:16 +0000605
Victor Stinnerd6284962011-06-20 23:28:09 +0200606 def readpipe_interrupted(self, interrupt):
Jean-Paul Calderone9c39bc72010-05-09 03:25:16 +0000607 """Perform a read during which a signal will arrive. Return True if the
608 read is interrupted by the signal and raises an exception. Return False
609 if it returns normally.
610 """
Victor Stinnerd6284962011-06-20 23:28:09 +0200611 # use a subprocess to have only one thread, to have a timeout on the
612 # blocking read and to not touch signal handling in this process
613 code = """if 1:
614 import errno
615 import os
616 import signal
617 import sys
Jean-Paul Calderone9c39bc72010-05-09 03:25:16 +0000618
Victor Stinnerd6284962011-06-20 23:28:09 +0200619 interrupt = %r
620 r, w = os.pipe()
Christian Heimes8640e742008-02-23 16:23:06 +0000621
Victor Stinnerd6284962011-06-20 23:28:09 +0200622 def handler(signum, frame):
Charles-François Natali6e6c59b2015-02-07 13:27:50 +0000623 1 / 0
Victor Stinnerd6284962011-06-20 23:28:09 +0200624
625 signal.signal(signal.SIGALRM, handler)
626 if interrupt is not None:
627 signal.siginterrupt(signal.SIGALRM, interrupt)
628
Victor Stinnerdfde0d42011-07-01 15:58:39 +0200629 print("ready")
630 sys.stdout.flush()
631
Victor Stinnerd6284962011-06-20 23:28:09 +0200632 # run the test twice
Victor Stinner56e8c292014-07-21 12:30:22 +0200633 try:
634 for loop in range(2):
635 # send a SIGALRM in a second (during the read)
636 signal.alarm(1)
637 try:
638 # blocking call: read from a pipe without data
639 os.read(r, 1)
Charles-François Natali6e6c59b2015-02-07 13:27:50 +0000640 except ZeroDivisionError:
641 pass
Victor Stinner56e8c292014-07-21 12:30:22 +0200642 else:
643 sys.exit(2)
644 sys.exit(3)
645 finally:
646 os.close(r)
647 os.close(w)
Victor Stinnerd6284962011-06-20 23:28:09 +0200648 """ % (interrupt,)
649 with spawn_python('-c', code) as process:
Christian Heimes8640e742008-02-23 16:23:06 +0000650 try:
Victor Stinner45273652011-06-22 22:15:51 +0200651 # wait until the child process is loaded and has started
652 first_line = process.stdout.readline()
653
Victor Stinner0d63bac2019-12-11 11:30:03 +0100654 stdout, stderr = process.communicate(timeout=support.SHORT_TIMEOUT)
Victor Stinnerd6284962011-06-20 23:28:09 +0200655 except subprocess.TimeoutExpired:
656 process.kill()
Christian Heimes8640e742008-02-23 16:23:06 +0000657 return False
Victor Stinnerd6284962011-06-20 23:28:09 +0200658 else:
Victor Stinner45273652011-06-22 22:15:51 +0200659 stdout = first_line + stdout
Victor Stinnerd6284962011-06-20 23:28:09 +0200660 exitcode = process.wait()
661 if exitcode not in (2, 3):
Antoine Pitroudab4e8a2014-05-11 19:05:23 +0200662 raise Exception("Child error (exit code %s): %r"
Victor Stinnerd6284962011-06-20 23:28:09 +0200663 % (exitcode, stdout))
664 return (exitcode == 3)
Christian Heimes8640e742008-02-23 16:23:06 +0000665
666 def test_without_siginterrupt(self):
Victor Stinner3a7f0f02011-05-08 02:10:36 +0200667 # If a signal handler is installed and siginterrupt is not called
668 # at all, when that signal arrives, it interrupts a syscall that's in
669 # progress.
Victor Stinnerd6284962011-06-20 23:28:09 +0200670 interrupted = self.readpipe_interrupted(None)
671 self.assertTrue(interrupted)
Christian Heimes8640e742008-02-23 16:23:06 +0000672
673 def test_siginterrupt_on(self):
Victor Stinner3a7f0f02011-05-08 02:10:36 +0200674 # If a signal handler is installed and siginterrupt is called with
675 # a true value for the second argument, when that signal arrives, it
676 # interrupts a syscall that's in progress.
Victor Stinnerd6284962011-06-20 23:28:09 +0200677 interrupted = self.readpipe_interrupted(True)
678 self.assertTrue(interrupted)
Christian Heimes8640e742008-02-23 16:23:06 +0000679
680 def test_siginterrupt_off(self):
Victor Stinner3a7f0f02011-05-08 02:10:36 +0200681 # If a signal handler is installed and siginterrupt is called with
682 # a false value for the second argument, when that signal arrives, it
683 # does not interrupt a syscall that's in progress.
Victor Stinnerd6284962011-06-20 23:28:09 +0200684 interrupted = self.readpipe_interrupted(False)
685 self.assertFalse(interrupted)
Jean-Paul Calderone9c39bc72010-05-09 03:25:16 +0000686
687
Brian Curtin3f004b12010-08-06 19:34:52 +0000688@unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
pxinwr1244c812020-12-01 05:48:33 +0800689@unittest.skipUnless(hasattr(signal, 'getitimer') and hasattr(signal, 'setitimer'),
690 "needs signal.getitimer() and signal.setitimer()")
Martin v. Löwis823725e2008-03-24 13:39:54 +0000691class ItimerTest(unittest.TestCase):
692 def setUp(self):
693 self.hndl_called = False
694 self.hndl_count = 0
695 self.itimer = None
Christian Heimescc47b052008-03-25 14:56:36 +0000696 self.old_alarm = signal.signal(signal.SIGALRM, self.sig_alrm)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000697
698 def tearDown(self):
Christian Heimescc47b052008-03-25 14:56:36 +0000699 signal.signal(signal.SIGALRM, self.old_alarm)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000700 if self.itimer is not None: # test_itimer_exc doesn't change this attr
701 # just ensure that itimer is stopped
702 signal.setitimer(self.itimer, 0)
703
704 def sig_alrm(self, *args):
705 self.hndl_called = True
Martin v. Löwis823725e2008-03-24 13:39:54 +0000706
707 def sig_vtalrm(self, *args):
708 self.hndl_called = True
709
710 if self.hndl_count > 3:
711 # it shouldn't be here, because it should have been disabled.
712 raise signal.ItimerError("setitimer didn't disable ITIMER_VIRTUAL "
713 "timer.")
714 elif self.hndl_count == 3:
715 # disable ITIMER_VIRTUAL, this function shouldn't be called anymore
716 signal.setitimer(signal.ITIMER_VIRTUAL, 0)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000717
718 self.hndl_count += 1
719
Martin v. Löwis823725e2008-03-24 13:39:54 +0000720 def sig_prof(self, *args):
721 self.hndl_called = True
722 signal.setitimer(signal.ITIMER_PROF, 0)
723
Martin v. Löwis823725e2008-03-24 13:39:54 +0000724 def test_itimer_exc(self):
725 # XXX I'm assuming -1 is an invalid itimer, but maybe some platform
726 # defines it ?
727 self.assertRaises(signal.ItimerError, signal.setitimer, -1, 0)
Christian Heimescc47b052008-03-25 14:56:36 +0000728 # Negative times are treated as zero on some platforms.
729 if 0:
730 self.assertRaises(signal.ItimerError,
731 signal.setitimer, signal.ITIMER_REAL, -1)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000732
733 def test_itimer_real(self):
734 self.itimer = signal.ITIMER_REAL
Martin v. Löwis823725e2008-03-24 13:39:54 +0000735 signal.setitimer(self.itimer, 1.0)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000736 signal.pause()
Martin v. Löwis823725e2008-03-24 13:39:54 +0000737 self.assertEqual(self.hndl_called, True)
738
R. David Murray44546f82010-04-21 01:59:28 +0000739 # Issue 3864, unknown if this affects earlier versions of freebsd also
Victor Stinner13ff2452018-01-22 18:32:50 +0100740 @unittest.skipIf(sys.platform in ('netbsd5',),
Gregory P. Smith397cd8a2010-10-17 04:23:21 +0000741 'itimer not reliable (does not mix well with threading) on some BSDs.')
Martin v. Löwis823725e2008-03-24 13:39:54 +0000742 def test_itimer_virtual(self):
743 self.itimer = signal.ITIMER_VIRTUAL
744 signal.signal(signal.SIGVTALRM, self.sig_vtalrm)
745 signal.setitimer(self.itimer, 0.3, 0.2)
746
Victor Stinner79d68f92015-03-19 21:54:09 +0100747 start_time = time.monotonic()
748 while time.monotonic() - start_time < 60.0:
Mark Dickinson95078872009-10-04 18:47:48 +0000749 # use up some virtual time by doing real work
750 _ = pow(12345, 67890, 10000019)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000751 if signal.getitimer(self.itimer) == (0.0, 0.0):
752 break # sig_vtalrm handler stopped this itimer
Stefan Krahf1da973042010-04-20 08:15:14 +0000753 else: # Issue 8424
Benjamin Peterson9b140f62010-05-15 18:00:56 +0000754 self.skipTest("timeout: likely cause: machine too slow or load too "
755 "high")
Martin v. Löwis823725e2008-03-24 13:39:54 +0000756
757 # virtual itimer should be (0.0, 0.0) now
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000758 self.assertEqual(signal.getitimer(self.itimer), (0.0, 0.0))
Martin v. Löwis823725e2008-03-24 13:39:54 +0000759 # and the handler should have been called
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000760 self.assertEqual(self.hndl_called, True)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000761
762 def test_itimer_prof(self):
763 self.itimer = signal.ITIMER_PROF
764 signal.signal(signal.SIGPROF, self.sig_prof)
Neal Norwitzf5c7c2e2008-04-05 04:47:45 +0000765 signal.setitimer(self.itimer, 0.2, 0.2)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000766
Victor Stinner79d68f92015-03-19 21:54:09 +0100767 start_time = time.monotonic()
768 while time.monotonic() - start_time < 60.0:
Mark Dickinson78373472009-10-31 10:39:21 +0000769 # do some work
770 _ = pow(12345, 67890, 10000019)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000771 if signal.getitimer(self.itimer) == (0.0, 0.0):
772 break # sig_prof handler stopped this itimer
Stefan Krahf1da973042010-04-20 08:15:14 +0000773 else: # Issue 8424
Benjamin Peterson9b140f62010-05-15 18:00:56 +0000774 self.skipTest("timeout: likely cause: machine too slow or load too "
775 "high")
Martin v. Löwis823725e2008-03-24 13:39:54 +0000776
Neal Norwitzf5c7c2e2008-04-05 04:47:45 +0000777 # profiling itimer should be (0.0, 0.0) now
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000778 self.assertEqual(signal.getitimer(self.itimer), (0.0, 0.0))
Neal Norwitzf5c7c2e2008-04-05 04:47:45 +0000779 # and the handler should have been called
Martin v. Löwis823725e2008-03-24 13:39:54 +0000780 self.assertEqual(self.hndl_called, True)
781
Antoine Pitrou729780a2017-06-30 10:01:05 +0200782 def test_setitimer_tiny(self):
783 # bpo-30807: C setitimer() takes a microsecond-resolution interval.
784 # Check that float -> timeval conversion doesn't round
785 # the interval down to zero, which would disable the timer.
786 self.itimer = signal.ITIMER_REAL
787 signal.setitimer(self.itimer, 1e-6)
788 time.sleep(1)
789 self.assertEqual(self.hndl_called, True)
790
Victor Stinnera9293352011-04-30 15:21:58 +0200791
Victor Stinner35b300c2011-05-04 13:20:35 +0200792class PendingSignalsTests(unittest.TestCase):
793 """
Victor Stinnerb3e72192011-05-08 01:46:11 +0200794 Test pthread_sigmask(), pthread_kill(), sigpending() and sigwait()
795 functions.
Victor Stinner35b300c2011-05-04 13:20:35 +0200796 """
Victor Stinnerb3e72192011-05-08 01:46:11 +0200797 @unittest.skipUnless(hasattr(signal, 'sigpending'),
798 'need signal.sigpending()')
799 def test_sigpending_empty(self):
800 self.assertEqual(signal.sigpending(), set())
801
802 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
803 'need signal.pthread_sigmask()')
804 @unittest.skipUnless(hasattr(signal, 'sigpending'),
805 'need signal.sigpending()')
806 def test_sigpending(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200807 code = """if 1:
808 import os
809 import signal
Victor Stinnerb3e72192011-05-08 01:46:11 +0200810
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200811 def handler(signum, frame):
812 1/0
Victor Stinnerb3e72192011-05-08 01:46:11 +0200813
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200814 signum = signal.SIGUSR1
815 signal.signal(signum, handler)
816
817 signal.pthread_sigmask(signal.SIG_BLOCK, [signum])
818 os.kill(os.getpid(), signum)
819 pending = signal.sigpending()
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +0200820 for sig in pending:
821 assert isinstance(sig, signal.Signals), repr(pending)
Victor Stinner0a01f132011-07-04 18:06:35 +0200822 if pending != {signum}:
823 raise Exception('%s != {%s}' % (pending, signum))
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200824 try:
825 signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum])
826 except ZeroDivisionError:
827 pass
828 else:
829 raise Exception("ZeroDivisionError not raised")
830 """
831 assert_python_ok('-c', code)
Victor Stinnerb3e72192011-05-08 01:46:11 +0200832
833 @unittest.skipUnless(hasattr(signal, 'pthread_kill'),
834 'need signal.pthread_kill()')
835 def test_pthread_kill(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200836 code = """if 1:
837 import signal
838 import threading
839 import sys
Victor Stinnerb3e72192011-05-08 01:46:11 +0200840
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200841 signum = signal.SIGUSR1
Victor Stinnerb3e72192011-05-08 01:46:11 +0200842
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200843 def handler(signum, frame):
844 1/0
845
846 signal.signal(signum, handler)
847
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200848 tid = threading.get_ident()
849 try:
850 signal.pthread_kill(tid, signum)
851 except ZeroDivisionError:
852 pass
853 else:
854 raise Exception("ZeroDivisionError not raised")
855 """
856 assert_python_ok('-c', code)
Victor Stinnerb3e72192011-05-08 01:46:11 +0200857
Victor Stinner7f294d12011-06-10 14:02:10 +0200858 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
859 'need signal.pthread_sigmask()')
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200860 def wait_helper(self, blocked, test):
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200861 """
862 test: body of the "def test(signum):" function.
863 blocked: number of the blocked signal
864 """
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200865 code = '''if 1:
866 import signal
867 import sys
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +0200868 from signal import Signals
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200869
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200870 def handler(signum, frame):
871 1/0
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200872
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200873 %s
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200874
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200875 blocked = %s
876 signum = signal.SIGALRM
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200877
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200878 # child: block and wait the signal
879 try:
880 signal.signal(signum, handler)
881 signal.pthread_sigmask(signal.SIG_BLOCK, [blocked])
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200882
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200883 # Do the tests
884 test(signum)
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200885
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200886 # The handler must not be called on unblock
887 try:
888 signal.pthread_sigmask(signal.SIG_UNBLOCK, [blocked])
889 except ZeroDivisionError:
890 print("the signal handler has been called",
891 file=sys.stderr)
892 sys.exit(1)
893 except BaseException as err:
894 print("error: {}".format(err), file=sys.stderr)
895 sys.stderr.flush()
896 sys.exit(1)
897 ''' % (test.strip(), blocked)
Victor Stinner415007e2011-06-13 16:19:06 +0200898
Ross Lagerwallbc808222011-06-25 12:13:40 +0200899 # sig*wait* must be called with the signal blocked: since the current
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200900 # process might have several threads running, use a subprocess to have
901 # a single thread.
902 assert_python_ok('-c', code)
Victor Stinneraf494602011-06-10 12:48:13 +0200903
Victor Stinnerb3e72192011-05-08 01:46:11 +0200904 @unittest.skipUnless(hasattr(signal, 'sigwait'),
905 'need signal.sigwait()')
Ross Lagerwallbc808222011-06-25 12:13:40 +0200906 def test_sigwait(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200907 self.wait_helper(signal.SIGALRM, '''
908 def test(signum):
Ross Lagerwallbc808222011-06-25 12:13:40 +0200909 signal.alarm(1)
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200910 received = signal.sigwait([signum])
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +0200911 assert isinstance(received, signal.Signals), received
Victor Stinner0a01f132011-07-04 18:06:35 +0200912 if received != signum:
913 raise Exception('received %s, not %s' % (received, signum))
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200914 ''')
Ross Lagerwallbc808222011-06-25 12:13:40 +0200915
916 @unittest.skipUnless(hasattr(signal, 'sigwaitinfo'),
917 'need signal.sigwaitinfo()')
918 def test_sigwaitinfo(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200919 self.wait_helper(signal.SIGALRM, '''
920 def test(signum):
Ross Lagerwallbc808222011-06-25 12:13:40 +0200921 signal.alarm(1)
922 info = signal.sigwaitinfo([signum])
Victor Stinner0a01f132011-07-04 18:06:35 +0200923 if info.si_signo != signum:
924 raise Exception("info.si_signo != %s" % signum)
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200925 ''')
Ross Lagerwallbc808222011-06-25 12:13:40 +0200926
927 @unittest.skipUnless(hasattr(signal, 'sigtimedwait'),
928 'need signal.sigtimedwait()')
929 def test_sigtimedwait(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200930 self.wait_helper(signal.SIGALRM, '''
931 def test(signum):
Ross Lagerwallbc808222011-06-25 12:13:40 +0200932 signal.alarm(1)
Victor Stinner643cd682012-03-02 22:54:03 +0100933 info = signal.sigtimedwait([signum], 10.1000)
Victor Stinner0a01f132011-07-04 18:06:35 +0200934 if info.si_signo != signum:
935 raise Exception('info.si_signo != %s' % signum)
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200936 ''')
Ross Lagerwallbc808222011-06-25 12:13:40 +0200937
Ross Lagerwallbc808222011-06-25 12:13:40 +0200938 @unittest.skipUnless(hasattr(signal, 'sigtimedwait'),
939 'need signal.sigtimedwait()')
940 def test_sigtimedwait_poll(self):
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200941 # check that polling with sigtimedwait works
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200942 self.wait_helper(signal.SIGALRM, '''
943 def test(signum):
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200944 import os
945 os.kill(os.getpid(), signum)
Victor Stinner643cd682012-03-02 22:54:03 +0100946 info = signal.sigtimedwait([signum], 0)
Victor Stinner0a01f132011-07-04 18:06:35 +0200947 if info.si_signo != signum:
948 raise Exception('info.si_signo != %s' % signum)
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200949 ''')
Ross Lagerwallbc808222011-06-25 12:13:40 +0200950
951 @unittest.skipUnless(hasattr(signal, 'sigtimedwait'),
952 'need signal.sigtimedwait()')
953 def test_sigtimedwait_timeout(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200954 self.wait_helper(signal.SIGALRM, '''
955 def test(signum):
Victor Stinner643cd682012-03-02 22:54:03 +0100956 received = signal.sigtimedwait([signum], 1.0)
Victor Stinner0a01f132011-07-04 18:06:35 +0200957 if received is not None:
958 raise Exception("received=%r" % (received,))
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200959 ''')
Ross Lagerwallbc808222011-06-25 12:13:40 +0200960
961 @unittest.skipUnless(hasattr(signal, 'sigtimedwait'),
962 'need signal.sigtimedwait()')
963 def test_sigtimedwait_negative_timeout(self):
964 signum = signal.SIGALRM
Victor Stinner643cd682012-03-02 22:54:03 +0100965 self.assertRaises(ValueError, signal.sigtimedwait, [signum], -1.0)
Ross Lagerwallbc808222011-06-25 12:13:40 +0200966
Ross Lagerwallbc808222011-06-25 12:13:40 +0200967 @unittest.skipUnless(hasattr(signal, 'sigwait'),
968 'need signal.sigwait()')
Victor Stinner415007e2011-06-13 16:19:06 +0200969 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
970 'need signal.pthread_sigmask()')
Victor Stinner10c30d62011-06-10 01:39:53 +0200971 def test_sigwait_thread(self):
Victor Stinner415007e2011-06-13 16:19:06 +0200972 # Check that calling sigwait() from a thread doesn't suspend the whole
973 # process. A new interpreter is spawned to avoid problems when mixing
974 # threads and fork(): only async-safe functions are allowed between
975 # fork() and exec().
976 assert_python_ok("-c", """if True:
977 import os, threading, sys, time, signal
Victor Stinner10c30d62011-06-10 01:39:53 +0200978
Victor Stinner415007e2011-06-13 16:19:06 +0200979 # the default handler terminates the process
980 signum = signal.SIGUSR1
981
982 def kill_later():
983 # wait until the main thread is waiting in sigwait()
984 time.sleep(1)
985 os.kill(os.getpid(), signum)
986
987 # the signal must be blocked by all the threads
988 signal.pthread_sigmask(signal.SIG_BLOCK, [signum])
989 killer = threading.Thread(target=kill_later)
Victor Stinneraf494602011-06-10 12:48:13 +0200990 killer.start()
991 received = signal.sigwait([signum])
992 if received != signum:
993 print("sigwait() received %s, not %s" % (received, signum),
994 file=sys.stderr)
Victor Stinner415007e2011-06-13 16:19:06 +0200995 sys.exit(1)
Victor Stinner10c30d62011-06-10 01:39:53 +0200996 killer.join()
Victor Stinner415007e2011-06-13 16:19:06 +0200997 # unblock the signal, which should have been cleared by sigwait()
998 signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum])
999 """)
Victor Stinneraf494602011-06-10 12:48:13 +02001000
Victor Stinnerb3e72192011-05-08 01:46:11 +02001001 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
1002 'need signal.pthread_sigmask()')
1003 def test_pthread_sigmask_arguments(self):
1004 self.assertRaises(TypeError, signal.pthread_sigmask)
1005 self.assertRaises(TypeError, signal.pthread_sigmask, 1)
1006 self.assertRaises(TypeError, signal.pthread_sigmask, 1, 2, 3)
1007 self.assertRaises(OSError, signal.pthread_sigmask, 1700, [])
Antoine Pitrou9d3627e2018-05-04 13:00:50 +02001008 with self.assertRaises(ValueError):
1009 signal.pthread_sigmask(signal.SIG_BLOCK, [signal.NSIG])
Serhiy Storchakad54cfb12018-05-08 07:48:50 +03001010 with self.assertRaises(ValueError):
1011 signal.pthread_sigmask(signal.SIG_BLOCK, [0])
1012 with self.assertRaises(ValueError):
1013 signal.pthread_sigmask(signal.SIG_BLOCK, [1<<1000])
Antoine Pitrou9d3627e2018-05-04 13:00:50 +02001014
1015 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
1016 'need signal.pthread_sigmask()')
1017 def test_pthread_sigmask_valid_signals(self):
1018 s = signal.pthread_sigmask(signal.SIG_BLOCK, signal.valid_signals())
1019 self.addCleanup(signal.pthread_sigmask, signal.SIG_SETMASK, s)
1020 # Get current blocked set
1021 s = signal.pthread_sigmask(signal.SIG_UNBLOCK, signal.valid_signals())
1022 self.assertLessEqual(s, signal.valid_signals())
Victor Stinnerb3e72192011-05-08 01:46:11 +02001023
1024 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
1025 'need signal.pthread_sigmask()')
1026 def test_pthread_sigmask(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +02001027 code = """if 1:
1028 import signal
1029 import os; import threading
1030
1031 def handler(signum, frame):
1032 1/0
1033
1034 def kill(signum):
1035 os.kill(os.getpid(), signum)
1036
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +02001037 def check_mask(mask):
1038 for sig in mask:
1039 assert isinstance(sig, signal.Signals), repr(sig)
1040
Victor Stinnerd554cdf2011-07-04 17:49:40 +02001041 def read_sigmask():
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +02001042 sigmask = signal.pthread_sigmask(signal.SIG_BLOCK, [])
1043 check_mask(sigmask)
1044 return sigmask
Victor Stinnerd554cdf2011-07-04 17:49:40 +02001045
Victor Stinnerb3e72192011-05-08 01:46:11 +02001046 signum = signal.SIGUSR1
Victor Stinner6fd49e12011-05-04 12:38:03 +02001047
Victor Stinnerd0e516d2011-05-03 14:57:12 +02001048 # Install our signal handler
Victor Stinnerd554cdf2011-07-04 17:49:40 +02001049 old_handler = signal.signal(signum, handler)
Victor Stinnera9293352011-04-30 15:21:58 +02001050
Victor Stinnerd0e516d2011-05-03 14:57:12 +02001051 # Unblock SIGUSR1 (and copy the old mask) to test our signal handler
Victor Stinnera9293352011-04-30 15:21:58 +02001052 old_mask = signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum])
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +02001053 check_mask(old_mask)
Victor Stinnerd554cdf2011-07-04 17:49:40 +02001054 try:
1055 kill(signum)
1056 except ZeroDivisionError:
1057 pass
1058 else:
1059 raise Exception("ZeroDivisionError not raised")
Victor Stinnera9293352011-04-30 15:21:58 +02001060
Victor Stinnerd0e516d2011-05-03 14:57:12 +02001061 # Block and then raise SIGUSR1. The signal is blocked: the signal
1062 # handler is not called, and the signal is now pending
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +02001063 mask = signal.pthread_sigmask(signal.SIG_BLOCK, [signum])
1064 check_mask(mask)
Victor Stinnerd554cdf2011-07-04 17:49:40 +02001065 kill(signum)
Victor Stinnera9293352011-04-30 15:21:58 +02001066
Victor Stinnerd0e516d2011-05-03 14:57:12 +02001067 # Check the new mask
Victor Stinnerd554cdf2011-07-04 17:49:40 +02001068 blocked = read_sigmask()
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +02001069 check_mask(blocked)
Victor Stinner0a01f132011-07-04 18:06:35 +02001070 if signum not in blocked:
1071 raise Exception("%s not in %s" % (signum, blocked))
1072 if old_mask ^ blocked != {signum}:
1073 raise Exception("%s ^ %s != {%s}" % (old_mask, blocked, signum))
Victor Stinnera9293352011-04-30 15:21:58 +02001074
Victor Stinnerd0e516d2011-05-03 14:57:12 +02001075 # Unblock SIGUSR1
Victor Stinnerd554cdf2011-07-04 17:49:40 +02001076 try:
R David Murrayfc069992013-12-13 20:52:19 -05001077 # unblock the pending signal calls immediately the signal handler
Victor Stinnerd0e516d2011-05-03 14:57:12 +02001078 signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum])
Victor Stinnerd554cdf2011-07-04 17:49:40 +02001079 except ZeroDivisionError:
1080 pass
1081 else:
1082 raise Exception("ZeroDivisionError not raised")
1083 try:
1084 kill(signum)
1085 except ZeroDivisionError:
1086 pass
1087 else:
1088 raise Exception("ZeroDivisionError not raised")
Victor Stinnera9293352011-04-30 15:21:58 +02001089
Victor Stinnerd0e516d2011-05-03 14:57:12 +02001090 # Check the new mask
Victor Stinnerd554cdf2011-07-04 17:49:40 +02001091 unblocked = read_sigmask()
Victor Stinner0a01f132011-07-04 18:06:35 +02001092 if signum in unblocked:
1093 raise Exception("%s in %s" % (signum, unblocked))
1094 if blocked ^ unblocked != {signum}:
1095 raise Exception("%s ^ %s != {%s}" % (blocked, unblocked, signum))
1096 if old_mask != unblocked:
1097 raise Exception("%s != %s" % (old_mask, unblocked))
Victor Stinnerd554cdf2011-07-04 17:49:40 +02001098 """
1099 assert_python_ok('-c', code)
1100
Victor Stinnerd554cdf2011-07-04 17:49:40 +02001101 @unittest.skipUnless(hasattr(signal, 'pthread_kill'),
1102 'need signal.pthread_kill()')
1103 def test_pthread_kill_main_thread(self):
1104 # Test that a signal can be sent to the main thread with pthread_kill()
1105 # before any other thread has been created (see issue #12392).
1106 code = """if True:
1107 import threading
1108 import signal
1109 import sys
1110
1111 def handler(signum, frame):
1112 sys.exit(3)
1113
1114 signal.signal(signal.SIGUSR1, handler)
1115 signal.pthread_kill(threading.get_ident(), signal.SIGUSR1)
1116 sys.exit(2)
1117 """
1118
1119 with spawn_python('-c', code) as process:
1120 stdout, stderr = process.communicate()
1121 exitcode = process.wait()
1122 if exitcode != 3:
1123 raise Exception("Child error (exit code %s): %s" %
1124 (exitcode, stdout))
Victor Stinnera9293352011-04-30 15:21:58 +02001125
1126
Antoine Pitrouc08177a2017-06-28 23:29:29 +02001127class StressTest(unittest.TestCase):
1128 """
1129 Stress signal delivery, especially when a signal arrives in
1130 the middle of recomputing the signal state or executing
1131 previously tripped signal handlers.
1132 """
1133
Antoine Pitrouf7d090c2017-06-29 16:40:14 +02001134 def setsig(self, signum, handler):
1135 old_handler = signal.signal(signum, handler)
1136 self.addCleanup(signal.signal, signum, old_handler)
1137
1138 def measure_itimer_resolution(self):
1139 N = 20
1140 times = []
1141
1142 def handler(signum=None, frame=None):
1143 if len(times) < N:
1144 times.append(time.perf_counter())
1145 # 1 µs is the smallest possible timer interval,
1146 # we want to measure what the concrete duration
1147 # will be on this platform
1148 signal.setitimer(signal.ITIMER_REAL, 1e-6)
1149
1150 self.addCleanup(signal.setitimer, signal.ITIMER_REAL, 0)
1151 self.setsig(signal.SIGALRM, handler)
1152 handler()
1153 while len(times) < N:
1154 time.sleep(1e-3)
1155
1156 durations = [times[i+1] - times[i] for i in range(len(times) - 1)]
1157 med = statistics.median(durations)
1158 if support.verbose:
1159 print("detected median itimer() resolution: %.6f s." % (med,))
1160 return med
1161
1162 def decide_itimer_count(self):
1163 # Some systems have poor setitimer() resolution (for example
1164 # measured around 20 ms. on FreeBSD 9), so decide on a reasonable
1165 # number of sequential timers based on that.
1166 reso = self.measure_itimer_resolution()
1167 if reso <= 1e-4:
1168 return 10000
1169 elif reso <= 1e-2:
1170 return 100
1171 else:
1172 self.skipTest("detected itimer resolution (%.3f s.) too high "
1173 "(> 10 ms.) on this platform (or system too busy)"
1174 % (reso,))
1175
Antoine Pitrouc08177a2017-06-28 23:29:29 +02001176 @unittest.skipUnless(hasattr(signal, "setitimer"),
1177 "test needs setitimer()")
1178 def test_stress_delivery_dependent(self):
1179 """
1180 This test uses dependent signal handlers.
1181 """
Antoine Pitrouf7d090c2017-06-29 16:40:14 +02001182 N = self.decide_itimer_count()
Antoine Pitrouc08177a2017-06-28 23:29:29 +02001183 sigs = []
1184
1185 def first_handler(signum, frame):
1186 # 1e-6 is the minimum non-zero value for `setitimer()`.
1187 # Choose a random delay so as to improve chances of
1188 # triggering a race condition. Ideally the signal is received
1189 # when inside critical signal-handling routines such as
1190 # Py_MakePendingCalls().
1191 signal.setitimer(signal.ITIMER_REAL, 1e-6 + random.random() * 1e-5)
1192
1193 def second_handler(signum=None, frame=None):
1194 sigs.append(signum)
1195
Antoine Pitrouc08177a2017-06-28 23:29:29 +02001196 # Here on Linux, SIGPROF > SIGALRM > SIGUSR1. By using both
1197 # ascending and descending sequences (SIGUSR1 then SIGALRM,
1198 # SIGPROF then SIGALRM), we maximize chances of hitting a bug.
Antoine Pitrouf7d090c2017-06-29 16:40:14 +02001199 self.setsig(signal.SIGPROF, first_handler)
1200 self.setsig(signal.SIGUSR1, first_handler)
1201 self.setsig(signal.SIGALRM, second_handler) # for ITIMER_REAL
Antoine Pitrouc08177a2017-06-28 23:29:29 +02001202
1203 expected_sigs = 0
Victor Stinner0d63bac2019-12-11 11:30:03 +01001204 deadline = time.monotonic() + support.SHORT_TIMEOUT
Antoine Pitrouc08177a2017-06-28 23:29:29 +02001205
1206 while expected_sigs < N:
1207 os.kill(os.getpid(), signal.SIGPROF)
1208 expected_sigs += 1
1209 # Wait for handlers to run to avoid signal coalescing
Victor Stinner2cf4c202018-12-17 09:36:36 +01001210 while len(sigs) < expected_sigs and time.monotonic() < deadline:
Antoine Pitrouc08177a2017-06-28 23:29:29 +02001211 time.sleep(1e-5)
1212
1213 os.kill(os.getpid(), signal.SIGUSR1)
1214 expected_sigs += 1
Victor Stinner2cf4c202018-12-17 09:36:36 +01001215 while len(sigs) < expected_sigs and time.monotonic() < deadline:
Antoine Pitrouc08177a2017-06-28 23:29:29 +02001216 time.sleep(1e-5)
1217
1218 # All ITIMER_REAL signals should have been delivered to the
1219 # Python handler
1220 self.assertEqual(len(sigs), N, "Some signals were lost")
1221
1222 @unittest.skipUnless(hasattr(signal, "setitimer"),
1223 "test needs setitimer()")
1224 def test_stress_delivery_simultaneous(self):
1225 """
1226 This test uses simultaneous signal handlers.
1227 """
Antoine Pitrouf7d090c2017-06-29 16:40:14 +02001228 N = self.decide_itimer_count()
Antoine Pitrouc08177a2017-06-28 23:29:29 +02001229 sigs = []
1230
1231 def handler(signum, frame):
1232 sigs.append(signum)
1233
Antoine Pitrouf7d090c2017-06-29 16:40:14 +02001234 self.setsig(signal.SIGUSR1, handler)
1235 self.setsig(signal.SIGALRM, handler) # for ITIMER_REAL
Antoine Pitrouc08177a2017-06-28 23:29:29 +02001236
1237 expected_sigs = 0
Victor Stinner0d63bac2019-12-11 11:30:03 +01001238 deadline = time.monotonic() + support.SHORT_TIMEOUT
Antoine Pitrouc08177a2017-06-28 23:29:29 +02001239
1240 while expected_sigs < N:
1241 # Hopefully the SIGALRM will be received somewhere during
1242 # initial processing of SIGUSR1.
1243 signal.setitimer(signal.ITIMER_REAL, 1e-6 + random.random() * 1e-5)
1244 os.kill(os.getpid(), signal.SIGUSR1)
1245
1246 expected_sigs += 2
1247 # Wait for handlers to run to avoid signal coalescing
Victor Stinner2cf4c202018-12-17 09:36:36 +01001248 while len(sigs) < expected_sigs and time.monotonic() < deadline:
Antoine Pitrouc08177a2017-06-28 23:29:29 +02001249 time.sleep(1e-5)
1250
1251 # All ITIMER_REAL signals should have been delivered to the
1252 # Python handler
1253 self.assertEqual(len(sigs), N, "Some signals were lost")
1254
Antoine Pitrou68245b72021-03-05 10:32:50 +01001255 @unittest.skipUnless(hasattr(signal, "SIGUSR1"),
1256 "test needs SIGUSR1")
1257 def test_stress_modifying_handlers(self):
1258 # bpo-43406: race condition between trip_signal() and signal.signal
1259 signum = signal.SIGUSR1
1260 num_sent_signals = 0
1261 num_received_signals = 0
1262 do_stop = False
1263
1264 def custom_handler(signum, frame):
1265 nonlocal num_received_signals
1266 num_received_signals += 1
1267
1268 def set_interrupts():
1269 nonlocal num_sent_signals
1270 while not do_stop:
1271 signal.raise_signal(signum)
1272 num_sent_signals += 1
1273
1274 def cycle_handlers():
1275 while num_sent_signals < 100:
1276 for i in range(20000):
1277 # Cycle between a Python-defined and a non-Python handler
1278 for handler in [custom_handler, signal.SIG_IGN]:
1279 signal.signal(signum, handler)
1280
1281 old_handler = signal.signal(signum, custom_handler)
1282 self.addCleanup(signal.signal, signum, old_handler)
Victor Stinner1fa17e82021-03-10 15:26:45 +01001283
Antoine Pitrou68245b72021-03-05 10:32:50 +01001284 t = threading.Thread(target=set_interrupts)
Antoine Pitrou68245b72021-03-05 10:32:50 +01001285 try:
Victor Stinner1fa17e82021-03-10 15:26:45 +01001286 ignored = False
Antoine Pitrou68245b72021-03-05 10:32:50 +01001287 with support.catch_unraisable_exception() as cm:
Victor Stinner1fa17e82021-03-10 15:26:45 +01001288 t.start()
Antoine Pitrou68245b72021-03-05 10:32:50 +01001289 cycle_handlers()
Victor Stinner1fa17e82021-03-10 15:26:45 +01001290 do_stop = True
1291 t.join()
1292
Antoine Pitrou68245b72021-03-05 10:32:50 +01001293 if cm.unraisable is not None:
1294 # An unraisable exception may be printed out when
1295 # a signal is ignored due to the aforementioned
1296 # race condition, check it.
1297 self.assertIsInstance(cm.unraisable.exc_value, OSError)
1298 self.assertIn(
1299 f"Signal {signum} ignored due to race condition",
1300 str(cm.unraisable.exc_value))
Victor Stinner1fa17e82021-03-10 15:26:45 +01001301 ignored = True
1302
1303 # bpo-43406: Even if it is unlikely, it's technically possible that
1304 # all signals were ignored because of race conditions.
1305 if not ignored:
1306 # Sanity check that some signals were received, but not all
1307 self.assertGreater(num_received_signals, 0)
Antoine Pitrou68245b72021-03-05 10:32:50 +01001308 self.assertLess(num_received_signals, num_sent_signals)
1309 finally:
1310 do_stop = True
1311 t.join()
1312
1313
Vladimir Matveevc24c6c22019-01-08 01:58:25 -08001314class RaiseSignalTest(unittest.TestCase):
1315
1316 def test_sigint(self):
Gregory P. Smith38f11cc2019-02-16 12:57:40 -08001317 with self.assertRaises(KeyboardInterrupt):
Vladimir Matveevc24c6c22019-01-08 01:58:25 -08001318 signal.raise_signal(signal.SIGINT)
Vladimir Matveevc24c6c22019-01-08 01:58:25 -08001319
1320 @unittest.skipIf(sys.platform != "win32", "Windows specific test")
1321 def test_invalid_argument(self):
1322 try:
1323 SIGHUP = 1 # not supported on win32
1324 signal.raise_signal(SIGHUP)
1325 self.fail("OSError (Invalid argument) expected")
1326 except OSError as e:
1327 if e.errno == errno.EINVAL:
1328 pass
1329 else:
1330 raise
1331
1332 def test_handler(self):
1333 is_ok = False
1334 def handler(a, b):
1335 nonlocal is_ok
1336 is_ok = True
1337 old_signal = signal.signal(signal.SIGINT, handler)
1338 self.addCleanup(signal.signal, signal.SIGINT, old_signal)
1339
1340 signal.raise_signal(signal.SIGINT)
1341 self.assertTrue(is_ok)
1342
Antoine Pitrouc08177a2017-06-28 23:29:29 +02001343
Benjamin Peterson74834512019-11-19 20:39:14 -08001344class PidfdSignalTest(unittest.TestCase):
1345
1346 @unittest.skipUnless(
1347 hasattr(signal, "pidfd_send_signal"),
1348 "pidfd support not built in",
1349 )
1350 def test_pidfd_send_signal(self):
1351 with self.assertRaises(OSError) as cm:
1352 signal.pidfd_send_signal(0, signal.SIGINT)
1353 if cm.exception.errno == errno.ENOSYS:
1354 self.skipTest("kernel does not support pidfds")
Pablo Galindo8f0703f2019-12-29 21:35:54 +00001355 elif cm.exception.errno == errno.EPERM:
1356 self.skipTest("Not enough privileges to use pidfs")
Benjamin Peterson74834512019-11-19 20:39:14 -08001357 self.assertEqual(cm.exception.errno, errno.EBADF)
1358 my_pidfd = os.open(f'/proc/{os.getpid()}', os.O_DIRECTORY)
1359 self.addCleanup(os.close, my_pidfd)
damani4238c878b2020-01-30 11:26:22 +01001360 with self.assertRaisesRegex(TypeError, "^siginfo must be None$"):
Benjamin Peterson74834512019-11-19 20:39:14 -08001361 signal.pidfd_send_signal(my_pidfd, signal.SIGINT, object(), 0)
1362 with self.assertRaises(KeyboardInterrupt):
1363 signal.pidfd_send_signal(my_pidfd, signal.SIGINT)
1364
Zachary Ware38c707e2015-04-13 15:00:43 -05001365def tearDownModule():
1366 support.reap_children()
Thomas Woutersed03b412007-08-28 21:37:11 +00001367
1368if __name__ == "__main__":
Zachary Ware38c707e2015-04-13 15:00:43 -05001369 unittest.main()