blob: ecdffa60a65c03ee4d6f18d2ab74dbd26639a170 [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
Antoine Pietri5d2a27d2018-03-12 14:42:34 +010046 self.assertRaises(ValueError, signal.strsignal, 4242)
47
Thomas Woutersed03b412007-08-28 21:37:11 +000048 def test_setting_signal_handler_to_none_raises_error(self):
49 self.assertRaises(TypeError, signal.signal,
50 signal.SIGUSR1, None)
51
Christian Heimes4fbc72b2008-03-22 00:47:35 +000052 def test_getsignal(self):
53 hup = signal.signal(signal.SIGHUP, self.trivial_signal_handler)
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +020054 self.assertIsInstance(hup, signal.Handlers)
Ezio Melotti19f2aeb2010-11-21 01:30:29 +000055 self.assertEqual(signal.getsignal(signal.SIGHUP),
56 self.trivial_signal_handler)
Christian Heimes4fbc72b2008-03-22 00:47:35 +000057 signal.signal(signal.SIGHUP, hup)
Ezio Melotti19f2aeb2010-11-21 01:30:29 +000058 self.assertEqual(signal.getsignal(signal.SIGHUP), hup)
Christian Heimes4fbc72b2008-03-22 00:47:35 +000059
Antoine Pietri5d2a27d2018-03-12 14:42:34 +010060 def test_strsignal(self):
Antoine Pietri019f5b32018-03-12 20:03:14 +010061 self.assertIn("Interrupt", signal.strsignal(signal.SIGINT))
62 self.assertIn("Terminated", signal.strsignal(signal.SIGTERM))
Antoine Pietri5d2a27d2018-03-12 14:42:34 +010063
Victor Stinner32eb8402016-03-15 11:12:35 +010064 # Issue 3864, unknown if this affects earlier versions of freebsd also
Victor Stinner32eb8402016-03-15 11:12:35 +010065 def test_interprocess_signal(self):
66 dirname = os.path.dirname(__file__)
67 script = os.path.join(dirname, 'signalinterproctester.py')
68 assert_python_ok(script)
69
Antoine Pitrou9d3627e2018-05-04 13:00:50 +020070 def test_valid_signals(self):
71 s = signal.valid_signals()
72 self.assertIsInstance(s, set)
73 self.assertIn(signal.Signals.SIGINT, s)
74 self.assertIn(signal.Signals.SIGALRM, s)
75 self.assertNotIn(0, s)
76 self.assertNotIn(signal.NSIG, s)
77 self.assertLess(len(s), signal.NSIG)
78
Christian Heimes4fbc72b2008-03-22 00:47:35 +000079
Brian Curtin3f004b12010-08-06 19:34:52 +000080@unittest.skipUnless(sys.platform == "win32", "Windows specific")
81class WindowsSignalTests(unittest.TestCase):
Antoine Pitrou9d3627e2018-05-04 13:00:50 +020082
83 def test_valid_signals(self):
84 s = signal.valid_signals()
85 self.assertIsInstance(s, set)
86 self.assertGreaterEqual(len(s), 6)
87 self.assertIn(signal.Signals.SIGINT, s)
88 self.assertNotIn(0, s)
89 self.assertNotIn(signal.NSIG, s)
90 self.assertLess(len(s), signal.NSIG)
91
Brian Curtin3f004b12010-08-06 19:34:52 +000092 def test_issue9324(self):
Brian Curtineccd4d92010-10-01 15:09:53 +000093 # Updated for issue #10003, adding SIGBREAK
Brian Curtin3f004b12010-08-06 19:34:52 +000094 handler = lambda x, y: None
Nick Coghlan60b3ac72013-08-03 22:56:30 +100095 checked = set()
Brian Curtineccd4d92010-10-01 15:09:53 +000096 for sig in (signal.SIGABRT, signal.SIGBREAK, signal.SIGFPE,
97 signal.SIGILL, signal.SIGINT, signal.SIGSEGV,
98 signal.SIGTERM):
Nick Coghlan60b3ac72013-08-03 22:56:30 +100099 # Set and then reset a handler for signals that work on windows.
100 # Issue #18396, only for signals without a C-level handler.
101 if signal.getsignal(sig) is not None:
102 signal.signal(sig, signal.signal(sig, handler))
103 checked.add(sig)
104 # Issue #18396: Ensure the above loop at least tested *something*
105 self.assertTrue(checked)
Brian Curtin3f004b12010-08-06 19:34:52 +0000106
107 with self.assertRaises(ValueError):
108 signal.signal(-1, handler)
Brian Curtin80cd4bf2010-08-07 03:52:38 +0000109
110 with self.assertRaises(ValueError):
111 signal.signal(7, handler)
Brian Curtin3f004b12010-08-06 19:34:52 +0000112
113
Benjamin Petersonc68a4a02013-01-18 00:10:24 -0500114class WakeupFDTests(unittest.TestCase):
115
Nathaniel J. Smith902ab802017-12-17 20:10:18 -0800116 def test_invalid_call(self):
117 # First parameter is positional-only
118 with self.assertRaises(TypeError):
119 signal.set_wakeup_fd(signum=signal.SIGINT)
120
121 # warn_on_full_buffer is a keyword-only parameter
122 with self.assertRaises(TypeError):
123 signal.set_wakeup_fd(signal.SIGINT, False)
124
Benjamin Petersonc68a4a02013-01-18 00:10:24 -0500125 def test_invalid_fd(self):
Victor Stinner1d8948e2014-07-24 22:51:05 +0200126 fd = support.make_bad_fd()
Victor Stinnera7d03d92014-07-21 17:17:28 +0200127 self.assertRaises((ValueError, OSError),
128 signal.set_wakeup_fd, fd)
Benjamin Petersonc68a4a02013-01-18 00:10:24 -0500129
Victor Stinner11517102014-07-29 23:31:34 +0200130 def test_invalid_socket(self):
131 sock = socket.socket()
132 fd = sock.fileno()
133 sock.close()
134 self.assertRaises((ValueError, OSError),
135 signal.set_wakeup_fd, fd)
136
Victor Stinnerd18ccd12014-07-24 21:58:53 +0200137 def test_set_wakeup_fd_result(self):
Victor Stinner1d8948e2014-07-24 22:51:05 +0200138 r1, w1 = os.pipe()
139 self.addCleanup(os.close, r1)
140 self.addCleanup(os.close, w1)
141 r2, w2 = os.pipe()
142 self.addCleanup(os.close, r2)
143 self.addCleanup(os.close, w2)
Victor Stinnerd18ccd12014-07-24 21:58:53 +0200144
Victor Stinner7cea44d2014-08-27 14:02:36 +0200145 if hasattr(os, 'set_blocking'):
146 os.set_blocking(w1, False)
147 os.set_blocking(w2, False)
Victor Stinner38227602014-08-27 12:59:44 +0200148
Victor Stinner1d8948e2014-07-24 22:51:05 +0200149 signal.set_wakeup_fd(w1)
Victor Stinnerc82a1792014-07-24 22:55:12 +0200150 self.assertEqual(signal.set_wakeup_fd(w2), w1)
151 self.assertEqual(signal.set_wakeup_fd(-1), w2)
152 self.assertEqual(signal.set_wakeup_fd(-1), -1)
Victor Stinner56e8c292014-07-21 12:30:22 +0200153
Victor Stinner11517102014-07-29 23:31:34 +0200154 def test_set_wakeup_fd_socket_result(self):
155 sock1 = socket.socket()
156 self.addCleanup(sock1.close)
Victor Stinner38227602014-08-27 12:59:44 +0200157 sock1.setblocking(False)
Victor Stinner11517102014-07-29 23:31:34 +0200158 fd1 = sock1.fileno()
159
160 sock2 = socket.socket()
161 self.addCleanup(sock2.close)
Victor Stinner38227602014-08-27 12:59:44 +0200162 sock2.setblocking(False)
Victor Stinner11517102014-07-29 23:31:34 +0200163 fd2 = sock2.fileno()
164
165 signal.set_wakeup_fd(fd1)
Victor Stinnerda565a72014-07-30 10:03:03 +0200166 self.assertEqual(signal.set_wakeup_fd(fd2), fd1)
167 self.assertEqual(signal.set_wakeup_fd(-1), fd2)
168 self.assertEqual(signal.set_wakeup_fd(-1), -1)
Victor Stinner11517102014-07-29 23:31:34 +0200169
Victor Stinner38227602014-08-27 12:59:44 +0200170 # On Windows, files are always blocking and Windows does not provide a
171 # function to test if a socket is in non-blocking mode.
172 @unittest.skipIf(sys.platform == "win32", "tests specific to POSIX")
173 def test_set_wakeup_fd_blocking(self):
174 rfd, wfd = os.pipe()
175 self.addCleanup(os.close, rfd)
176 self.addCleanup(os.close, wfd)
177
178 # fd must be non-blocking
179 os.set_blocking(wfd, True)
180 with self.assertRaises(ValueError) as cm:
181 signal.set_wakeup_fd(wfd)
182 self.assertEqual(str(cm.exception),
183 "the fd %s must be in non-blocking mode" % wfd)
184
185 # non-blocking is ok
186 os.set_blocking(wfd, False)
187 signal.set_wakeup_fd(wfd)
188 signal.set_wakeup_fd(-1)
189
Benjamin Petersonc68a4a02013-01-18 00:10:24 -0500190
Brian Curtin3f004b12010-08-06 19:34:52 +0000191@unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000192class WakeupSignalTests(unittest.TestCase):
Victor Stinner56e8c292014-07-21 12:30:22 +0200193 @unittest.skipIf(_testcapi is None, 'need _testcapi')
Charles-François Natali027f9a32011-10-02 18:36:05 +0200194 def check_wakeup(self, test_body, *signals, ordered=True):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200195 # use a subprocess to have only one thread
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200196 code = """if 1:
Victor Stinner56e8c292014-07-21 12:30:22 +0200197 import _testcapi
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200198 import os
199 import signal
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200200 import struct
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000201
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200202 signals = {!r}
Victor Stinnerc13ef662011-05-25 02:35:58 +0200203
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200204 def handler(signum, frame):
205 pass
206
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200207 def check_signum(signals):
208 data = os.read(read, len(signals)+1)
209 raised = struct.unpack('%uB' % len(data), data)
Charles-François Natali027f9a32011-10-02 18:36:05 +0200210 if not {!r}:
211 raised = set(raised)
212 signals = set(signals)
Victor Stinner0a01f132011-07-04 18:06:35 +0200213 if raised != signals:
214 raise Exception("%r != %r" % (raised, signals))
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200215
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200216 {}
217
218 signal.signal(signal.SIGALRM, handler)
219 read, write = os.pipe()
Victor Stinner1db9e7b2014-07-29 22:32:47 +0200220 os.set_blocking(write, False)
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200221 signal.set_wakeup_fd(write)
222
223 test()
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200224 check_signum(signals)
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200225
226 os.close(read)
227 os.close(write)
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +0200228 """.format(tuple(map(int, signals)), ordered, test_body)
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200229
230 assert_python_ok('-c', code)
Victor Stinnerd49b1f12011-05-08 02:03:15 +0200231
Victor Stinner56e8c292014-07-21 12:30:22 +0200232 @unittest.skipIf(_testcapi is None, 'need _testcapi')
Antoine Pitrou6f6ec372013-08-17 20:27:56 +0200233 def test_wakeup_write_error(self):
234 # Issue #16105: write() errors in the C signal handler should not
235 # pass silently.
236 # Use a subprocess to have only one thread.
237 code = """if 1:
Victor Stinner56e8c292014-07-21 12:30:22 +0200238 import _testcapi
Antoine Pitrou6f6ec372013-08-17 20:27:56 +0200239 import errno
Antoine Pitrou6f6ec372013-08-17 20:27:56 +0200240 import os
241 import signal
242 import sys
Antoine Pitrou6f6ec372013-08-17 20:27:56 +0200243 from test.support import captured_stderr
244
245 def handler(signum, frame):
246 1/0
247
248 signal.signal(signal.SIGALRM, handler)
249 r, w = os.pipe()
Victor Stinner1db9e7b2014-07-29 22:32:47 +0200250 os.set_blocking(r, False)
Antoine Pitrou6f6ec372013-08-17 20:27:56 +0200251
252 # Set wakeup_fd a read-only file descriptor to trigger the error
253 signal.set_wakeup_fd(r)
254 try:
255 with captured_stderr() as err:
Victor Stinner56e8c292014-07-21 12:30:22 +0200256 _testcapi.raise_signal(signal.SIGALRM)
Antoine Pitrou6f6ec372013-08-17 20:27:56 +0200257 except ZeroDivisionError:
258 # An ignored exception should have been printed out on stderr
259 err = err.getvalue()
260 if ('Exception ignored when trying to write to the signal wakeup fd'
261 not in err):
262 raise AssertionError(err)
263 if ('OSError: [Errno %d]' % errno.EBADF) not in err:
264 raise AssertionError(err)
265 else:
266 raise AssertionError("ZeroDivisionError not raised")
Victor Stinner56e8c292014-07-21 12:30:22 +0200267
268 os.close(r)
269 os.close(w)
Antoine Pitrou6f6ec372013-08-17 20:27:56 +0200270 """
Antoine Pitrou8f0bdda2013-08-17 21:43:47 +0200271 r, w = os.pipe()
272 try:
273 os.write(r, b'x')
274 except OSError:
275 pass
276 else:
277 self.skipTest("OS doesn't report write() error on the read end of a pipe")
278 finally:
279 os.close(r)
280 os.close(w)
Antoine Pitrou6f6ec372013-08-17 20:27:56 +0200281
282 assert_python_ok('-c', code)
283
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000284 def test_wakeup_fd_early(self):
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200285 self.check_wakeup("""def test():
286 import select
287 import time
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000288
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200289 TIMEOUT_FULL = 10
290 TIMEOUT_HALF = 5
291
Victor Stinner749a6a82015-03-30 22:09:14 +0200292 class InterruptSelect(Exception):
293 pass
294
295 def handler(signum, frame):
296 raise InterruptSelect
297 signal.signal(signal.SIGALRM, handler)
298
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200299 signal.alarm(1)
Victor Stinner79d68f92015-03-19 21:54:09 +0100300
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200301 # We attempt to get a signal during the sleep,
302 # before select is called
Victor Stinner79d68f92015-03-19 21:54:09 +0100303 try:
304 select.select([], [], [], TIMEOUT_FULL)
Victor Stinner749a6a82015-03-30 22:09:14 +0200305 except InterruptSelect:
Victor Stinner79d68f92015-03-19 21:54:09 +0100306 pass
307 else:
308 raise Exception("select() was not interrupted")
309
310 before_time = time.monotonic()
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200311 select.select([read], [], [], TIMEOUT_FULL)
Victor Stinner79d68f92015-03-19 21:54:09 +0100312 after_time = time.monotonic()
313 dt = after_time - before_time
Victor Stinner0a01f132011-07-04 18:06:35 +0200314 if dt >= TIMEOUT_HALF:
315 raise Exception("%s >= %s" % (dt, TIMEOUT_HALF))
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200316 """, signal.SIGALRM)
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000317
318 def test_wakeup_fd_during(self):
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200319 self.check_wakeup("""def test():
320 import select
321 import time
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000322
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200323 TIMEOUT_FULL = 10
324 TIMEOUT_HALF = 5
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000325
Victor Stinner749a6a82015-03-30 22:09:14 +0200326 class InterruptSelect(Exception):
327 pass
328
329 def handler(signum, frame):
330 raise InterruptSelect
331 signal.signal(signal.SIGALRM, handler)
332
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200333 signal.alarm(1)
Victor Stinner79d68f92015-03-19 21:54:09 +0100334 before_time = time.monotonic()
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200335 # We attempt to get a signal during the select call
336 try:
337 select.select([read], [], [], TIMEOUT_FULL)
Victor Stinner749a6a82015-03-30 22:09:14 +0200338 except InterruptSelect:
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200339 pass
340 else:
Victor Stinner749a6a82015-03-30 22:09:14 +0200341 raise Exception("select() was not interrupted")
Victor Stinner79d68f92015-03-19 21:54:09 +0100342 after_time = time.monotonic()
Victor Stinnere40b3aa2011-07-04 17:35:10 +0200343 dt = after_time - before_time
Victor Stinner0a01f132011-07-04 18:06:35 +0200344 if dt >= TIMEOUT_HALF:
345 raise Exception("%s >= %s" % (dt, TIMEOUT_HALF))
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200346 """, signal.SIGALRM)
Victor Stinnerd49b1f12011-05-08 02:03:15 +0200347
348 def test_signum(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200349 self.check_wakeup("""def test():
Victor Stinner56e8c292014-07-21 12:30:22 +0200350 import _testcapi
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200351 signal.signal(signal.SIGUSR1, handler)
Victor Stinner56e8c292014-07-21 12:30:22 +0200352 _testcapi.raise_signal(signal.SIGUSR1)
353 _testcapi.raise_signal(signal.SIGALRM)
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200354 """, signal.SIGUSR1, signal.SIGALRM)
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000355
Victor Stinnerc13ef662011-05-25 02:35:58 +0200356 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
357 'need signal.pthread_sigmask()')
Victor Stinnerc13ef662011-05-25 02:35:58 +0200358 def test_pending(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200359 self.check_wakeup("""def test():
360 signum1 = signal.SIGUSR1
361 signum2 = signal.SIGUSR2
Victor Stinnerc13ef662011-05-25 02:35:58 +0200362
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200363 signal.signal(signum1, handler)
364 signal.signal(signum2, handler)
Victor Stinnerc13ef662011-05-25 02:35:58 +0200365
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200366 signal.pthread_sigmask(signal.SIG_BLOCK, (signum1, signum2))
Victor Stinner56e8c292014-07-21 12:30:22 +0200367 _testcapi.raise_signal(signum1)
368 _testcapi.raise_signal(signum2)
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200369 # Unblocking the 2 signals calls the C signal handler twice
370 signal.pthread_sigmask(signal.SIG_UNBLOCK, (signum1, signum2))
Charles-François Natali027f9a32011-10-02 18:36:05 +0200371 """, signal.SIGUSR1, signal.SIGUSR2, ordered=False)
Victor Stinnerc13ef662011-05-25 02:35:58 +0200372
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000373
Victor Stinner11517102014-07-29 23:31:34 +0200374@unittest.skipUnless(hasattr(socket, 'socketpair'), 'need socket.socketpair')
375class WakeupSocketSignalTests(unittest.TestCase):
376
377 @unittest.skipIf(_testcapi is None, 'need _testcapi')
378 def test_socket(self):
379 # use a subprocess to have only one thread
380 code = """if 1:
381 import signal
382 import socket
383 import struct
384 import _testcapi
385
386 signum = signal.SIGINT
387 signals = (signum,)
388
389 def handler(signum, frame):
390 pass
391
392 signal.signal(signum, handler)
393
394 read, write = socket.socketpair()
Victor Stinner11517102014-07-29 23:31:34 +0200395 write.setblocking(False)
396 signal.set_wakeup_fd(write.fileno())
397
398 _testcapi.raise_signal(signum)
399
400 data = read.recv(1)
401 if not data:
402 raise Exception("no signum written")
403 raised = struct.unpack('B', data)
404 if raised != signals:
405 raise Exception("%r != %r" % (raised, signals))
406
407 read.close()
408 write.close()
409 """
410
411 assert_python_ok('-c', code)
412
413 @unittest.skipIf(_testcapi is None, 'need _testcapi')
414 def test_send_error(self):
415 # Use a subprocess to have only one thread.
416 if os.name == 'nt':
417 action = 'send'
418 else:
419 action = 'write'
420 code = """if 1:
421 import errno
422 import signal
423 import socket
424 import sys
425 import time
426 import _testcapi
427 from test.support import captured_stderr
428
429 signum = signal.SIGINT
430
431 def handler(signum, frame):
432 pass
433
434 signal.signal(signum, handler)
435
436 read, write = socket.socketpair()
437 read.setblocking(False)
438 write.setblocking(False)
439
440 signal.set_wakeup_fd(write.fileno())
441
442 # Close sockets: send() will fail
443 read.close()
444 write.close()
445
446 with captured_stderr() as err:
447 _testcapi.raise_signal(signum)
448
449 err = err.getvalue()
450 if ('Exception ignored when trying to {action} to the signal wakeup fd'
451 not in err):
452 raise AssertionError(err)
453 """.format(action=action)
454 assert_python_ok('-c', code)
455
Nathaniel J. Smith902ab802017-12-17 20:10:18 -0800456 @unittest.skipIf(_testcapi is None, 'need _testcapi')
457 def test_warn_on_full_buffer(self):
458 # Use a subprocess to have only one thread.
459 if os.name == 'nt':
460 action = 'send'
461 else:
462 action = 'write'
463 code = """if 1:
464 import errno
465 import signal
466 import socket
467 import sys
468 import time
469 import _testcapi
470 from test.support import captured_stderr
471
472 signum = signal.SIGINT
473
474 # This handler will be called, but we intentionally won't read from
475 # the wakeup fd.
476 def handler(signum, frame):
477 pass
478
479 signal.signal(signum, handler)
480
481 read, write = socket.socketpair()
Nathaniel J. Smith902ab802017-12-17 20:10:18 -0800482
Victor Stinner686b4b52018-07-18 18:29:54 +0200483 # Fill the socketpair buffer
484 if sys.platform == 'win32':
485 # bpo-34130: On Windows, sometimes non-blocking send fails to fill
486 # the full socketpair buffer, so use a timeout of 50 ms instead.
487 write.settimeout(0.050)
488 else:
489 write.setblocking(False)
490
491 # Start with large chunk size to reduce the
492 # number of send needed to fill the buffer.
493 written = 0
494 for chunk_size in (2 ** 16, 2 ** 8, 1):
495 chunk = b"x" * chunk_size
496 try:
497 while True:
498 write.send(chunk)
499 written += chunk_size
500 except (BlockingIOError, socket.timeout):
501 pass
502
503 print(f"%s bytes written into the socketpair" % written, flush=True)
504
505 write.setblocking(False)
Nathaniel J. Smith902ab802017-12-17 20:10:18 -0800506 try:
Victor Stinner686b4b52018-07-18 18:29:54 +0200507 write.send(b"x")
Nathaniel J. Smith902ab802017-12-17 20:10:18 -0800508 except BlockingIOError:
Victor Stinner686b4b52018-07-18 18:29:54 +0200509 # The socketpair buffer seems full
Nathaniel J. Smith902ab802017-12-17 20:10:18 -0800510 pass
Victor Stinner686b4b52018-07-18 18:29:54 +0200511 else:
512 raise AssertionError("%s bytes failed to fill the socketpair "
513 "buffer" % written)
Nathaniel J. Smith902ab802017-12-17 20:10:18 -0800514
515 # By default, we get a warning when a signal arrives
Victor Stinner686b4b52018-07-18 18:29:54 +0200516 msg = ('Exception ignored when trying to {action} '
517 'to the signal wakeup fd')
Nathaniel J. Smith902ab802017-12-17 20:10:18 -0800518 signal.set_wakeup_fd(write.fileno())
519
520 with captured_stderr() as err:
521 _testcapi.raise_signal(signum)
522
523 err = err.getvalue()
Victor Stinner686b4b52018-07-18 18:29:54 +0200524 if msg not in err:
525 raise AssertionError("first set_wakeup_fd() test failed, "
526 "stderr: %r" % err)
Nathaniel J. Smith902ab802017-12-17 20:10:18 -0800527
528 # And also if warn_on_full_buffer=True
529 signal.set_wakeup_fd(write.fileno(), warn_on_full_buffer=True)
530
531 with captured_stderr() as err:
532 _testcapi.raise_signal(signum)
533
534 err = err.getvalue()
Victor Stinner686b4b52018-07-18 18:29:54 +0200535 if msg not in err:
536 raise AssertionError("set_wakeup_fd(warn_on_full_buffer=True) "
537 "test failed, stderr: %r" % err)
Nathaniel J. Smith902ab802017-12-17 20:10:18 -0800538
539 # But not if warn_on_full_buffer=False
540 signal.set_wakeup_fd(write.fileno(), warn_on_full_buffer=False)
541
542 with captured_stderr() as err:
543 _testcapi.raise_signal(signum)
544
545 err = err.getvalue()
546 if err != "":
Victor Stinner686b4b52018-07-18 18:29:54 +0200547 raise AssertionError("set_wakeup_fd(warn_on_full_buffer=False) "
548 "test failed, stderr: %r" % err)
Nathaniel J. Smith902ab802017-12-17 20:10:18 -0800549
550 # And then check the default again, to make sure warn_on_full_buffer
551 # settings don't leak across calls.
552 signal.set_wakeup_fd(write.fileno())
553
554 with captured_stderr() as err:
555 _testcapi.raise_signal(signum)
556
557 err = err.getvalue()
Victor Stinner686b4b52018-07-18 18:29:54 +0200558 if msg not in err:
559 raise AssertionError("second set_wakeup_fd() test failed, "
560 "stderr: %r" % err)
Nathaniel J. Smith902ab802017-12-17 20:10:18 -0800561
562 """.format(action=action)
563 assert_python_ok('-c', code)
564
Victor Stinner11517102014-07-29 23:31:34 +0200565
Brian Curtin3f004b12010-08-06 19:34:52 +0000566@unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
Christian Heimes8640e742008-02-23 16:23:06 +0000567class SiginterruptTest(unittest.TestCase):
Jean-Paul Calderone9c39bc72010-05-09 03:25:16 +0000568
Victor Stinnerd6284962011-06-20 23:28:09 +0200569 def readpipe_interrupted(self, interrupt):
Jean-Paul Calderone9c39bc72010-05-09 03:25:16 +0000570 """Perform a read during which a signal will arrive. Return True if the
571 read is interrupted by the signal and raises an exception. Return False
572 if it returns normally.
573 """
Victor Stinnerd6284962011-06-20 23:28:09 +0200574 # use a subprocess to have only one thread, to have a timeout on the
575 # blocking read and to not touch signal handling in this process
576 code = """if 1:
577 import errno
578 import os
579 import signal
580 import sys
Jean-Paul Calderone9c39bc72010-05-09 03:25:16 +0000581
Victor Stinnerd6284962011-06-20 23:28:09 +0200582 interrupt = %r
583 r, w = os.pipe()
Christian Heimes8640e742008-02-23 16:23:06 +0000584
Victor Stinnerd6284962011-06-20 23:28:09 +0200585 def handler(signum, frame):
Charles-François Natali6e6c59b2015-02-07 13:27:50 +0000586 1 / 0
Victor Stinnerd6284962011-06-20 23:28:09 +0200587
588 signal.signal(signal.SIGALRM, handler)
589 if interrupt is not None:
590 signal.siginterrupt(signal.SIGALRM, interrupt)
591
Victor Stinnerdfde0d42011-07-01 15:58:39 +0200592 print("ready")
593 sys.stdout.flush()
594
Victor Stinnerd6284962011-06-20 23:28:09 +0200595 # run the test twice
Victor Stinner56e8c292014-07-21 12:30:22 +0200596 try:
597 for loop in range(2):
598 # send a SIGALRM in a second (during the read)
599 signal.alarm(1)
600 try:
601 # blocking call: read from a pipe without data
602 os.read(r, 1)
Charles-François Natali6e6c59b2015-02-07 13:27:50 +0000603 except ZeroDivisionError:
604 pass
Victor Stinner56e8c292014-07-21 12:30:22 +0200605 else:
606 sys.exit(2)
607 sys.exit(3)
608 finally:
609 os.close(r)
610 os.close(w)
Victor Stinnerd6284962011-06-20 23:28:09 +0200611 """ % (interrupt,)
612 with spawn_python('-c', code) as process:
Christian Heimes8640e742008-02-23 16:23:06 +0000613 try:
Victor Stinner45273652011-06-22 22:15:51 +0200614 # wait until the child process is loaded and has started
615 first_line = process.stdout.readline()
616
Victor Stinner19e5bcd2011-07-01 15:59:54 +0200617 stdout, stderr = process.communicate(timeout=5.0)
Victor Stinnerd6284962011-06-20 23:28:09 +0200618 except subprocess.TimeoutExpired:
619 process.kill()
Christian Heimes8640e742008-02-23 16:23:06 +0000620 return False
Victor Stinnerd6284962011-06-20 23:28:09 +0200621 else:
Victor Stinner45273652011-06-22 22:15:51 +0200622 stdout = first_line + stdout
Victor Stinnerd6284962011-06-20 23:28:09 +0200623 exitcode = process.wait()
624 if exitcode not in (2, 3):
Antoine Pitroudab4e8a2014-05-11 19:05:23 +0200625 raise Exception("Child error (exit code %s): %r"
Victor Stinnerd6284962011-06-20 23:28:09 +0200626 % (exitcode, stdout))
627 return (exitcode == 3)
Christian Heimes8640e742008-02-23 16:23:06 +0000628
629 def test_without_siginterrupt(self):
Victor Stinner3a7f0f02011-05-08 02:10:36 +0200630 # If a signal handler is installed and siginterrupt is not called
631 # at all, when that signal arrives, it interrupts a syscall that's in
632 # progress.
Victor Stinnerd6284962011-06-20 23:28:09 +0200633 interrupted = self.readpipe_interrupted(None)
634 self.assertTrue(interrupted)
Christian Heimes8640e742008-02-23 16:23:06 +0000635
636 def test_siginterrupt_on(self):
Victor Stinner3a7f0f02011-05-08 02:10:36 +0200637 # If a signal handler is installed and siginterrupt is called with
638 # a true value for the second argument, when that signal arrives, it
639 # interrupts a syscall that's in progress.
Victor Stinnerd6284962011-06-20 23:28:09 +0200640 interrupted = self.readpipe_interrupted(True)
641 self.assertTrue(interrupted)
Christian Heimes8640e742008-02-23 16:23:06 +0000642
643 def test_siginterrupt_off(self):
Victor Stinner3a7f0f02011-05-08 02:10:36 +0200644 # If a signal handler is installed and siginterrupt is called with
645 # a false value for the second argument, when that signal arrives, it
646 # does not interrupt a syscall that's in progress.
Victor Stinnerd6284962011-06-20 23:28:09 +0200647 interrupted = self.readpipe_interrupted(False)
648 self.assertFalse(interrupted)
Jean-Paul Calderone9c39bc72010-05-09 03:25:16 +0000649
650
Brian Curtin3f004b12010-08-06 19:34:52 +0000651@unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
Martin v. Löwis823725e2008-03-24 13:39:54 +0000652class ItimerTest(unittest.TestCase):
653 def setUp(self):
654 self.hndl_called = False
655 self.hndl_count = 0
656 self.itimer = None
Christian Heimescc47b052008-03-25 14:56:36 +0000657 self.old_alarm = signal.signal(signal.SIGALRM, self.sig_alrm)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000658
659 def tearDown(self):
Christian Heimescc47b052008-03-25 14:56:36 +0000660 signal.signal(signal.SIGALRM, self.old_alarm)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000661 if self.itimer is not None: # test_itimer_exc doesn't change this attr
662 # just ensure that itimer is stopped
663 signal.setitimer(self.itimer, 0)
664
665 def sig_alrm(self, *args):
666 self.hndl_called = True
Martin v. Löwis823725e2008-03-24 13:39:54 +0000667
668 def sig_vtalrm(self, *args):
669 self.hndl_called = True
670
671 if self.hndl_count > 3:
672 # it shouldn't be here, because it should have been disabled.
673 raise signal.ItimerError("setitimer didn't disable ITIMER_VIRTUAL "
674 "timer.")
675 elif self.hndl_count == 3:
676 # disable ITIMER_VIRTUAL, this function shouldn't be called anymore
677 signal.setitimer(signal.ITIMER_VIRTUAL, 0)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000678
679 self.hndl_count += 1
680
Martin v. Löwis823725e2008-03-24 13:39:54 +0000681 def sig_prof(self, *args):
682 self.hndl_called = True
683 signal.setitimer(signal.ITIMER_PROF, 0)
684
Martin v. Löwis823725e2008-03-24 13:39:54 +0000685 def test_itimer_exc(self):
686 # XXX I'm assuming -1 is an invalid itimer, but maybe some platform
687 # defines it ?
688 self.assertRaises(signal.ItimerError, signal.setitimer, -1, 0)
Christian Heimescc47b052008-03-25 14:56:36 +0000689 # Negative times are treated as zero on some platforms.
690 if 0:
691 self.assertRaises(signal.ItimerError,
692 signal.setitimer, signal.ITIMER_REAL, -1)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000693
694 def test_itimer_real(self):
695 self.itimer = signal.ITIMER_REAL
Martin v. Löwis823725e2008-03-24 13:39:54 +0000696 signal.setitimer(self.itimer, 1.0)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000697 signal.pause()
Martin v. Löwis823725e2008-03-24 13:39:54 +0000698 self.assertEqual(self.hndl_called, True)
699
R. David Murray44546f82010-04-21 01:59:28 +0000700 # Issue 3864, unknown if this affects earlier versions of freebsd also
Victor Stinner13ff2452018-01-22 18:32:50 +0100701 @unittest.skipIf(sys.platform in ('netbsd5',),
Gregory P. Smith397cd8a2010-10-17 04:23:21 +0000702 'itimer not reliable (does not mix well with threading) on some BSDs.')
Martin v. Löwis823725e2008-03-24 13:39:54 +0000703 def test_itimer_virtual(self):
704 self.itimer = signal.ITIMER_VIRTUAL
705 signal.signal(signal.SIGVTALRM, self.sig_vtalrm)
706 signal.setitimer(self.itimer, 0.3, 0.2)
707
Victor Stinner79d68f92015-03-19 21:54:09 +0100708 start_time = time.monotonic()
709 while time.monotonic() - start_time < 60.0:
Mark Dickinson95078872009-10-04 18:47:48 +0000710 # use up some virtual time by doing real work
711 _ = pow(12345, 67890, 10000019)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000712 if signal.getitimer(self.itimer) == (0.0, 0.0):
713 break # sig_vtalrm handler stopped this itimer
Stefan Krahf1da973042010-04-20 08:15:14 +0000714 else: # Issue 8424
Benjamin Peterson9b140f62010-05-15 18:00:56 +0000715 self.skipTest("timeout: likely cause: machine too slow or load too "
716 "high")
Martin v. Löwis823725e2008-03-24 13:39:54 +0000717
718 # virtual itimer should be (0.0, 0.0) now
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000719 self.assertEqual(signal.getitimer(self.itimer), (0.0, 0.0))
Martin v. Löwis823725e2008-03-24 13:39:54 +0000720 # and the handler should have been called
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000721 self.assertEqual(self.hndl_called, True)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000722
723 def test_itimer_prof(self):
724 self.itimer = signal.ITIMER_PROF
725 signal.signal(signal.SIGPROF, self.sig_prof)
Neal Norwitzf5c7c2e2008-04-05 04:47:45 +0000726 signal.setitimer(self.itimer, 0.2, 0.2)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000727
Victor Stinner79d68f92015-03-19 21:54:09 +0100728 start_time = time.monotonic()
729 while time.monotonic() - start_time < 60.0:
Mark Dickinson78373472009-10-31 10:39:21 +0000730 # do some work
731 _ = pow(12345, 67890, 10000019)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000732 if signal.getitimer(self.itimer) == (0.0, 0.0):
733 break # sig_prof handler stopped this itimer
Stefan Krahf1da973042010-04-20 08:15:14 +0000734 else: # Issue 8424
Benjamin Peterson9b140f62010-05-15 18:00:56 +0000735 self.skipTest("timeout: likely cause: machine too slow or load too "
736 "high")
Martin v. Löwis823725e2008-03-24 13:39:54 +0000737
Neal Norwitzf5c7c2e2008-04-05 04:47:45 +0000738 # profiling itimer should be (0.0, 0.0) now
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000739 self.assertEqual(signal.getitimer(self.itimer), (0.0, 0.0))
Neal Norwitzf5c7c2e2008-04-05 04:47:45 +0000740 # and the handler should have been called
Martin v. Löwis823725e2008-03-24 13:39:54 +0000741 self.assertEqual(self.hndl_called, True)
742
Antoine Pitrou729780a2017-06-30 10:01:05 +0200743 def test_setitimer_tiny(self):
744 # bpo-30807: C setitimer() takes a microsecond-resolution interval.
745 # Check that float -> timeval conversion doesn't round
746 # the interval down to zero, which would disable the timer.
747 self.itimer = signal.ITIMER_REAL
748 signal.setitimer(self.itimer, 1e-6)
749 time.sleep(1)
750 self.assertEqual(self.hndl_called, True)
751
Victor Stinnera9293352011-04-30 15:21:58 +0200752
Victor Stinner35b300c2011-05-04 13:20:35 +0200753class PendingSignalsTests(unittest.TestCase):
754 """
Victor Stinnerb3e72192011-05-08 01:46:11 +0200755 Test pthread_sigmask(), pthread_kill(), sigpending() and sigwait()
756 functions.
Victor Stinner35b300c2011-05-04 13:20:35 +0200757 """
Victor Stinnerb3e72192011-05-08 01:46:11 +0200758 @unittest.skipUnless(hasattr(signal, 'sigpending'),
759 'need signal.sigpending()')
760 def test_sigpending_empty(self):
761 self.assertEqual(signal.sigpending(), set())
762
763 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
764 'need signal.pthread_sigmask()')
765 @unittest.skipUnless(hasattr(signal, 'sigpending'),
766 'need signal.sigpending()')
767 def test_sigpending(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200768 code = """if 1:
769 import os
770 import signal
Victor Stinnerb3e72192011-05-08 01:46:11 +0200771
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200772 def handler(signum, frame):
773 1/0
Victor Stinnerb3e72192011-05-08 01:46:11 +0200774
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200775 signum = signal.SIGUSR1
776 signal.signal(signum, handler)
777
778 signal.pthread_sigmask(signal.SIG_BLOCK, [signum])
779 os.kill(os.getpid(), signum)
780 pending = signal.sigpending()
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +0200781 for sig in pending:
782 assert isinstance(sig, signal.Signals), repr(pending)
Victor Stinner0a01f132011-07-04 18:06:35 +0200783 if pending != {signum}:
784 raise Exception('%s != {%s}' % (pending, signum))
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200785 try:
786 signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum])
787 except ZeroDivisionError:
788 pass
789 else:
790 raise Exception("ZeroDivisionError not raised")
791 """
792 assert_python_ok('-c', code)
Victor Stinnerb3e72192011-05-08 01:46:11 +0200793
794 @unittest.skipUnless(hasattr(signal, 'pthread_kill'),
795 'need signal.pthread_kill()')
796 def test_pthread_kill(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200797 code = """if 1:
798 import signal
799 import threading
800 import sys
Victor Stinnerb3e72192011-05-08 01:46:11 +0200801
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200802 signum = signal.SIGUSR1
Victor Stinnerb3e72192011-05-08 01:46:11 +0200803
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200804 def handler(signum, frame):
805 1/0
806
807 signal.signal(signum, handler)
808
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200809 tid = threading.get_ident()
810 try:
811 signal.pthread_kill(tid, signum)
812 except ZeroDivisionError:
813 pass
814 else:
815 raise Exception("ZeroDivisionError not raised")
816 """
817 assert_python_ok('-c', code)
Victor Stinnerb3e72192011-05-08 01:46:11 +0200818
Victor Stinner7f294d12011-06-10 14:02:10 +0200819 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
820 'need signal.pthread_sigmask()')
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200821 def wait_helper(self, blocked, test):
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200822 """
823 test: body of the "def test(signum):" function.
824 blocked: number of the blocked signal
825 """
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200826 code = '''if 1:
827 import signal
828 import sys
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +0200829 from signal import Signals
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200830
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200831 def handler(signum, frame):
832 1/0
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200833
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200834 %s
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200835
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200836 blocked = %s
837 signum = signal.SIGALRM
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200838
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200839 # child: block and wait the signal
840 try:
841 signal.signal(signum, handler)
842 signal.pthread_sigmask(signal.SIG_BLOCK, [blocked])
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200843
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200844 # Do the tests
845 test(signum)
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200846
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200847 # The handler must not be called on unblock
848 try:
849 signal.pthread_sigmask(signal.SIG_UNBLOCK, [blocked])
850 except ZeroDivisionError:
851 print("the signal handler has been called",
852 file=sys.stderr)
853 sys.exit(1)
854 except BaseException as err:
855 print("error: {}".format(err), file=sys.stderr)
856 sys.stderr.flush()
857 sys.exit(1)
858 ''' % (test.strip(), blocked)
Victor Stinner415007e2011-06-13 16:19:06 +0200859
Ross Lagerwallbc808222011-06-25 12:13:40 +0200860 # sig*wait* must be called with the signal blocked: since the current
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200861 # process might have several threads running, use a subprocess to have
862 # a single thread.
863 assert_python_ok('-c', code)
Victor Stinneraf494602011-06-10 12:48:13 +0200864
Victor Stinnerb3e72192011-05-08 01:46:11 +0200865 @unittest.skipUnless(hasattr(signal, 'sigwait'),
866 'need signal.sigwait()')
Ross Lagerwallbc808222011-06-25 12:13:40 +0200867 def test_sigwait(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200868 self.wait_helper(signal.SIGALRM, '''
869 def test(signum):
Ross Lagerwallbc808222011-06-25 12:13:40 +0200870 signal.alarm(1)
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200871 received = signal.sigwait([signum])
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +0200872 assert isinstance(received, signal.Signals), received
Victor Stinner0a01f132011-07-04 18:06:35 +0200873 if received != signum:
874 raise Exception('received %s, not %s' % (received, signum))
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200875 ''')
Ross Lagerwallbc808222011-06-25 12:13:40 +0200876
877 @unittest.skipUnless(hasattr(signal, 'sigwaitinfo'),
878 'need signal.sigwaitinfo()')
879 def test_sigwaitinfo(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200880 self.wait_helper(signal.SIGALRM, '''
881 def test(signum):
Ross Lagerwallbc808222011-06-25 12:13:40 +0200882 signal.alarm(1)
883 info = signal.sigwaitinfo([signum])
Victor Stinner0a01f132011-07-04 18:06:35 +0200884 if info.si_signo != signum:
885 raise Exception("info.si_signo != %s" % signum)
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(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200891 self.wait_helper(signal.SIGALRM, '''
892 def test(signum):
Ross Lagerwallbc808222011-06-25 12:13:40 +0200893 signal.alarm(1)
Victor Stinner643cd682012-03-02 22:54:03 +0100894 info = signal.sigtimedwait([signum], 10.1000)
Victor Stinner0a01f132011-07-04 18:06:35 +0200895 if info.si_signo != signum:
896 raise Exception('info.si_signo != %s' % signum)
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200897 ''')
Ross Lagerwallbc808222011-06-25 12:13:40 +0200898
Ross Lagerwallbc808222011-06-25 12:13:40 +0200899 @unittest.skipUnless(hasattr(signal, 'sigtimedwait'),
900 'need signal.sigtimedwait()')
901 def test_sigtimedwait_poll(self):
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200902 # check that polling with sigtimedwait works
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200903 self.wait_helper(signal.SIGALRM, '''
904 def test(signum):
Victor Stinner9e8b82f2011-06-29 10:43:02 +0200905 import os
906 os.kill(os.getpid(), signum)
Victor Stinner643cd682012-03-02 22:54:03 +0100907 info = signal.sigtimedwait([signum], 0)
Victor Stinner0a01f132011-07-04 18:06:35 +0200908 if info.si_signo != signum:
909 raise Exception('info.si_signo != %s' % signum)
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200910 ''')
Ross Lagerwallbc808222011-06-25 12:13:40 +0200911
912 @unittest.skipUnless(hasattr(signal, 'sigtimedwait'),
913 'need signal.sigtimedwait()')
914 def test_sigtimedwait_timeout(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200915 self.wait_helper(signal.SIGALRM, '''
916 def test(signum):
Victor Stinner643cd682012-03-02 22:54:03 +0100917 received = signal.sigtimedwait([signum], 1.0)
Victor Stinner0a01f132011-07-04 18:06:35 +0200918 if received is not None:
919 raise Exception("received=%r" % (received,))
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200920 ''')
Ross Lagerwallbc808222011-06-25 12:13:40 +0200921
922 @unittest.skipUnless(hasattr(signal, 'sigtimedwait'),
923 'need signal.sigtimedwait()')
924 def test_sigtimedwait_negative_timeout(self):
925 signum = signal.SIGALRM
Victor Stinner643cd682012-03-02 22:54:03 +0100926 self.assertRaises(ValueError, signal.sigtimedwait, [signum], -1.0)
Ross Lagerwallbc808222011-06-25 12:13:40 +0200927
Ross Lagerwallbc808222011-06-25 12:13:40 +0200928 @unittest.skipUnless(hasattr(signal, 'sigwait'),
929 'need signal.sigwait()')
Victor Stinner415007e2011-06-13 16:19:06 +0200930 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
931 'need signal.pthread_sigmask()')
Victor Stinner10c30d62011-06-10 01:39:53 +0200932 def test_sigwait_thread(self):
Victor Stinner415007e2011-06-13 16:19:06 +0200933 # Check that calling sigwait() from a thread doesn't suspend the whole
934 # process. A new interpreter is spawned to avoid problems when mixing
935 # threads and fork(): only async-safe functions are allowed between
936 # fork() and exec().
937 assert_python_ok("-c", """if True:
938 import os, threading, sys, time, signal
Victor Stinner10c30d62011-06-10 01:39:53 +0200939
Victor Stinner415007e2011-06-13 16:19:06 +0200940 # the default handler terminates the process
941 signum = signal.SIGUSR1
942
943 def kill_later():
944 # wait until the main thread is waiting in sigwait()
945 time.sleep(1)
946 os.kill(os.getpid(), signum)
947
948 # the signal must be blocked by all the threads
949 signal.pthread_sigmask(signal.SIG_BLOCK, [signum])
950 killer = threading.Thread(target=kill_later)
Victor Stinneraf494602011-06-10 12:48:13 +0200951 killer.start()
952 received = signal.sigwait([signum])
953 if received != signum:
954 print("sigwait() received %s, not %s" % (received, signum),
955 file=sys.stderr)
Victor Stinner415007e2011-06-13 16:19:06 +0200956 sys.exit(1)
Victor Stinner10c30d62011-06-10 01:39:53 +0200957 killer.join()
Victor Stinner415007e2011-06-13 16:19:06 +0200958 # unblock the signal, which should have been cleared by sigwait()
959 signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum])
960 """)
Victor Stinneraf494602011-06-10 12:48:13 +0200961
Victor Stinnerb3e72192011-05-08 01:46:11 +0200962 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
963 'need signal.pthread_sigmask()')
964 def test_pthread_sigmask_arguments(self):
965 self.assertRaises(TypeError, signal.pthread_sigmask)
966 self.assertRaises(TypeError, signal.pthread_sigmask, 1)
967 self.assertRaises(TypeError, signal.pthread_sigmask, 1, 2, 3)
968 self.assertRaises(OSError, signal.pthread_sigmask, 1700, [])
Antoine Pitrou9d3627e2018-05-04 13:00:50 +0200969 with self.assertRaises(ValueError):
970 signal.pthread_sigmask(signal.SIG_BLOCK, [signal.NSIG])
Serhiy Storchakad54cfb12018-05-08 07:48:50 +0300971 with self.assertRaises(ValueError):
972 signal.pthread_sigmask(signal.SIG_BLOCK, [0])
973 with self.assertRaises(ValueError):
974 signal.pthread_sigmask(signal.SIG_BLOCK, [1<<1000])
Antoine Pitrou9d3627e2018-05-04 13:00:50 +0200975
976 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
977 'need signal.pthread_sigmask()')
978 def test_pthread_sigmask_valid_signals(self):
979 s = signal.pthread_sigmask(signal.SIG_BLOCK, signal.valid_signals())
980 self.addCleanup(signal.pthread_sigmask, signal.SIG_SETMASK, s)
981 # Get current blocked set
982 s = signal.pthread_sigmask(signal.SIG_UNBLOCK, signal.valid_signals())
983 self.assertLessEqual(s, signal.valid_signals())
Victor Stinnerb3e72192011-05-08 01:46:11 +0200984
985 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
986 'need signal.pthread_sigmask()')
987 def test_pthread_sigmask(self):
Victor Stinnerd554cdf2011-07-04 17:49:40 +0200988 code = """if 1:
989 import signal
990 import os; import threading
991
992 def handler(signum, frame):
993 1/0
994
995 def kill(signum):
996 os.kill(os.getpid(), signum)
997
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +0200998 def check_mask(mask):
999 for sig in mask:
1000 assert isinstance(sig, signal.Signals), repr(sig)
1001
Victor Stinnerd554cdf2011-07-04 17:49:40 +02001002 def read_sigmask():
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +02001003 sigmask = signal.pthread_sigmask(signal.SIG_BLOCK, [])
1004 check_mask(sigmask)
1005 return sigmask
Victor Stinnerd554cdf2011-07-04 17:49:40 +02001006
Victor Stinnerb3e72192011-05-08 01:46:11 +02001007 signum = signal.SIGUSR1
Victor Stinner6fd49e12011-05-04 12:38:03 +02001008
Victor Stinnerd0e516d2011-05-03 14:57:12 +02001009 # Install our signal handler
Victor Stinnerd554cdf2011-07-04 17:49:40 +02001010 old_handler = signal.signal(signum, handler)
Victor Stinnera9293352011-04-30 15:21:58 +02001011
Victor Stinnerd0e516d2011-05-03 14:57:12 +02001012 # Unblock SIGUSR1 (and copy the old mask) to test our signal handler
Victor Stinnera9293352011-04-30 15:21:58 +02001013 old_mask = signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum])
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +02001014 check_mask(old_mask)
Victor Stinnerd554cdf2011-07-04 17:49:40 +02001015 try:
1016 kill(signum)
1017 except ZeroDivisionError:
1018 pass
1019 else:
1020 raise Exception("ZeroDivisionError not raised")
Victor Stinnera9293352011-04-30 15:21:58 +02001021
Victor Stinnerd0e516d2011-05-03 14:57:12 +02001022 # Block and then raise SIGUSR1. The signal is blocked: the signal
1023 # handler is not called, and the signal is now pending
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +02001024 mask = signal.pthread_sigmask(signal.SIG_BLOCK, [signum])
1025 check_mask(mask)
Victor Stinnerd554cdf2011-07-04 17:49:40 +02001026 kill(signum)
Victor Stinnera9293352011-04-30 15:21:58 +02001027
Victor Stinnerd0e516d2011-05-03 14:57:12 +02001028 # Check the new mask
Victor Stinnerd554cdf2011-07-04 17:49:40 +02001029 blocked = read_sigmask()
Giampaolo Rodola'e09fb712014-04-04 15:34:17 +02001030 check_mask(blocked)
Victor Stinner0a01f132011-07-04 18:06:35 +02001031 if signum not in blocked:
1032 raise Exception("%s not in %s" % (signum, blocked))
1033 if old_mask ^ blocked != {signum}:
1034 raise Exception("%s ^ %s != {%s}" % (old_mask, blocked, signum))
Victor Stinnera9293352011-04-30 15:21:58 +02001035
Victor Stinnerd0e516d2011-05-03 14:57:12 +02001036 # Unblock SIGUSR1
Victor Stinnerd554cdf2011-07-04 17:49:40 +02001037 try:
R David Murrayfc069992013-12-13 20:52:19 -05001038 # unblock the pending signal calls immediately the signal handler
Victor Stinnerd0e516d2011-05-03 14:57:12 +02001039 signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum])
Victor Stinnerd554cdf2011-07-04 17:49:40 +02001040 except ZeroDivisionError:
1041 pass
1042 else:
1043 raise Exception("ZeroDivisionError not raised")
1044 try:
1045 kill(signum)
1046 except ZeroDivisionError:
1047 pass
1048 else:
1049 raise Exception("ZeroDivisionError not raised")
Victor Stinnera9293352011-04-30 15:21:58 +02001050
Victor Stinnerd0e516d2011-05-03 14:57:12 +02001051 # Check the new mask
Victor Stinnerd554cdf2011-07-04 17:49:40 +02001052 unblocked = read_sigmask()
Victor Stinner0a01f132011-07-04 18:06:35 +02001053 if signum in unblocked:
1054 raise Exception("%s in %s" % (signum, unblocked))
1055 if blocked ^ unblocked != {signum}:
1056 raise Exception("%s ^ %s != {%s}" % (blocked, unblocked, signum))
1057 if old_mask != unblocked:
1058 raise Exception("%s != %s" % (old_mask, unblocked))
Victor Stinnerd554cdf2011-07-04 17:49:40 +02001059 """
1060 assert_python_ok('-c', code)
1061
Victor Stinnerd554cdf2011-07-04 17:49:40 +02001062 @unittest.skipUnless(hasattr(signal, 'pthread_kill'),
1063 'need signal.pthread_kill()')
1064 def test_pthread_kill_main_thread(self):
1065 # Test that a signal can be sent to the main thread with pthread_kill()
1066 # before any other thread has been created (see issue #12392).
1067 code = """if True:
1068 import threading
1069 import signal
1070 import sys
1071
1072 def handler(signum, frame):
1073 sys.exit(3)
1074
1075 signal.signal(signal.SIGUSR1, handler)
1076 signal.pthread_kill(threading.get_ident(), signal.SIGUSR1)
1077 sys.exit(2)
1078 """
1079
1080 with spawn_python('-c', code) as process:
1081 stdout, stderr = process.communicate()
1082 exitcode = process.wait()
1083 if exitcode != 3:
1084 raise Exception("Child error (exit code %s): %s" %
1085 (exitcode, stdout))
Victor Stinnera9293352011-04-30 15:21:58 +02001086
1087
Antoine Pitrouc08177a2017-06-28 23:29:29 +02001088class StressTest(unittest.TestCase):
1089 """
1090 Stress signal delivery, especially when a signal arrives in
1091 the middle of recomputing the signal state or executing
1092 previously tripped signal handlers.
1093 """
1094
Antoine Pitrouf7d090c2017-06-29 16:40:14 +02001095 def setsig(self, signum, handler):
1096 old_handler = signal.signal(signum, handler)
1097 self.addCleanup(signal.signal, signum, old_handler)
1098
1099 def measure_itimer_resolution(self):
1100 N = 20
1101 times = []
1102
1103 def handler(signum=None, frame=None):
1104 if len(times) < N:
1105 times.append(time.perf_counter())
1106 # 1 µs is the smallest possible timer interval,
1107 # we want to measure what the concrete duration
1108 # will be on this platform
1109 signal.setitimer(signal.ITIMER_REAL, 1e-6)
1110
1111 self.addCleanup(signal.setitimer, signal.ITIMER_REAL, 0)
1112 self.setsig(signal.SIGALRM, handler)
1113 handler()
1114 while len(times) < N:
1115 time.sleep(1e-3)
1116
1117 durations = [times[i+1] - times[i] for i in range(len(times) - 1)]
1118 med = statistics.median(durations)
1119 if support.verbose:
1120 print("detected median itimer() resolution: %.6f s." % (med,))
1121 return med
1122
1123 def decide_itimer_count(self):
1124 # Some systems have poor setitimer() resolution (for example
1125 # measured around 20 ms. on FreeBSD 9), so decide on a reasonable
1126 # number of sequential timers based on that.
1127 reso = self.measure_itimer_resolution()
1128 if reso <= 1e-4:
1129 return 10000
1130 elif reso <= 1e-2:
1131 return 100
1132 else:
1133 self.skipTest("detected itimer resolution (%.3f s.) too high "
1134 "(> 10 ms.) on this platform (or system too busy)"
1135 % (reso,))
1136
Antoine Pitrouc08177a2017-06-28 23:29:29 +02001137 @unittest.skipUnless(hasattr(signal, "setitimer"),
1138 "test needs setitimer()")
1139 def test_stress_delivery_dependent(self):
1140 """
1141 This test uses dependent 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 first_handler(signum, frame):
1147 # 1e-6 is the minimum non-zero value for `setitimer()`.
1148 # Choose a random delay so as to improve chances of
1149 # triggering a race condition. Ideally the signal is received
1150 # when inside critical signal-handling routines such as
1151 # Py_MakePendingCalls().
1152 signal.setitimer(signal.ITIMER_REAL, 1e-6 + random.random() * 1e-5)
1153
1154 def second_handler(signum=None, frame=None):
1155 sigs.append(signum)
1156
Antoine Pitrouc08177a2017-06-28 23:29:29 +02001157 # Here on Linux, SIGPROF > SIGALRM > SIGUSR1. By using both
1158 # ascending and descending sequences (SIGUSR1 then SIGALRM,
1159 # SIGPROF then SIGALRM), we maximize chances of hitting a bug.
Antoine Pitrouf7d090c2017-06-29 16:40:14 +02001160 self.setsig(signal.SIGPROF, first_handler)
1161 self.setsig(signal.SIGUSR1, first_handler)
1162 self.setsig(signal.SIGALRM, second_handler) # for ITIMER_REAL
Antoine Pitrouc08177a2017-06-28 23:29:29 +02001163
1164 expected_sigs = 0
1165 deadline = time.time() + 15.0
1166
1167 while expected_sigs < N:
1168 os.kill(os.getpid(), signal.SIGPROF)
1169 expected_sigs += 1
1170 # Wait for handlers to run to avoid signal coalescing
1171 while len(sigs) < expected_sigs and time.time() < deadline:
1172 time.sleep(1e-5)
1173
1174 os.kill(os.getpid(), signal.SIGUSR1)
1175 expected_sigs += 1
1176 while len(sigs) < expected_sigs and time.time() < deadline:
1177 time.sleep(1e-5)
1178
1179 # All ITIMER_REAL signals should have been delivered to the
1180 # Python handler
1181 self.assertEqual(len(sigs), N, "Some signals were lost")
1182
1183 @unittest.skipUnless(hasattr(signal, "setitimer"),
1184 "test needs setitimer()")
1185 def test_stress_delivery_simultaneous(self):
1186 """
1187 This test uses simultaneous signal handlers.
1188 """
Antoine Pitrouf7d090c2017-06-29 16:40:14 +02001189 N = self.decide_itimer_count()
Antoine Pitrouc08177a2017-06-28 23:29:29 +02001190 sigs = []
1191
1192 def handler(signum, frame):
1193 sigs.append(signum)
1194
Antoine Pitrouf7d090c2017-06-29 16:40:14 +02001195 self.setsig(signal.SIGUSR1, handler)
1196 self.setsig(signal.SIGALRM, handler) # for ITIMER_REAL
Antoine Pitrouc08177a2017-06-28 23:29:29 +02001197
1198 expected_sigs = 0
1199 deadline = time.time() + 15.0
1200
1201 while expected_sigs < N:
1202 # Hopefully the SIGALRM will be received somewhere during
1203 # initial processing of SIGUSR1.
1204 signal.setitimer(signal.ITIMER_REAL, 1e-6 + random.random() * 1e-5)
1205 os.kill(os.getpid(), signal.SIGUSR1)
1206
1207 expected_sigs += 2
1208 # Wait for handlers to run to avoid signal coalescing
1209 while len(sigs) < expected_sigs and time.time() < deadline:
1210 time.sleep(1e-5)
1211
1212 # All ITIMER_REAL signals should have been delivered to the
1213 # Python handler
1214 self.assertEqual(len(sigs), N, "Some signals were lost")
1215
1216
Zachary Ware38c707e2015-04-13 15:00:43 -05001217def tearDownModule():
1218 support.reap_children()
Thomas Woutersed03b412007-08-28 21:37:11 +00001219
1220if __name__ == "__main__":
Zachary Ware38c707e2015-04-13 15:00:43 -05001221 unittest.main()