| 
									
										
										
										
											2023-09-28 19:12:11 +02:00
										 |  |  | import gc | 
					
						
							| 
									
										
										
										
											2016-03-15 11:12:35 +01:00
										 |  |  | import os | 
					
						
							|  |  |  | import signal | 
					
						
							|  |  |  | import subprocess | 
					
						
							|  |  |  | import sys | 
					
						
							|  |  |  | import time | 
					
						
							|  |  |  | import unittest | 
					
						
							| 
									
										
										
										
											2019-12-11 11:30:03 +01:00
										 |  |  | from test import support | 
					
						
							| 
									
										
										
										
											2016-03-15 11:12:35 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class SIGUSR1Exception(Exception): | 
					
						
							|  |  |  |     pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class InterProcessSignalTests(unittest.TestCase): | 
					
						
							|  |  |  |     def setUp(self): | 
					
						
							|  |  |  |         self.got_signals = {'SIGHUP': 0, 'SIGUSR1': 0, 'SIGALRM': 0} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def sighup_handler(self, signum, frame): | 
					
						
							|  |  |  |         self.got_signals['SIGHUP'] += 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def sigusr1_handler(self, signum, frame): | 
					
						
							|  |  |  |         self.got_signals['SIGUSR1'] += 1 | 
					
						
							|  |  |  |         raise SIGUSR1Exception | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-11 11:32:12 +00:00
										 |  |  |     def wait_signal(self, child, signame): | 
					
						
							|  |  |  |         if child is not None: | 
					
						
							|  |  |  |             # This wait should be interrupted by exc_class | 
					
						
							|  |  |  |             # (if set) | 
					
						
							|  |  |  |             child.wait() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-15 14:09:56 +02:00
										 |  |  |         start_time = time.monotonic() | 
					
						
							|  |  |  |         for _ in support.busy_retry(support.SHORT_TIMEOUT, error=False): | 
					
						
							| 
									
										
										
										
											2018-12-11 11:32:12 +00:00
										 |  |  |             if self.got_signals[signame]: | 
					
						
							| 
									
										
										
										
											2016-03-15 11:12:35 +01:00
										 |  |  |                 return | 
					
						
							| 
									
										
										
										
											2018-12-11 11:32:12 +00:00
										 |  |  |             signal.pause() | 
					
						
							| 
									
										
										
										
											2022-06-15 14:09:56 +02:00
										 |  |  |         else: | 
					
						
							|  |  |  |             dt = time.monotonic() - start_time | 
					
						
							|  |  |  |             self.fail('signal %s not received after %.1f seconds' | 
					
						
							|  |  |  |                       % (signame, dt)) | 
					
						
							| 
									
										
										
										
											2016-03-15 11:12:35 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def subprocess_send_signal(self, pid, signame): | 
					
						
							|  |  |  |         code = 'import os, signal; os.kill(%s, signal.%s)' % (pid, signame) | 
					
						
							|  |  |  |         args = [sys.executable, '-I', '-c', code] | 
					
						
							|  |  |  |         return subprocess.Popen(args) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_interprocess_signal(self): | 
					
						
							|  |  |  |         # Install handlers. This function runs in a sub-process, so we | 
					
						
							|  |  |  |         # don't worry about re-setting the default handlers. | 
					
						
							|  |  |  |         signal.signal(signal.SIGHUP, self.sighup_handler) | 
					
						
							|  |  |  |         signal.signal(signal.SIGUSR1, self.sigusr1_handler) | 
					
						
							|  |  |  |         signal.signal(signal.SIGUSR2, signal.SIG_IGN) | 
					
						
							|  |  |  |         signal.signal(signal.SIGALRM, signal.default_int_handler) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Let the sub-processes know who to send signals to. | 
					
						
							|  |  |  |         pid = str(os.getpid()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.subprocess_send_signal(pid, "SIGHUP") as child: | 
					
						
							|  |  |  |             self.wait_signal(child, 'SIGHUP') | 
					
						
							|  |  |  |         self.assertEqual(self.got_signals, {'SIGHUP': 1, 'SIGUSR1': 0, | 
					
						
							|  |  |  |                                             'SIGALRM': 0}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-28 19:12:11 +02:00
										 |  |  |         # gh-110033: Make sure that the subprocess.Popen is deleted before | 
					
						
							|  |  |  |         # the next test which raises an exception. Otherwise, the exception | 
					
						
							|  |  |  |         # may be raised when Popen.__del__() is executed and so be logged | 
					
						
							|  |  |  |         # as "Exception ignored in: <function Popen.__del__ at ...>". | 
					
						
							|  |  |  |         child = None | 
					
						
							|  |  |  |         gc.collect() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-11 11:32:12 +00:00
										 |  |  |         with self.assertRaises(SIGUSR1Exception): | 
					
						
							|  |  |  |             with self.subprocess_send_signal(pid, "SIGUSR1") as child: | 
					
						
							|  |  |  |                 self.wait_signal(child, 'SIGUSR1') | 
					
						
							| 
									
										
										
										
											2016-03-15 11:12:35 +01:00
										 |  |  |         self.assertEqual(self.got_signals, {'SIGHUP': 1, 'SIGUSR1': 1, | 
					
						
							|  |  |  |                                             'SIGALRM': 0}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         with self.subprocess_send_signal(pid, "SIGUSR2") as child: | 
					
						
							|  |  |  |             # Nothing should happen: SIGUSR2 is ignored | 
					
						
							|  |  |  |             child.wait() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-19 09:36:54 -07:00
										 |  |  |         try: | 
					
						
							| 
									
										
										
										
											2018-12-11 11:32:12 +00:00
										 |  |  |             with self.assertRaises(KeyboardInterrupt): | 
					
						
							|  |  |  |                 signal.alarm(1) | 
					
						
							|  |  |  |                 self.wait_signal(None, 'SIGALRM') | 
					
						
							| 
									
										
										
										
											2017-09-19 09:36:54 -07:00
										 |  |  |             self.assertEqual(self.got_signals, {'SIGHUP': 1, 'SIGUSR1': 1, | 
					
						
							|  |  |  |                                                 'SIGALRM': 0}) | 
					
						
							|  |  |  |         finally: | 
					
						
							|  |  |  |             signal.alarm(0) | 
					
						
							| 
									
										
										
										
											2016-03-15 11:12:35 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if __name__ == "__main__": | 
					
						
							|  |  |  |     unittest.main() |