mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	gh-83856: Honor atexit for all multiprocessing start methods (GH-114279)
Use atexit for all multiprocessing start methods to cleanup. See the GH-114279 PR discussion and related issue for details as to why.
This commit is contained in:
		
							parent
							
								
									cb57a52a85
								
							
						
					
					
						commit
						998c3856c1
					
				
					 5 changed files with 34 additions and 5 deletions
				
			
		|  | @ -1,3 +1,4 @@ | ||||||
|  | import atexit | ||||||
| import errno | import errno | ||||||
| import os | import os | ||||||
| import selectors | import selectors | ||||||
|  | @ -271,6 +272,8 @@ def sigchld_handler(*_unused): | ||||||
|                                 selector.close() |                                 selector.close() | ||||||
|                                 unused_fds = [alive_r, child_w, sig_r, sig_w] |                                 unused_fds = [alive_r, child_w, sig_r, sig_w] | ||||||
|                                 unused_fds.extend(pid_to_fd.values()) |                                 unused_fds.extend(pid_to_fd.values()) | ||||||
|  |                                 atexit._clear() | ||||||
|  |                                 atexit.register(util._exit_function) | ||||||
|                                 code = _serve_one(child_r, fds, |                                 code = _serve_one(child_r, fds, | ||||||
|                                                   unused_fds, |                                                   unused_fds, | ||||||
|                                                   old_handlers) |                                                   old_handlers) | ||||||
|  | @ -278,6 +281,7 @@ def sigchld_handler(*_unused): | ||||||
|                                 sys.excepthook(*sys.exc_info()) |                                 sys.excepthook(*sys.exc_info()) | ||||||
|                                 sys.stderr.flush() |                                 sys.stderr.flush() | ||||||
|                             finally: |                             finally: | ||||||
|  |                                 atexit._run_exitfuncs() | ||||||
|                                 os._exit(code) |                                 os._exit(code) | ||||||
|                         else: |                         else: | ||||||
|                             # Send pid to client process |                             # Send pid to client process | ||||||
|  |  | ||||||
|  | @ -1,3 +1,4 @@ | ||||||
|  | import atexit | ||||||
| import os | import os | ||||||
| import signal | import signal | ||||||
| 
 | 
 | ||||||
|  | @ -66,10 +67,13 @@ def _launch(self, process_obj): | ||||||
|         self.pid = os.fork() |         self.pid = os.fork() | ||||||
|         if self.pid == 0: |         if self.pid == 0: | ||||||
|             try: |             try: | ||||||
|  |                 atexit._clear() | ||||||
|  |                 atexit.register(util._exit_function) | ||||||
|                 os.close(parent_r) |                 os.close(parent_r) | ||||||
|                 os.close(parent_w) |                 os.close(parent_w) | ||||||
|                 code = process_obj._bootstrap(parent_sentinel=child_r) |                 code = process_obj._bootstrap(parent_sentinel=child_r) | ||||||
|             finally: |             finally: | ||||||
|  |                 atexit._run_exitfuncs() | ||||||
|                 os._exit(code) |                 os._exit(code) | ||||||
|         else: |         else: | ||||||
|             os.close(child_w) |             os.close(child_w) | ||||||
|  |  | ||||||
|  | @ -310,11 +310,8 @@ def _bootstrap(self, parent_sentinel=None): | ||||||
|                 # _run_after_forkers() is executed |                 # _run_after_forkers() is executed | ||||||
|                 del old_process |                 del old_process | ||||||
|             util.info('child process calling self.run()') |             util.info('child process calling self.run()') | ||||||
|             try: |             self.run() | ||||||
|                 self.run() |             exitcode = 0 | ||||||
|                 exitcode = 0 |  | ||||||
|             finally: |  | ||||||
|                 util._exit_function() |  | ||||||
|         except SystemExit as e: |         except SystemExit as e: | ||||||
|             if e.code is None: |             if e.code is None: | ||||||
|                 exitcode = 0 |                 exitcode = 0 | ||||||
|  |  | ||||||
|  | @ -6161,6 +6161,29 @@ def submain(): pass | ||||||
|         self.assertFalse(err, msg=err.decode('utf-8')) |         self.assertFalse(err, msg=err.decode('utf-8')) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | class _TestAtExit(BaseTestCase): | ||||||
|  | 
 | ||||||
|  |     ALLOWED_TYPES = ('processes',) | ||||||
|  | 
 | ||||||
|  |     @classmethod | ||||||
|  |     def _write_file_at_exit(self, output_path): | ||||||
|  |         import atexit | ||||||
|  |         def exit_handler(): | ||||||
|  |             with open(output_path, 'w') as f: | ||||||
|  |                 f.write("deadbeef") | ||||||
|  |         atexit.register(exit_handler) | ||||||
|  | 
 | ||||||
|  |     def test_atexit(self): | ||||||
|  |         # gh-83856 | ||||||
|  |         with os_helper.temp_dir() as temp_dir: | ||||||
|  |             output_path = os.path.join(temp_dir, 'output.txt') | ||||||
|  |             p = self.Process(target=self._write_file_at_exit, args=(output_path,)) | ||||||
|  |             p.start() | ||||||
|  |             p.join() | ||||||
|  |             with open(output_path) as f: | ||||||
|  |                 self.assertEqual(f.read(), 'deadbeef') | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| class MiscTestCase(unittest.TestCase): | class MiscTestCase(unittest.TestCase): | ||||||
|     def test__all__(self): |     def test__all__(self): | ||||||
|         # Just make sure names in not_exported are excluded |         # Just make sure names in not_exported are excluded | ||||||
|  |  | ||||||
|  | @ -0,0 +1 @@ | ||||||
|  | Honor :mod:`atexit` for all :mod:`multiprocessing` start methods | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Tian Gao
						Tian Gao