mirror of
				https://github.com/python/cpython.git
				synced 2025-10-30 21:21:22 +00:00 
			
		
		
		
	bpo-36867: Create the resource_tracker before launching SharedMemoryManagers (GH-13276)
This commit is contained in:
		
							parent
							
								
									be6939fb02
								
							
						
					
					
						commit
						b1dfcad6f0
					
				
					 3 changed files with 54 additions and 14 deletions
				
			
		|  | @ -21,6 +21,7 @@ | |||
| import array | ||||
| import queue | ||||
| import time | ||||
| import os | ||||
| from os import getpid | ||||
| 
 | ||||
| from traceback import format_exc | ||||
|  | @ -1349,6 +1350,14 @@ class SharedMemoryManager(BaseManager): | |||
|         _Server = SharedMemoryServer | ||||
| 
 | ||||
|         def __init__(self, *args, **kwargs): | ||||
|             if os.name == "posix": | ||||
|                 # bpo-36867: Ensure the resource_tracker is running before | ||||
|                 # launching the manager process, so that concurrent | ||||
|                 # shared_memory manipulation both in the manager and in the | ||||
|                 # current process does not create two resource_tracker | ||||
|                 # processes. | ||||
|                 from . import resource_tracker | ||||
|                 resource_tracker.ensure_running() | ||||
|             BaseManager.__init__(self, *args, **kwargs) | ||||
|             util.debug(f"{self.__class__.__name__} created by pid {getpid()}") | ||||
| 
 | ||||
|  |  | |||
|  | @ -17,6 +17,7 @@ | |||
| import socket | ||||
| import random | ||||
| import logging | ||||
| import subprocess | ||||
| import struct | ||||
| import operator | ||||
| import pickle | ||||
|  | @ -3765,6 +3766,27 @@ def test_shared_memory_SharedMemoryServer_ignores_sigint(self): | |||
| 
 | ||||
|         smm.shutdown() | ||||
| 
 | ||||
|     @unittest.skipIf(os.name != "posix", "resource_tracker is posix only") | ||||
|     def test_shared_memory_SharedMemoryManager_reuses_resource_tracker(self): | ||||
|         # bpo-36867: test that a SharedMemoryManager uses the | ||||
|         # same resource_tracker process as its parent. | ||||
|         cmd = '''if 1: | ||||
|             from multiprocessing.managers import SharedMemoryManager | ||||
| 
 | ||||
| 
 | ||||
|             smm = SharedMemoryManager() | ||||
|             smm.start() | ||||
|             sl = smm.ShareableList(range(10)) | ||||
|             smm.shutdown() | ||||
|         ''' | ||||
|         rc, out, err = test.support.script_helper.assert_python_ok('-c', cmd) | ||||
| 
 | ||||
|         # Before bpo-36867 was fixed, a SharedMemoryManager not using the same | ||||
|         # resource_tracker process as its parent would make the parent's | ||||
|         # tracker complain about sl being leaked even though smm.shutdown() | ||||
|         # properly released sl. | ||||
|         self.assertFalse(err) | ||||
| 
 | ||||
|     def test_shared_memory_SharedMemoryManager_basics(self): | ||||
|         smm1 = multiprocessing.managers.SharedMemoryManager() | ||||
|         with self.assertRaises(ValueError): | ||||
|  | @ -3904,8 +3926,6 @@ def test_shared_memory_ShareableList_pickling(self): | |||
|         sl.shm.close() | ||||
| 
 | ||||
|     def test_shared_memory_cleaned_after_process_termination(self): | ||||
|         import subprocess | ||||
|         from multiprocessing import shared_memory | ||||
|         cmd = '''if 1: | ||||
|             import os, time, sys | ||||
|             from multiprocessing import shared_memory | ||||
|  | @ -3916,18 +3936,29 @@ def test_shared_memory_cleaned_after_process_termination(self): | |||
|             sys.stdout.flush() | ||||
|             time.sleep(100) | ||||
|         ''' | ||||
|         p = subprocess.Popen([sys.executable, '-E', '-c', cmd], | ||||
|                              stdout=subprocess.PIPE) | ||||
|         name = p.stdout.readline().strip().decode() | ||||
|         with subprocess.Popen([sys.executable, '-E', '-c', cmd], | ||||
|                               stdout=subprocess.PIPE, | ||||
|                               stderr=subprocess.PIPE) as p: | ||||
|             name = p.stdout.readline().strip().decode() | ||||
| 
 | ||||
|         # killing abruptly processes holding reference to a shared memory | ||||
|         # segment should not leak the given memory segment. | ||||
|         p.terminate() | ||||
|         p.wait() | ||||
|         time.sleep(1.0)  # wait for the OS to collect the segment | ||||
|             # killing abruptly processes holding reference to a shared memory | ||||
|             # segment should not leak the given memory segment. | ||||
|             p.terminate() | ||||
|             p.wait() | ||||
|             time.sleep(1.0)  # wait for the OS to collect the segment | ||||
| 
 | ||||
|         with self.assertRaises(FileNotFoundError): | ||||
|             smm = shared_memory.SharedMemory(name, create=False) | ||||
|             # The shared memory file was deleted. | ||||
|             with self.assertRaises(FileNotFoundError): | ||||
|                 smm = shared_memory.SharedMemory(name, create=False) | ||||
| 
 | ||||
|             if os.name == 'posix': | ||||
|                 # A warning was emitted by the subprocess' own | ||||
|                 # resource_tracker (on Windows, shared memory segments | ||||
|                 # are released automatically by the OS). | ||||
|                 err = p.stderr.read().decode() | ||||
|                 self.assertIn( | ||||
|                     "resource_tracker: There appear to be 1 leaked " | ||||
|                     "shared_memory objects to clean up at shutdown", err) | ||||
| 
 | ||||
| # | ||||
| # | ||||
|  | @ -4560,7 +4591,7 @@ def run_in_child(cls): | |||
|         print(json.dumps(flags)) | ||||
| 
 | ||||
|     def test_flags(self): | ||||
|         import json, subprocess | ||||
|         import json | ||||
|         # start child process using unusual flags | ||||
|         prog = ('from test._test_multiprocessing import TestFlags; ' + | ||||
|                 'TestFlags.run_in_child()') | ||||
|  | @ -4866,7 +4897,6 @@ def test_resource_tracker(self): | |||
|         # | ||||
|         # Check that killing process does not leak named semaphores | ||||
|         # | ||||
|         import subprocess | ||||
|         cmd = '''if 1: | ||||
|             import time, os, tempfile | ||||
|             import multiprocessing as mp | ||||
|  |  | |||
|  | @ -0,0 +1 @@ | |||
| Fix a bug making a SharedMemoryManager instance and its parent process use two separate resource_tracker processes. | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Pierre Glaser
						Pierre Glaser