blob: effdbef127c33eb7d89912caff1b719df0829499 [file] [log] [blame]
Thomas Woutersed03b412007-08-28 21:37:11 +00001import unittest
Benjamin Petersonee8712c2008-05-20 21:35:26 +00002from test import support
Raymond Hettinger722d8c32009-06-18 22:21:03 +00003from contextlib import closing
Christian Heimescc47b052008-03-25 14:56:36 +00004import gc
Christian Heimes4fbc72b2008-03-22 00:47:35 +00005import pickle
6import select
Guido van Rossum4f17e3e1995-03-16 15:07:38 +00007import signal
Victor Stinnerd49b1f12011-05-08 02:03:15 +02008import struct
Christian Heimes4fbc72b2008-03-22 00:47:35 +00009import subprocess
10import traceback
Christian Heimesc06950e2008-02-28 21:17:00 +000011import sys, os, time, errno
Victor Stinner415007e2011-06-13 16:19:06 +020012from test.script_helper import assert_python_ok
Victor Stinnerb3e72192011-05-08 01:46:11 +020013try:
14 import threading
15except ImportError:
16 threading = None
Christian Heimesc06950e2008-02-28 21:17:00 +000017
Brian Curtin912443c2010-09-06 16:10:04 +000018if sys.platform in ('os2', 'riscos'):
19 raise unittest.SkipTest("Can't test signal on %s" % sys.platform)
Christian Heimesc06950e2008-02-28 21:17:00 +000020
Guido van Rossumcc5a91d1997-04-16 00:29:15 +000021
Armin Rigo8b2cbfd2004-08-07 21:27:43 +000022class HandlerBCalled(Exception):
23 pass
Guido van Rossum4f17e3e1995-03-16 15:07:38 +000024
Christian Heimes4fbc72b2008-03-22 00:47:35 +000025
26def exit_subprocess():
27 """Use os._exit(0) to exit the current subprocess.
28
29 Otherwise, the test catches the SystemExit and continues executing
30 in parallel with the original test, so you wind up with an
31 exponential number of tests running concurrently.
32 """
33 os._exit(0)
34
35
Benjamin Petersonad9d48d2008-04-02 21:49:44 +000036def ignoring_eintr(__func, *args, **kwargs):
37 try:
38 return __func(*args, **kwargs)
Neal Norwitzf5c7c2e2008-04-05 04:47:45 +000039 except EnvironmentError as e:
40 if e.errno != errno.EINTR:
Benjamin Petersonad9d48d2008-04-02 21:49:44 +000041 raise
42 return None
43
44
Brian Curtin3f004b12010-08-06 19:34:52 +000045@unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
Thomas Woutersed03b412007-08-28 21:37:11 +000046class InterProcessSignalTests(unittest.TestCase):
47 MAX_DURATION = 20 # Entire test should last at most 20 sec.
Guido van Rossum4f17e3e1995-03-16 15:07:38 +000048
Christian Heimescc47b052008-03-25 14:56:36 +000049 def setUp(self):
50 self.using_gc = gc.isenabled()
51 gc.disable()
52
53 def tearDown(self):
54 if self.using_gc:
55 gc.enable()
56
Christian Heimes5e696852008-04-09 08:37:03 +000057 def format_frame(self, frame, limit=None):
58 return ''.join(traceback.format_stack(frame, limit=limit))
59
60 def handlerA(self, signum, frame):
Thomas Woutersed03b412007-08-28 21:37:11 +000061 self.a_called = True
Guido van Rossum4f17e3e1995-03-16 15:07:38 +000062
Christian Heimes5e696852008-04-09 08:37:03 +000063 def handlerB(self, signum, frame):
Thomas Woutersed03b412007-08-28 21:37:11 +000064 self.b_called = True
Christian Heimes5e696852008-04-09 08:37:03 +000065 raise HandlerBCalled(signum, self.format_frame(frame))
Neal Norwitz9730bcb2006-01-23 07:50:06 +000066
Christian Heimes4fbc72b2008-03-22 00:47:35 +000067 def wait(self, child):
68 """Wait for child to finish, ignoring EINTR."""
69 while True:
70 try:
71 child.wait()
72 return
73 except OSError as e:
74 if e.errno != errno.EINTR:
75 raise
Fred Drake004d5e62000-10-23 17:22:08 +000076
Christian Heimes4fbc72b2008-03-22 00:47:35 +000077 def run_test(self):
78 # Install handlers. This function runs in a sub-process, so we
79 # don't worry about re-setting the default handlers.
80 signal.signal(signal.SIGHUP, self.handlerA)
81 signal.signal(signal.SIGUSR1, self.handlerB)
82 signal.signal(signal.SIGUSR2, signal.SIG_IGN)
83 signal.signal(signal.SIGALRM, signal.default_int_handler)
Michael W. Hudson5c26e862004-06-11 18:09:28 +000084
Christian Heimes4fbc72b2008-03-22 00:47:35 +000085 # Variables the signals will modify:
86 self.a_called = False
87 self.b_called = False
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000088
Christian Heimes4fbc72b2008-03-22 00:47:35 +000089 # Let the sub-processes know who to send signals to.
90 pid = os.getpid()
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000091
Benjamin Petersonad9d48d2008-04-02 21:49:44 +000092 child = ignoring_eintr(subprocess.Popen, ['kill', '-HUP', str(pid)])
93 if child:
94 self.wait(child)
95 if not self.a_called:
96 time.sleep(1) # Give the signal time to be delivered.
Christian Heimes4fbc72b2008-03-22 00:47:35 +000097 self.assertTrue(self.a_called)
98 self.assertFalse(self.b_called)
99 self.a_called = False
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000100
Christian Heimes5e696852008-04-09 08:37:03 +0000101 # Make sure the signal isn't delivered while the previous
102 # Popen object is being destroyed, because __del__ swallows
103 # exceptions.
104 del child
Thomas Woutersed03b412007-08-28 21:37:11 +0000105 try:
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000106 child = subprocess.Popen(['kill', '-USR1', str(pid)])
107 # This wait should be interrupted by the signal's exception.
108 self.wait(child)
Benjamin Petersonad9d48d2008-04-02 21:49:44 +0000109 time.sleep(1) # Give the signal time to be delivered.
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000110 self.fail('HandlerBCalled exception not thrown')
111 except HandlerBCalled:
112 self.assertTrue(self.b_called)
113 self.assertFalse(self.a_called)
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000114
Benjamin Petersonad9d48d2008-04-02 21:49:44 +0000115 child = ignoring_eintr(subprocess.Popen, ['kill', '-USR2', str(pid)])
116 if child:
117 self.wait(child) # Nothing should happen.
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000118
119 try:
120 signal.alarm(1)
121 # The race condition in pause doesn't matter in this case,
122 # since alarm is going to raise a KeyboardException, which
123 # will skip the call.
124 signal.pause()
Benjamin Petersonad9d48d2008-04-02 21:49:44 +0000125 # But if another signal arrives before the alarm, pause
126 # may return early.
127 time.sleep(1)
Thomas Woutersed03b412007-08-28 21:37:11 +0000128 except KeyboardInterrupt:
Victor Stinner3a7f0f02011-05-08 02:10:36 +0200129 pass
Thomas Woutersed03b412007-08-28 21:37:11 +0000130 except:
Benjamin Petersonad9d48d2008-04-02 21:49:44 +0000131 self.fail("Some other exception woke us from pause: %s" %
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000132 traceback.format_exc())
133 else:
Benjamin Petersonad9d48d2008-04-02 21:49:44 +0000134 self.fail("pause returned of its own accord, and the signal"
135 " didn't arrive after another second.")
Thomas Woutersed03b412007-08-28 21:37:11 +0000136
R. David Murray44546f82010-04-21 01:59:28 +0000137 # Issue 3864, unknown if this affects earlier versions of freebsd also
138 @unittest.skipIf(sys.platform=='freebsd6',
139 'inter process signals not reliable (do not mix well with threading) '
140 'on freebsd6')
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000141 def test_main(self):
142 # This function spawns a child process to insulate the main
143 # test-running process from all the signals. It then
144 # communicates with that child process over a pipe and
145 # re-raises information about any exceptions the child
146 # throws. The real work happens in self.run_test().
147 os_done_r, os_done_w = os.pipe()
Raymond Hettinger686057b2009-06-04 00:11:54 +0000148 with closing(os.fdopen(os_done_r, 'rb')) as done_r, \
149 closing(os.fdopen(os_done_w, 'wb')) as done_w:
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000150 child = os.fork()
151 if child == 0:
152 # In the child process; run the test and report results
153 # through the pipe.
154 try:
155 done_r.close()
156 # Have to close done_w again here because
157 # exit_subprocess() will skip the enclosing with block.
158 with closing(done_w):
159 try:
160 self.run_test()
161 except:
162 pickle.dump(traceback.format_exc(), done_w)
163 else:
164 pickle.dump(None, done_w)
165 except:
166 print('Uh oh, raised from pickle.')
167 traceback.print_exc()
168 finally:
169 exit_subprocess()
170
171 done_w.close()
172 # Block for up to MAX_DURATION seconds for the test to finish.
173 r, w, x = select.select([done_r], [], [], self.MAX_DURATION)
174 if done_r in r:
175 tb = pickle.load(done_r)
176 if tb:
177 self.fail(tb)
178 else:
179 os.kill(child, signal.SIGKILL)
180 self.fail('Test deadlocked after %d seconds.' %
181 self.MAX_DURATION)
Thomas Woutersed03b412007-08-28 21:37:11 +0000182
183
Brian Curtin3f004b12010-08-06 19:34:52 +0000184@unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
Victor Stinnerb3e72192011-05-08 01:46:11 +0200185class PosixTests(unittest.TestCase):
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000186 def trivial_signal_handler(self, *args):
187 pass
188
Thomas Woutersed03b412007-08-28 21:37:11 +0000189 def test_out_of_range_signal_number_raises_error(self):
190 self.assertRaises(ValueError, signal.getsignal, 4242)
191
Thomas Woutersed03b412007-08-28 21:37:11 +0000192 self.assertRaises(ValueError, signal.signal, 4242,
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000193 self.trivial_signal_handler)
Thomas Woutersed03b412007-08-28 21:37:11 +0000194
195 def test_setting_signal_handler_to_none_raises_error(self):
196 self.assertRaises(TypeError, signal.signal,
197 signal.SIGUSR1, None)
198
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000199 def test_getsignal(self):
200 hup = signal.signal(signal.SIGHUP, self.trivial_signal_handler)
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000201 self.assertEqual(signal.getsignal(signal.SIGHUP),
202 self.trivial_signal_handler)
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000203 signal.signal(signal.SIGHUP, hup)
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000204 self.assertEqual(signal.getsignal(signal.SIGHUP), hup)
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000205
206
Brian Curtin3f004b12010-08-06 19:34:52 +0000207@unittest.skipUnless(sys.platform == "win32", "Windows specific")
208class WindowsSignalTests(unittest.TestCase):
209 def test_issue9324(self):
Brian Curtineccd4d92010-10-01 15:09:53 +0000210 # Updated for issue #10003, adding SIGBREAK
Brian Curtin3f004b12010-08-06 19:34:52 +0000211 handler = lambda x, y: None
Brian Curtineccd4d92010-10-01 15:09:53 +0000212 for sig in (signal.SIGABRT, signal.SIGBREAK, signal.SIGFPE,
213 signal.SIGILL, signal.SIGINT, signal.SIGSEGV,
214 signal.SIGTERM):
215 # Set and then reset a handler for signals that work on windows
216 signal.signal(sig, signal.signal(sig, handler))
Brian Curtin3f004b12010-08-06 19:34:52 +0000217
218 with self.assertRaises(ValueError):
219 signal.signal(-1, handler)
Brian Curtin80cd4bf2010-08-07 03:52:38 +0000220
221 with self.assertRaises(ValueError):
222 signal.signal(7, handler)
Brian Curtin3f004b12010-08-06 19:34:52 +0000223
224
225@unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000226class WakeupSignalTests(unittest.TestCase):
227 TIMEOUT_FULL = 10
228 TIMEOUT_HALF = 5
229
Victor Stinnerc13ef662011-05-25 02:35:58 +0200230 def handler(self, signum, frame):
231 pass
232
Victor Stinner20822682011-05-31 22:31:09 +0200233 def check_signum(self, *signals):
Victor Stinnerd49b1f12011-05-08 02:03:15 +0200234 data = os.read(self.read, len(signals)+1)
235 raised = struct.unpack('%uB' % len(data), data)
Victor Stinner20822682011-05-31 22:31:09 +0200236 # We don't care of the signal delivery order (it's not portable or
237 # reliable)
238 raised = set(raised)
239 signals = set(signals)
Victor Stinnerc13ef662011-05-25 02:35:58 +0200240 self.assertEqual(raised, signals)
Victor Stinnerd49b1f12011-05-08 02:03:15 +0200241
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000242 def test_wakeup_fd_early(self):
243 import select
244
245 signal.alarm(1)
246 before_time = time.time()
247 # We attempt to get a signal during the sleep,
248 # before select is called
249 time.sleep(self.TIMEOUT_FULL)
250 mid_time = time.time()
Georg Brandlab91fde2009-08-13 08:51:18 +0000251 self.assertTrue(mid_time - before_time < self.TIMEOUT_HALF)
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000252 select.select([self.read], [], [], self.TIMEOUT_FULL)
253 after_time = time.time()
Georg Brandlab91fde2009-08-13 08:51:18 +0000254 self.assertTrue(after_time - mid_time < self.TIMEOUT_HALF)
Victor Stinnerd49b1f12011-05-08 02:03:15 +0200255 self.check_signum(signal.SIGALRM)
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000256
257 def test_wakeup_fd_during(self):
258 import select
259
260 signal.alarm(1)
261 before_time = time.time()
262 # We attempt to get a signal during the select call
263 self.assertRaises(select.error, select.select,
264 [self.read], [], [], self.TIMEOUT_FULL)
265 after_time = time.time()
Georg Brandlab91fde2009-08-13 08:51:18 +0000266 self.assertTrue(after_time - before_time < self.TIMEOUT_HALF)
Victor Stinnerd49b1f12011-05-08 02:03:15 +0200267 self.check_signum(signal.SIGALRM)
268
269 def test_signum(self):
Victor Stinnerc13ef662011-05-25 02:35:58 +0200270 old_handler = signal.signal(signal.SIGUSR1, self.handler)
Victor Stinnerd49b1f12011-05-08 02:03:15 +0200271 self.addCleanup(signal.signal, signal.SIGUSR1, old_handler)
272 os.kill(os.getpid(), signal.SIGUSR1)
273 os.kill(os.getpid(), signal.SIGALRM)
274 self.check_signum(signal.SIGUSR1, signal.SIGALRM)
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000275
Victor Stinnerc13ef662011-05-25 02:35:58 +0200276 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
277 'need signal.pthread_sigmask()')
278 @unittest.skipUnless(hasattr(signal, 'pthread_kill'),
279 'need signal.pthread_kill()')
280 def test_pending(self):
281 signum1 = signal.SIGUSR1
282 signum2 = signal.SIGUSR2
283 tid = threading.current_thread().ident
284
285 old_handler = signal.signal(signum1, self.handler)
286 self.addCleanup(signal.signal, signum1, old_handler)
287 old_handler = signal.signal(signum2, self.handler)
288 self.addCleanup(signal.signal, signum2, old_handler)
289
290 signal.pthread_sigmask(signal.SIG_BLOCK, (signum1, signum2))
291 signal.pthread_kill(tid, signum1)
292 signal.pthread_kill(tid, signum2)
293 # Unblocking the 2 signals calls the C signal handler twice
294 signal.pthread_sigmask(signal.SIG_UNBLOCK, (signum1, signum2))
295
Victor Stinner20822682011-05-31 22:31:09 +0200296 self.check_signum(signum1, signum2)
Victor Stinnerc13ef662011-05-25 02:35:58 +0200297
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000298 def setUp(self):
299 import fcntl
300
Victor Stinnerc13ef662011-05-25 02:35:58 +0200301 self.alrm = signal.signal(signal.SIGALRM, self.handler)
Christian Heimes5fb7c2a2007-12-24 08:52:31 +0000302 self.read, self.write = os.pipe()
303 flags = fcntl.fcntl(self.write, fcntl.F_GETFL, 0)
304 flags = flags | os.O_NONBLOCK
305 fcntl.fcntl(self.write, fcntl.F_SETFL, flags)
306 self.old_wakeup = signal.set_wakeup_fd(self.write)
307
308 def tearDown(self):
309 signal.set_wakeup_fd(self.old_wakeup)
310 os.close(self.read)
311 os.close(self.write)
312 signal.signal(signal.SIGALRM, self.alrm)
313
Brian Curtin3f004b12010-08-06 19:34:52 +0000314@unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
Christian Heimes8640e742008-02-23 16:23:06 +0000315class SiginterruptTest(unittest.TestCase):
Jean-Paul Calderone9c39bc72010-05-09 03:25:16 +0000316
317 def setUp(self):
318 """Install a no-op signal handler that can be set to allow
319 interrupts or not, and arrange for the original signal handler to be
320 re-installed when the test is finished.
321 """
Brian Curtin3f004b12010-08-06 19:34:52 +0000322 self.signum = signal.SIGUSR1
Jean-Paul Calderone9c39bc72010-05-09 03:25:16 +0000323 oldhandler = signal.signal(self.signum, lambda x,y: None)
324 self.addCleanup(signal.signal, self.signum, oldhandler)
325
326 def readpipe_interrupted(self):
327 """Perform a read during which a signal will arrive. Return True if the
328 read is interrupted by the signal and raises an exception. Return False
329 if it returns normally.
330 """
331 # Create a pipe that can be used for the read. Also clean it up
332 # when the test is over, since nothing else will (but see below for
333 # the write end).
Christian Heimes8640e742008-02-23 16:23:06 +0000334 r, w = os.pipe()
Jean-Paul Calderone9c39bc72010-05-09 03:25:16 +0000335 self.addCleanup(os.close, r)
336
337 # Create another process which can send a signal to this one to try
338 # to interrupt the read.
Christian Heimes8640e742008-02-23 16:23:06 +0000339 ppid = os.getpid()
340 pid = os.fork()
341
Jean-Paul Calderone9c39bc72010-05-09 03:25:16 +0000342 if pid == 0:
343 # Child code: sleep to give the parent enough time to enter the
344 # read() call (there's a race here, but it's really tricky to
345 # eliminate it); then signal the parent process. Also, sleep
346 # again to make it likely that the signal is delivered to the
347 # parent process before the child exits. If the child exits
348 # first, the write end of the pipe will be closed and the test
349 # is invalid.
Christian Heimes8640e742008-02-23 16:23:06 +0000350 try:
351 time.sleep(0.2)
352 os.kill(ppid, self.signum)
353 time.sleep(0.2)
354 finally:
Jean-Paul Calderone9c39bc72010-05-09 03:25:16 +0000355 # No matter what, just exit as fast as possible now.
Christian Heimes4fbc72b2008-03-22 00:47:35 +0000356 exit_subprocess()
Jean-Paul Calderone9c39bc72010-05-09 03:25:16 +0000357 else:
358 # Parent code.
359 # Make sure the child is eventually reaped, else it'll be a
360 # zombie for the rest of the test suite run.
361 self.addCleanup(os.waitpid, pid, 0)
Christian Heimes8640e742008-02-23 16:23:06 +0000362
Jean-Paul Calderone9c39bc72010-05-09 03:25:16 +0000363 # Close the write end of the pipe. The child has a copy, so
364 # it's not really closed until the child exits. We need it to
365 # close when the child exits so that in the non-interrupt case
366 # the read eventually completes, otherwise we could just close
367 # it *after* the test.
Christian Heimes8640e742008-02-23 16:23:06 +0000368 os.close(w)
369
Jean-Paul Calderone9c39bc72010-05-09 03:25:16 +0000370 # Try the read and report whether it is interrupted or not to
371 # the caller.
Christian Heimes8640e742008-02-23 16:23:06 +0000372 try:
Jean-Paul Calderone9c39bc72010-05-09 03:25:16 +0000373 d = os.read(r, 1)
Christian Heimes8640e742008-02-23 16:23:06 +0000374 return False
375 except OSError as err:
376 if err.errno != errno.EINTR:
377 raise
378 return True
Christian Heimes8640e742008-02-23 16:23:06 +0000379
380 def test_without_siginterrupt(self):
Victor Stinner3a7f0f02011-05-08 02:10:36 +0200381 # If a signal handler is installed and siginterrupt is not called
382 # at all, when that signal arrives, it interrupts a syscall that's in
383 # progress.
Jean-Paul Calderone9c39bc72010-05-09 03:25:16 +0000384 i = self.readpipe_interrupted()
385 self.assertTrue(i)
386 # Arrival of the signal shouldn't have changed anything.
387 i = self.readpipe_interrupted()
388 self.assertTrue(i)
Christian Heimes8640e742008-02-23 16:23:06 +0000389
390 def test_siginterrupt_on(self):
Victor Stinner3a7f0f02011-05-08 02:10:36 +0200391 # If a signal handler is installed and siginterrupt is called with
392 # a true value for the second argument, when that signal arrives, it
393 # interrupts a syscall that's in progress.
Jean-Paul Calderone9c39bc72010-05-09 03:25:16 +0000394 signal.siginterrupt(self.signum, 1)
395 i = self.readpipe_interrupted()
396 self.assertTrue(i)
397 # Arrival of the signal shouldn't have changed anything.
398 i = self.readpipe_interrupted()
399 self.assertTrue(i)
Christian Heimes8640e742008-02-23 16:23:06 +0000400
401 def test_siginterrupt_off(self):
Victor Stinner3a7f0f02011-05-08 02:10:36 +0200402 # If a signal handler is installed and siginterrupt is called with
403 # a false value for the second argument, when that signal arrives, it
404 # does not interrupt a syscall that's in progress.
Jean-Paul Calderone9c39bc72010-05-09 03:25:16 +0000405 signal.siginterrupt(self.signum, 0)
406 i = self.readpipe_interrupted()
407 self.assertFalse(i)
408 # Arrival of the signal shouldn't have changed anything.
409 i = self.readpipe_interrupted()
410 self.assertFalse(i)
411
412
Brian Curtin3f004b12010-08-06 19:34:52 +0000413@unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
Martin v. Löwis823725e2008-03-24 13:39:54 +0000414class ItimerTest(unittest.TestCase):
415 def setUp(self):
416 self.hndl_called = False
417 self.hndl_count = 0
418 self.itimer = None
Christian Heimescc47b052008-03-25 14:56:36 +0000419 self.old_alarm = signal.signal(signal.SIGALRM, self.sig_alrm)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000420
421 def tearDown(self):
Christian Heimescc47b052008-03-25 14:56:36 +0000422 signal.signal(signal.SIGALRM, self.old_alarm)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000423 if self.itimer is not None: # test_itimer_exc doesn't change this attr
424 # just ensure that itimer is stopped
425 signal.setitimer(self.itimer, 0)
426
427 def sig_alrm(self, *args):
428 self.hndl_called = True
Martin v. Löwis823725e2008-03-24 13:39:54 +0000429
430 def sig_vtalrm(self, *args):
431 self.hndl_called = True
432
433 if self.hndl_count > 3:
434 # it shouldn't be here, because it should have been disabled.
435 raise signal.ItimerError("setitimer didn't disable ITIMER_VIRTUAL "
436 "timer.")
437 elif self.hndl_count == 3:
438 # disable ITIMER_VIRTUAL, this function shouldn't be called anymore
439 signal.setitimer(signal.ITIMER_VIRTUAL, 0)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000440
441 self.hndl_count += 1
442
Martin v. Löwis823725e2008-03-24 13:39:54 +0000443 def sig_prof(self, *args):
444 self.hndl_called = True
445 signal.setitimer(signal.ITIMER_PROF, 0)
446
Martin v. Löwis823725e2008-03-24 13:39:54 +0000447 def test_itimer_exc(self):
448 # XXX I'm assuming -1 is an invalid itimer, but maybe some platform
449 # defines it ?
450 self.assertRaises(signal.ItimerError, signal.setitimer, -1, 0)
Christian Heimescc47b052008-03-25 14:56:36 +0000451 # Negative times are treated as zero on some platforms.
452 if 0:
453 self.assertRaises(signal.ItimerError,
454 signal.setitimer, signal.ITIMER_REAL, -1)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000455
456 def test_itimer_real(self):
457 self.itimer = signal.ITIMER_REAL
Martin v. Löwis823725e2008-03-24 13:39:54 +0000458 signal.setitimer(self.itimer, 1.0)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000459 signal.pause()
Martin v. Löwis823725e2008-03-24 13:39:54 +0000460 self.assertEqual(self.hndl_called, True)
461
R. David Murray44546f82010-04-21 01:59:28 +0000462 # Issue 3864, unknown if this affects earlier versions of freebsd also
Gregory P. Smith397cd8a2010-10-17 04:23:21 +0000463 @unittest.skipIf(sys.platform in ('freebsd6', 'netbsd5'),
464 'itimer not reliable (does not mix well with threading) on some BSDs.')
Martin v. Löwis823725e2008-03-24 13:39:54 +0000465 def test_itimer_virtual(self):
466 self.itimer = signal.ITIMER_VIRTUAL
467 signal.signal(signal.SIGVTALRM, self.sig_vtalrm)
468 signal.setitimer(self.itimer, 0.3, 0.2)
469
Mark Dickinson78373472009-10-31 10:39:21 +0000470 start_time = time.time()
Stefan Krahf1da973042010-04-20 08:15:14 +0000471 while time.time() - start_time < 60.0:
Mark Dickinson95078872009-10-04 18:47:48 +0000472 # use up some virtual time by doing real work
473 _ = pow(12345, 67890, 10000019)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000474 if signal.getitimer(self.itimer) == (0.0, 0.0):
475 break # sig_vtalrm handler stopped this itimer
Stefan Krahf1da973042010-04-20 08:15:14 +0000476 else: # Issue 8424
Benjamin Peterson9b140f62010-05-15 18:00:56 +0000477 self.skipTest("timeout: likely cause: machine too slow or load too "
478 "high")
Martin v. Löwis823725e2008-03-24 13:39:54 +0000479
480 # virtual itimer should be (0.0, 0.0) now
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000481 self.assertEqual(signal.getitimer(self.itimer), (0.0, 0.0))
Martin v. Löwis823725e2008-03-24 13:39:54 +0000482 # and the handler should have been called
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000483 self.assertEqual(self.hndl_called, True)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000484
R. David Murray44546f82010-04-21 01:59:28 +0000485 # Issue 3864, unknown if this affects earlier versions of freebsd also
486 @unittest.skipIf(sys.platform=='freebsd6',
487 'itimer not reliable (does not mix well with threading) on freebsd6')
Martin v. Löwis823725e2008-03-24 13:39:54 +0000488 def test_itimer_prof(self):
489 self.itimer = signal.ITIMER_PROF
490 signal.signal(signal.SIGPROF, self.sig_prof)
Neal Norwitzf5c7c2e2008-04-05 04:47:45 +0000491 signal.setitimer(self.itimer, 0.2, 0.2)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000492
Mark Dickinson78373472009-10-31 10:39:21 +0000493 start_time = time.time()
Stefan Krahf1da973042010-04-20 08:15:14 +0000494 while time.time() - start_time < 60.0:
Mark Dickinson78373472009-10-31 10:39:21 +0000495 # do some work
496 _ = pow(12345, 67890, 10000019)
Martin v. Löwis823725e2008-03-24 13:39:54 +0000497 if signal.getitimer(self.itimer) == (0.0, 0.0):
498 break # sig_prof handler stopped this itimer
Stefan Krahf1da973042010-04-20 08:15:14 +0000499 else: # Issue 8424
Benjamin Peterson9b140f62010-05-15 18:00:56 +0000500 self.skipTest("timeout: likely cause: machine too slow or load too "
501 "high")
Martin v. Löwis823725e2008-03-24 13:39:54 +0000502
Neal Norwitzf5c7c2e2008-04-05 04:47:45 +0000503 # profiling itimer should be (0.0, 0.0) now
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000504 self.assertEqual(signal.getitimer(self.itimer), (0.0, 0.0))
Neal Norwitzf5c7c2e2008-04-05 04:47:45 +0000505 # and the handler should have been called
Martin v. Löwis823725e2008-03-24 13:39:54 +0000506 self.assertEqual(self.hndl_called, True)
507
Victor Stinnera9293352011-04-30 15:21:58 +0200508
Victor Stinner35b300c2011-05-04 13:20:35 +0200509class PendingSignalsTests(unittest.TestCase):
510 """
Victor Stinnerb3e72192011-05-08 01:46:11 +0200511 Test pthread_sigmask(), pthread_kill(), sigpending() and sigwait()
512 functions.
Victor Stinner35b300c2011-05-04 13:20:35 +0200513 """
Victor Stinnerb3e72192011-05-08 01:46:11 +0200514 def setUp(self):
515 self.has_pthread_kill = hasattr(signal, 'pthread_kill')
516
Victor Stinner35b300c2011-05-04 13:20:35 +0200517 def handler(self, signum, frame):
518 1/0
519
520 def read_sigmask(self):
521 return signal.pthread_sigmask(signal.SIG_BLOCK, [])
522
Victor Stinnerb3e72192011-05-08 01:46:11 +0200523 def can_test_blocked_signals(self, skip):
524 """
525 Check if a blocked signal can be raised to the main thread without
526 calling its signal handler. We need pthread_kill() or exactly one
527 thread (the main thread).
Victor Stinnera9293352011-04-30 15:21:58 +0200528
Victor Stinnerb3e72192011-05-08 01:46:11 +0200529 Return True if it's possible. Otherwise, return False and print a
530 warning if skip is False, or raise a SkipTest exception if skip is
531 True.
532 """
533 if self.has_pthread_kill:
534 return True
Victor Stinnera9293352011-04-30 15:21:58 +0200535
Victor Stinnerf44ce872011-05-03 17:20:31 +0200536 # The fault handler timeout thread masks all signals. If the main
537 # thread masks also SIGUSR1, all threads mask this signal. In this
538 # case, if we send SIGUSR1 to the process, the signal is pending in the
539 # main or the faulthandler timeout thread. Unblock SIGUSR1 in the main
540 # thread calls the signal handler only if the signal is pending for the
Victor Stinnerb3e72192011-05-08 01:46:11 +0200541 # main thread. Stop the faulthandler timeout thread to workaround this
542 # problem.
543 import faulthandler
Victor Stinnerf44ce872011-05-03 17:20:31 +0200544 faulthandler.cancel_dump_tracebacks_later()
Victor Stinner2d4a91e2011-05-03 14:11:22 +0200545
Victor Stinnerb3e72192011-05-08 01:46:11 +0200546 # Issue #11998: The _tkinter module loads the Tcl library which
547 # creates a thread waiting events in select(). This thread receives
548 # signals blocked by all other threads. We cannot test blocked
549 # signals
550 if '_tkinter' in sys.modules:
551 message = ("_tkinter is loaded and pthread_kill() is missing, "
552 "cannot test blocked signals (issue #11998)")
553 if skip:
554 self.skipTest(message)
555 else:
556 print("WARNING: %s" % message)
557 return False
558 return True
559
560 def kill(self, signum):
561 if self.has_pthread_kill:
Victor Stinner2a129742011-05-30 23:02:52 +0200562 tid = threading.get_ident()
Victor Stinnerb3e72192011-05-08 01:46:11 +0200563 signal.pthread_kill(tid, signum)
564 else:
565 pid = os.getpid()
566 os.kill(pid, signum)
567
568 @unittest.skipUnless(hasattr(signal, 'sigpending'),
569 'need signal.sigpending()')
570 def test_sigpending_empty(self):
571 self.assertEqual(signal.sigpending(), set())
572
573 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
574 'need signal.pthread_sigmask()')
575 @unittest.skipUnless(hasattr(signal, 'sigpending'),
576 'need signal.sigpending()')
577 def test_sigpending(self):
578 self.can_test_blocked_signals(True)
579
580 signum = signal.SIGUSR1
581 old_handler = signal.signal(signum, self.handler)
582 self.addCleanup(signal.signal, signum, old_handler)
583
584 signal.pthread_sigmask(signal.SIG_BLOCK, [signum])
585 self.kill(signum)
586 self.assertEqual(signal.sigpending(), {signum})
587 with self.assertRaises(ZeroDivisionError):
588 signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum])
589
590 @unittest.skipUnless(hasattr(signal, 'pthread_kill'),
591 'need signal.pthread_kill()')
592 def test_pthread_kill(self):
593 signum = signal.SIGUSR1
Victor Stinner2a129742011-05-30 23:02:52 +0200594 current = threading.get_ident()
Victor Stinnerb3e72192011-05-08 01:46:11 +0200595
596 old_handler = signal.signal(signum, self.handler)
597 self.addCleanup(signal.signal, signum, old_handler)
598
599 with self.assertRaises(ZeroDivisionError):
600 signal.pthread_kill(current, signum)
601
Victor Stinner415007e2011-06-13 16:19:06 +0200602 @unittest.skipUnless(hasattr(signal, 'sigwait'),
603 'need signal.sigwait()')
Victor Stinner7f294d12011-06-10 14:02:10 +0200604 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
605 'need signal.pthread_sigmask()')
Victor Stinner415007e2011-06-13 16:19:06 +0200606 @unittest.skipUnless(hasattr(os, 'fork'), 'need os.fork()')
607 def test_sigwait(self):
608 def test(signum):
609 signal.alarm(1)
610 received = signal.sigwait([signum])
611 if received != signum:
612 print("sigwait() received %s, not %s"
613 % (received, signum),
614 file=sys.stderr)
615 os._exit(1)
616
617 signum = signal.SIGALRM
618
Victor Stinneraf494602011-06-10 12:48:13 +0200619 # sigwait must be called with the signal blocked: since the current
620 # process might have several threads running, we fork() a child process
621 # to have a single thread.
622 pid = os.fork()
623 if pid == 0:
624 # child: block and wait the signal
625 try:
626 signal.signal(signum, self.handler)
627 signal.pthread_sigmask(signal.SIG_BLOCK, [signum])
628
629 # Do the tests
630 test(signum)
631
632 # The handler must not be called on unblock
633 try:
634 signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum])
635 except ZeroDivisionError:
636 print("the signal handler has been called",
637 file=sys.stderr)
638 os._exit(1)
Victor Stinner46591662011-06-10 13:53:32 +0200639 except BaseException as err:
640 print("error: {}".format(err), file=sys.stderr)
Victor Stinneraf494602011-06-10 12:48:13 +0200641 os._exit(1)
Victor Stinner46591662011-06-10 13:53:32 +0200642 else:
643 os._exit(0)
Victor Stinneraf494602011-06-10 12:48:13 +0200644 else:
Victor Stinner415007e2011-06-13 16:19:06 +0200645 # parent: check that the child correcty received the signal
Victor Stinneraf494602011-06-10 12:48:13 +0200646 self.assertEqual(os.waitpid(pid, 0), (pid, 0))
647
Victor Stinnerb3e72192011-05-08 01:46:11 +0200648 @unittest.skipUnless(hasattr(signal, 'sigwait'),
649 'need signal.sigwait()')
Victor Stinner415007e2011-06-13 16:19:06 +0200650 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
651 'need signal.pthread_sigmask()')
Victor Stinner10c30d62011-06-10 01:39:53 +0200652 @unittest.skipIf(threading is None, "test needs threading module")
653 def test_sigwait_thread(self):
Victor Stinner415007e2011-06-13 16:19:06 +0200654 # Check that calling sigwait() from a thread doesn't suspend the whole
655 # process. A new interpreter is spawned to avoid problems when mixing
656 # threads and fork(): only async-safe functions are allowed between
657 # fork() and exec().
658 assert_python_ok("-c", """if True:
659 import os, threading, sys, time, signal
Victor Stinner10c30d62011-06-10 01:39:53 +0200660
Victor Stinner415007e2011-06-13 16:19:06 +0200661 # the default handler terminates the process
662 signum = signal.SIGUSR1
663
664 def kill_later():
665 # wait until the main thread is waiting in sigwait()
666 time.sleep(1)
667 os.kill(os.getpid(), signum)
668
669 # the signal must be blocked by all the threads
670 signal.pthread_sigmask(signal.SIG_BLOCK, [signum])
671 killer = threading.Thread(target=kill_later)
Victor Stinneraf494602011-06-10 12:48:13 +0200672 killer.start()
673 received = signal.sigwait([signum])
674 if received != signum:
675 print("sigwait() received %s, not %s" % (received, signum),
676 file=sys.stderr)
Victor Stinner415007e2011-06-13 16:19:06 +0200677 sys.exit(1)
Victor Stinner10c30d62011-06-10 01:39:53 +0200678 killer.join()
Victor Stinner415007e2011-06-13 16:19:06 +0200679 # unblock the signal, which should have been cleared by sigwait()
680 signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum])
681 """)
Victor Stinneraf494602011-06-10 12:48:13 +0200682
Victor Stinnerb3e72192011-05-08 01:46:11 +0200683 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
684 'need signal.pthread_sigmask()')
685 def test_pthread_sigmask_arguments(self):
686 self.assertRaises(TypeError, signal.pthread_sigmask)
687 self.assertRaises(TypeError, signal.pthread_sigmask, 1)
688 self.assertRaises(TypeError, signal.pthread_sigmask, 1, 2, 3)
689 self.assertRaises(OSError, signal.pthread_sigmask, 1700, [])
690
691 @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
692 'need signal.pthread_sigmask()')
693 def test_pthread_sigmask(self):
694 test_blocked_signals = self.can_test_blocked_signals(False)
695 signum = signal.SIGUSR1
Victor Stinner6fd49e12011-05-04 12:38:03 +0200696
Victor Stinnerd0e516d2011-05-03 14:57:12 +0200697 # Install our signal handler
Victor Stinner35b300c2011-05-04 13:20:35 +0200698 old_handler = signal.signal(signum, self.handler)
Victor Stinnera9293352011-04-30 15:21:58 +0200699 self.addCleanup(signal.signal, signum, old_handler)
700
Victor Stinnerd0e516d2011-05-03 14:57:12 +0200701 # Unblock SIGUSR1 (and copy the old mask) to test our signal handler
Victor Stinnera9293352011-04-30 15:21:58 +0200702 old_mask = signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum])
703 self.addCleanup(signal.pthread_sigmask, signal.SIG_SETMASK, old_mask)
Victor Stinnerd0e516d2011-05-03 14:57:12 +0200704 with self.assertRaises(ZeroDivisionError):
Victor Stinnerb3e72192011-05-08 01:46:11 +0200705 self.kill(signum)
Victor Stinnera9293352011-04-30 15:21:58 +0200706
Victor Stinnerd0e516d2011-05-03 14:57:12 +0200707 # Block and then raise SIGUSR1. The signal is blocked: the signal
708 # handler is not called, and the signal is now pending
Victor Stinnera9293352011-04-30 15:21:58 +0200709 signal.pthread_sigmask(signal.SIG_BLOCK, [signum])
Victor Stinnerb3e72192011-05-08 01:46:11 +0200710 if test_blocked_signals:
711 self.kill(signum)
Victor Stinnera9293352011-04-30 15:21:58 +0200712
Victor Stinnerd0e516d2011-05-03 14:57:12 +0200713 # Check the new mask
Victor Stinner35b300c2011-05-04 13:20:35 +0200714 blocked = self.read_sigmask()
Victor Stinnera9293352011-04-30 15:21:58 +0200715 self.assertIn(signum, blocked)
Victor Stinner35b300c2011-05-04 13:20:35 +0200716 self.assertEqual(old_mask ^ blocked, {signum})
Victor Stinnera9293352011-04-30 15:21:58 +0200717
Victor Stinnerd0e516d2011-05-03 14:57:12 +0200718 # Unblock SIGUSR1
Victor Stinnerb3e72192011-05-08 01:46:11 +0200719 if test_blocked_signals:
Victor Stinner6fd49e12011-05-04 12:38:03 +0200720 with self.assertRaises(ZeroDivisionError):
721 # unblock the pending signal calls immediatly the signal handler
722 signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum])
723 else:
Victor Stinnerd0e516d2011-05-03 14:57:12 +0200724 signal.pthread_sigmask(signal.SIG_UNBLOCK, [signum])
725 with self.assertRaises(ZeroDivisionError):
Victor Stinnerb3e72192011-05-08 01:46:11 +0200726 self.kill(signum)
Victor Stinnera9293352011-04-30 15:21:58 +0200727
Victor Stinnerd0e516d2011-05-03 14:57:12 +0200728 # Check the new mask
Victor Stinner35b300c2011-05-04 13:20:35 +0200729 unblocked = self.read_sigmask()
Victor Stinnera9293352011-04-30 15:21:58 +0200730 self.assertNotIn(signum, unblocked)
Victor Stinner35b300c2011-05-04 13:20:35 +0200731 self.assertEqual(blocked ^ unblocked, {signum})
Victor Stinnera9293352011-04-30 15:21:58 +0200732 self.assertSequenceEqual(old_mask, unblocked)
Victor Stinnerd0e516d2011-05-03 14:57:12 +0200733 # Finally, restore the previous signal handler and the signal mask
Victor Stinnera9293352011-04-30 15:21:58 +0200734
735
Thomas Woutersed03b412007-08-28 21:37:11 +0000736def test_main():
Antoine Pitrou8189ab82011-03-20 17:35:32 +0100737 try:
Victor Stinnerb3e72192011-05-08 01:46:11 +0200738 support.run_unittest(PosixTests, InterProcessSignalTests,
Antoine Pitrou8189ab82011-03-20 17:35:32 +0100739 WakeupSignalTests, SiginterruptTest,
Victor Stinnera9293352011-04-30 15:21:58 +0200740 ItimerTest, WindowsSignalTests,
Victor Stinner35b300c2011-05-04 13:20:35 +0200741 PendingSignalsTests)
Antoine Pitrou8189ab82011-03-20 17:35:32 +0100742 finally:
743 support.reap_children()
Thomas Woutersed03b412007-08-28 21:37:11 +0000744
745
746if __name__ == "__main__":
747 test_main()