Michael W. Hudson | 43220ea | 2004-08-03 14:37:14 +0000 | [diff] [blame] | 1 | """PyUnit testing that threads honor our signal semantics""" |
| 2 | |
| 3 | import unittest |
| 4 | import thread |
| 5 | import signal |
| 6 | import os |
Fred Drake | 4818748 | 2004-08-03 16:14:13 +0000 | [diff] [blame] | 7 | import sys |
Michael W. Hudson | 574a251 | 2004-08-04 14:22:56 +0000 | [diff] [blame] | 8 | from test.test_support import run_unittest, TestSkipped |
Michael W. Hudson | 43220ea | 2004-08-03 14:37:14 +0000 | [diff] [blame] | 9 | |
Skip Montanaro | 289bc05 | 2007-08-17 02:30:27 +0000 | [diff] [blame] | 10 | if sys.platform[:3] in ('win', 'os2'): |
Collin Winter | 3add4d7 | 2007-08-29 23:37:32 +0000 | [diff] [blame] | 11 | raise TestSkipped("Can't test signal on %s" % sys.platform) |
Michael W. Hudson | 34fba3b | 2004-08-03 15:35:29 +0000 | [diff] [blame] | 12 | |
Michael W. Hudson | 43220ea | 2004-08-03 14:37:14 +0000 | [diff] [blame] | 13 | process_pid = os.getpid() |
| 14 | signalled_all=thread.allocate_lock() |
| 15 | |
| 16 | |
Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 17 | def registerSignals(for_usr1, for_usr2, for_alrm): |
Michael W. Hudson | 43220ea | 2004-08-03 14:37:14 +0000 | [diff] [blame] | 18 | usr1 = signal.signal(signal.SIGUSR1, for_usr1) |
| 19 | usr2 = signal.signal(signal.SIGUSR2, for_usr2) |
| 20 | alrm = signal.signal(signal.SIGALRM, for_alrm) |
| 21 | return usr1, usr2, alrm |
| 22 | |
| 23 | |
Fred Drake | db390c1 | 2005-10-28 14:39:47 +0000 | [diff] [blame] | 24 | # The signal handler. Just note that the signal occurred and |
Michael W. Hudson | 43220ea | 2004-08-03 14:37:14 +0000 | [diff] [blame] | 25 | # from who. |
| 26 | def handle_signals(sig,frame): |
Tim Peters | 6db15d7 | 2004-08-04 02:36:18 +0000 | [diff] [blame] | 27 | signal_blackboard[sig]['tripped'] += 1 |
Michael W. Hudson | 43220ea | 2004-08-03 14:37:14 +0000 | [diff] [blame] | 28 | signal_blackboard[sig]['tripped_by'] = thread.get_ident() |
| 29 | |
| 30 | # a function that will be spawned as a separate thread. |
| 31 | def send_signals(): |
| 32 | os.kill(process_pid, signal.SIGUSR1) |
| 33 | os.kill(process_pid, signal.SIGUSR2) |
| 34 | signalled_all.release() |
| 35 | |
| 36 | class ThreadSignals(unittest.TestCase): |
| 37 | """Test signal handling semantics of threads. |
| 38 | We spawn a thread, have the thread send two signals, and |
| 39 | wait for it to finish. Check that we got both signals |
| 40 | and that they were run by the main thread. |
| 41 | """ |
| 42 | def test_signals(self): |
| 43 | signalled_all.acquire() |
| 44 | self.spawnSignallingThread() |
| 45 | signalled_all.acquire() |
| 46 | # the signals that we asked the kernel to send |
| 47 | # will come back, but we don't know when. |
| 48 | # (it might even be after the thread exits |
| 49 | # and might be out of order.) If we haven't seen |
| 50 | # the signals yet, send yet another signal and |
| 51 | # wait for it return. |
Thomas Wouters | 00ee7ba | 2006-08-21 19:07:27 +0000 | [diff] [blame] | 52 | if signal_blackboard[signal.SIGUSR1]['tripped'] == 0 \ |
Michael W. Hudson | 43220ea | 2004-08-03 14:37:14 +0000 | [diff] [blame] | 53 | or signal_blackboard[signal.SIGUSR2]['tripped'] == 0: |
Tim Peters | 6db15d7 | 2004-08-04 02:36:18 +0000 | [diff] [blame] | 54 | signal.alarm(1) |
| 55 | signal.pause() |
| 56 | signal.alarm(0) |
Michael W. Hudson | 43220ea | 2004-08-03 14:37:14 +0000 | [diff] [blame] | 57 | |
| 58 | self.assertEqual( signal_blackboard[signal.SIGUSR1]['tripped'], 1) |
Tim Peters | 6db15d7 | 2004-08-04 02:36:18 +0000 | [diff] [blame] | 59 | self.assertEqual( signal_blackboard[signal.SIGUSR1]['tripped_by'], |
Michael W. Hudson | 43220ea | 2004-08-03 14:37:14 +0000 | [diff] [blame] | 60 | thread.get_ident()) |
| 61 | self.assertEqual( signal_blackboard[signal.SIGUSR2]['tripped'], 1) |
Tim Peters | 6db15d7 | 2004-08-04 02:36:18 +0000 | [diff] [blame] | 62 | self.assertEqual( signal_blackboard[signal.SIGUSR2]['tripped_by'], |
Michael W. Hudson | 43220ea | 2004-08-03 14:37:14 +0000 | [diff] [blame] | 63 | thread.get_ident()) |
Michael W. Hudson | 574a251 | 2004-08-04 14:22:56 +0000 | [diff] [blame] | 64 | signalled_all.release() |
Michael W. Hudson | 43220ea | 2004-08-03 14:37:14 +0000 | [diff] [blame] | 65 | |
| 66 | def spawnSignallingThread(self): |
| 67 | thread.start_new_thread(send_signals, ()) |
Tim Peters | 6db15d7 | 2004-08-04 02:36:18 +0000 | [diff] [blame] | 68 | |
Michael W. Hudson | 43220ea | 2004-08-03 14:37:14 +0000 | [diff] [blame] | 69 | |
| 70 | def test_main(): |
Michael W. Hudson | 574a251 | 2004-08-04 14:22:56 +0000 | [diff] [blame] | 71 | global signal_blackboard |
Tim Peters | d1b7827 | 2004-08-07 06:03:09 +0000 | [diff] [blame] | 72 | |
Michael W. Hudson | 574a251 | 2004-08-04 14:22:56 +0000 | [diff] [blame] | 73 | signal_blackboard = { signal.SIGUSR1 : {'tripped': 0, 'tripped_by': 0 }, |
| 74 | signal.SIGUSR2 : {'tripped': 0, 'tripped_by': 0 }, |
| 75 | signal.SIGALRM : {'tripped': 0, 'tripped_by': 0 } } |
| 76 | |
Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 77 | oldsigs = registerSignals(handle_signals, handle_signals, handle_signals) |
Michael W. Hudson | 43220ea | 2004-08-03 14:37:14 +0000 | [diff] [blame] | 78 | try: |
Michael W. Hudson | 574a251 | 2004-08-04 14:22:56 +0000 | [diff] [blame] | 79 | run_unittest(ThreadSignals) |
Michael W. Hudson | 43220ea | 2004-08-03 14:37:14 +0000 | [diff] [blame] | 80 | finally: |
Guido van Rossum | 1bc535d | 2007-05-15 18:46:22 +0000 | [diff] [blame] | 81 | registerSignals(*oldsigs) |
Michael W. Hudson | 43220ea | 2004-08-03 14:37:14 +0000 | [diff] [blame] | 82 | |
| 83 | if __name__ == '__main__': |
| 84 | test_main() |