10a8c90248264a8b26970b4473770bcc3df8515fJosh Gao"""PyUnit testing that threads honor our signal semantics"""
20a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
30a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoimport unittest
40a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoimport signal
50a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoimport os
60a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoimport sys
70a8c90248264a8b26970b4473770bcc3df8515fJosh Gaofrom test.test_support import run_unittest, import_module, reap_threads
80a8c90248264a8b26970b4473770bcc3df8515fJosh Gaothread = import_module('thread')
90a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
100a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoif sys.platform[:3] in ('win', 'os2') or sys.platform=='riscos':
110a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    raise unittest.SkipTest, "Can't test signal on %s" % sys.platform
120a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
130a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoprocess_pid = os.getpid()
140a8c90248264a8b26970b4473770bcc3df8515fJosh Gaosignalled_all=thread.allocate_lock()
150a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
160a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
170a8c90248264a8b26970b4473770bcc3df8515fJosh Gaodef registerSignals(for_usr1, for_usr2, for_alrm):
180a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    usr1 = signal.signal(signal.SIGUSR1, for_usr1)
190a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    usr2 = signal.signal(signal.SIGUSR2, for_usr2)
200a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    alrm = signal.signal(signal.SIGALRM, for_alrm)
210a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    return usr1, usr2, alrm
220a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
230a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
240a8c90248264a8b26970b4473770bcc3df8515fJosh Gao# The signal handler. Just note that the signal occurred and
250a8c90248264a8b26970b4473770bcc3df8515fJosh Gao# from who.
260a8c90248264a8b26970b4473770bcc3df8515fJosh Gaodef handle_signals(sig,frame):
270a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    signal_blackboard[sig]['tripped'] += 1
280a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    signal_blackboard[sig]['tripped_by'] = thread.get_ident()
290a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
300a8c90248264a8b26970b4473770bcc3df8515fJosh Gao# a function that will be spawned as a separate thread.
310a8c90248264a8b26970b4473770bcc3df8515fJosh Gaodef send_signals():
320a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    os.kill(process_pid, signal.SIGUSR1)
330a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    os.kill(process_pid, signal.SIGUSR2)
340a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    signalled_all.release()
350a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
360a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoclass ThreadSignals(unittest.TestCase):
370a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    """Test signal handling semantics of threads.
380a8c90248264a8b26970b4473770bcc3df8515fJosh Gao       We spawn a thread, have the thread send two signals, and
390a8c90248264a8b26970b4473770bcc3df8515fJosh Gao       wait for it to finish. Check that we got both signals
400a8c90248264a8b26970b4473770bcc3df8515fJosh Gao       and that they were run by the main thread.
410a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    """
420a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    @reap_threads
430a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def test_signals(self):
440a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        signalled_all.acquire()
450a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.spawnSignallingThread()
460a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        signalled_all.acquire()
470a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # the signals that we asked the kernel to send
480a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # will come back, but we don't know when.
490a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # (it might even be after the thread exits
500a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # and might be out of order.)  If we haven't seen
510a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # the signals yet, send yet another signal and
520a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # wait for it return.
530a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if signal_blackboard[signal.SIGUSR1]['tripped'] == 0 \
540a8c90248264a8b26970b4473770bcc3df8515fJosh Gao           or signal_blackboard[signal.SIGUSR2]['tripped'] == 0:
550a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            signal.alarm(1)
560a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            signal.pause()
570a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            signal.alarm(0)
580a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
590a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.assertEqual( signal_blackboard[signal.SIGUSR1]['tripped'], 1)
600a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.assertEqual( signal_blackboard[signal.SIGUSR1]['tripped_by'],
610a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                           thread.get_ident())
620a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.assertEqual( signal_blackboard[signal.SIGUSR2]['tripped'], 1)
630a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.assertEqual( signal_blackboard[signal.SIGUSR2]['tripped_by'],
640a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                           thread.get_ident())
650a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        signalled_all.release()
660a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
670a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def spawnSignallingThread(self):
680a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        thread.start_new_thread(send_signals, ())
690a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
700a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
710a8c90248264a8b26970b4473770bcc3df8515fJosh Gaodef test_main():
720a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    global signal_blackboard
730a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
740a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    signal_blackboard = { signal.SIGUSR1 : {'tripped': 0, 'tripped_by': 0 },
750a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                          signal.SIGUSR2 : {'tripped': 0, 'tripped_by': 0 },
760a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                          signal.SIGALRM : {'tripped': 0, 'tripped_by': 0 } }
770a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
780a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    oldsigs = registerSignals(handle_signals, handle_signals, handle_signals)
790a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    try:
800a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        run_unittest(ThreadSignals)
810a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    finally:
820a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        registerSignals(*oldsigs)
830a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
840a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoif __name__ == '__main__':
850a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    test_main()
86