blob: 13d02bbc2654cffbb8d75d3ed9829c755ec0a31b [file] [log] [blame]
Guido van Rossum4f17e3e1995-03-16 15:07:38 +00001# Test the signal module
Neal Norwitz9730bcb2006-01-23 07:50:06 +00002from test.test_support import verbose, TestSkipped, TestFailed, vereq
Guido van Rossum4f17e3e1995-03-16 15:07:38 +00003import signal
Michael W. Hudson34f20ea2002-05-27 15:08:24 +00004import os, sys, time
Guido van Rossumcc5a91d1997-04-16 00:29:15 +00005
Guido van Rossume2ae77b2001-10-24 20:42:55 +00006if sys.platform[:3] in ('win', 'os2') or sys.platform=='riscos':
7 raise TestSkipped, "Can't test signal on %s" % sys.platform
Guido van Rossum4f17e3e1995-03-16 15:07:38 +00008
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00009MAX_DURATION = 20 # Entire test should last at most 20 sec.
10
Barry Warsaw5e056bb1996-12-23 23:39:42 +000011if verbose:
Fred Drake004d5e62000-10-23 17:22:08 +000012 x = '-x'
Barry Warsaw5e056bb1996-12-23 23:39:42 +000013else:
Fred Drake004d5e62000-10-23 17:22:08 +000014 x = '+x'
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000015
Guido van Rossum4f17e3e1995-03-16 15:07:38 +000016pid = os.getpid()
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000017if verbose:
18 print "test runner's pid is", pid
Guido van Rossum4f17e3e1995-03-16 15:07:38 +000019
20# Shell script that will send us asynchronous signals
21script = """
Barry Warsaw5e056bb1996-12-23 23:39:42 +000022 (
Fred Drake004d5e62000-10-23 17:22:08 +000023 set %(x)s
24 sleep 2
Michael W. Hudson5c26e862004-06-11 18:09:28 +000025 kill -HUP %(pid)d
Fred Drake004d5e62000-10-23 17:22:08 +000026 sleep 2
Michael W. Hudson5c26e862004-06-11 18:09:28 +000027 kill -USR1 %(pid)d
Fred Drake004d5e62000-10-23 17:22:08 +000028 sleep 2
Michael W. Hudson5c26e862004-06-11 18:09:28 +000029 kill -USR2 %(pid)d
Barry Warsaw5e056bb1996-12-23 23:39:42 +000030 ) &
Guido van Rossum4f17e3e1995-03-16 15:07:38 +000031""" % vars()
32
Thomas Wouters0e3f5912006-08-11 14:57:12 +000033a_called = b_called = False
34
Guido van Rossum4f17e3e1995-03-16 15:07:38 +000035def handlerA(*args):
Thomas Wouters0e3f5912006-08-11 14:57:12 +000036 global a_called
37 a_called = True
Fred Drake004d5e62000-10-23 17:22:08 +000038 if verbose:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000039 print "handlerA invoked", args
Guido van Rossum4f17e3e1995-03-16 15:07:38 +000040
Armin Rigo8b2cbfd2004-08-07 21:27:43 +000041class HandlerBCalled(Exception):
42 pass
Guido van Rossum4f17e3e1995-03-16 15:07:38 +000043
44def handlerB(*args):
Thomas Wouters0e3f5912006-08-11 14:57:12 +000045 global b_called
46 b_called = True
Fred Drake004d5e62000-10-23 17:22:08 +000047 if verbose:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000048 print "handlerB invoked", args
Fred Drake004d5e62000-10-23 17:22:08 +000049 raise HandlerBCalled, args
Guido van Rossum4f17e3e1995-03-16 15:07:38 +000050
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000051# Set up a child to send signals to us (the parent) after waiting long
52# enough to receive the alarm. It seems we miss the alarm for some
53# reason. This will hopefully stop the hangs on Tru64/Alpha.
54# Alas, it doesn't. Tru64 appears to miss all the signals at times, or
55# seemingly random subsets of them, and nothing done in force_test_exit
56# so far has actually helped.
57def force_test_exit():
58 # Sigh, both imports seem necessary to avoid errors.
59 import os
60 fork_pid = os.fork()
61 if fork_pid:
62 # In parent.
63 return fork_pid
64
65 # In child.
66 import os, time
67 try:
68 # Wait 5 seconds longer than the expected alarm to give enough
69 # time for the normal sequence of events to occur. This is
70 # just a stop-gap to try to prevent the test from hanging.
71 time.sleep(MAX_DURATION + 5)
72 print >> sys.__stdout__, ' child should not have to kill parent'
73 for signame in "SIGHUP", "SIGUSR1", "SIGUSR2", "SIGALRM":
74 os.kill(pid, getattr(signal, signame))
75 print >> sys.__stdout__, " child sent", signame, "to", pid
76 time.sleep(1)
77 finally:
78 os._exit(0)
79
80# Install handlers.
Michael W. Hudson5c26e862004-06-11 18:09:28 +000081hup = signal.signal(signal.SIGHUP, handlerA)
82usr1 = signal.signal(signal.SIGUSR1, handlerB)
83usr2 = signal.signal(signal.SIGUSR2, signal.SIG_IGN)
84alrm = signal.signal(signal.SIGALRM, signal.default_int_handler)
Guido van Rossum4f17e3e1995-03-16 15:07:38 +000085
Neal Norwitz9730bcb2006-01-23 07:50:06 +000086try:
Neal Norwitz9730bcb2006-01-23 07:50:06 +000087
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000088 signal.alarm(MAX_DURATION)
89 vereq(signal.getsignal(signal.SIGHUP), handlerA)
90 vereq(signal.getsignal(signal.SIGUSR1), handlerB)
91 vereq(signal.getsignal(signal.SIGUSR2), signal.SIG_IGN)
92 vereq(signal.getsignal(signal.SIGALRM), signal.default_int_handler)
Fred Drake004d5e62000-10-23 17:22:08 +000093
Thomas Wouters0e3f5912006-08-11 14:57:12 +000094 # Try to ensure this test exits even if there is some problem with alarm.
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000095 # Tru64/Alpha often hangs and is ultimately killed by the buildbot.
Thomas Wouters0e3f5912006-08-11 14:57:12 +000096 fork_pid = force_test_exit()
Michael W. Hudson5c26e862004-06-11 18:09:28 +000097
98 try:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +000099 signal.getsignal(4242)
100 raise TestFailed('expected ValueError for invalid signal # to '
101 'getsignal()')
102 except ValueError:
103 pass
104
105 try:
106 signal.signal(4242, handlerB)
107 raise TestFailed('expected ValueError for invalid signal # to '
108 'signal()')
109 except ValueError:
110 pass
111
112 try:
113 signal.signal(signal.SIGUSR1, None)
114 raise TestFailed('expected TypeError for non-callable')
115 except TypeError:
116 pass
117
118 # Launch an external script to send us signals.
119 # We expect the external script to:
120 # send HUP, which invokes handlerA to set a_called
121 # send USR1, which invokes handlerB to set b_called and raise
122 # HandlerBCalled
123 # send USR2, which is ignored
124 #
125 # Then we expect the alarm to go off, and its handler raises
126 # KeyboardInterrupt, finally getting us out of the loop.
127 os.system(script)
128 try:
129 print "starting pause() loop..."
Michael W. Hudson5c26e862004-06-11 18:09:28 +0000130 while 1:
Michael W. Hudson5c26e862004-06-11 18:09:28 +0000131 try:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000132 if verbose:
133 print "call pause()..."
Michael W. Hudson5c26e862004-06-11 18:09:28 +0000134 signal.pause()
135 if verbose:
136 print "pause() returned"
137 except HandlerBCalled:
138 if verbose:
139 print "HandlerBCalled exception caught"
Michael W. Hudson5c26e862004-06-11 18:09:28 +0000140
141 except KeyboardInterrupt:
142 if verbose:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000143 print "KeyboardInterrupt (the alarm() went off)"
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000144
145 if not a_called:
146 print 'HandlerA not called'
147
148 if not b_called:
149 print 'HandlerB not called'
150
Michael W. Hudson5c26e862004-06-11 18:09:28 +0000151finally:
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000152 # Forcibly kill the child we created to ping us if there was a test error.
153 try:
154 # Make sure we don't kill ourself if there was a fork error.
155 if fork_pid > 0:
156 os.kill(fork_pid, signal.SIGKILL)
157 except:
158 # If the child killed us, it has probably exited. Killing a
159 # non-existent process will raise an error which we don't care about.
160 pass
161
162 # Restore handlers.
163 signal.alarm(0) # cancel alarm in case we died early
Michael W. Hudson5c26e862004-06-11 18:09:28 +0000164 signal.signal(signal.SIGHUP, hup)
165 signal.signal(signal.SIGUSR1, usr1)
166 signal.signal(signal.SIGUSR2, usr2)
167 signal.signal(signal.SIGALRM, alrm)