mirror of https://github.com/python/cpython
Issue #13841: Make child processes exit using sys.exit() on Windows
This commit is contained in:
parent
bc07cb883e
commit
73d9a292ae
|
@ -13,7 +13,7 @@ import signal
|
|||
|
||||
from multiprocessing import util, process
|
||||
|
||||
__all__ = ['Popen', 'assert_spawning', 'exit', 'duplicate', 'close', 'ForkingPickler']
|
||||
__all__ = ['Popen', 'assert_spawning', 'duplicate', 'close', 'ForkingPickler']
|
||||
|
||||
#
|
||||
# Check that the current thread is spawning a child process
|
||||
|
@ -75,7 +75,6 @@ else:
|
|||
#
|
||||
|
||||
if sys.platform != 'win32':
|
||||
exit = os._exit
|
||||
duplicate = os.dup
|
||||
close = os.close
|
||||
|
||||
|
@ -168,7 +167,6 @@ else:
|
|||
WINEXE = (sys.platform == 'win32' and getattr(sys, 'frozen', False))
|
||||
WINSERVICE = sys.executable.lower().endswith("pythonservice.exe")
|
||||
|
||||
exit = _winapi.ExitProcess
|
||||
close = _winapi.CloseHandle
|
||||
|
||||
#
|
||||
|
@ -349,7 +347,7 @@ else:
|
|||
from_parent.close()
|
||||
|
||||
exitcode = self._bootstrap()
|
||||
exit(exitcode)
|
||||
sys.exit(exitcode)
|
||||
|
||||
|
||||
def get_preparation_data(name):
|
||||
|
|
|
@ -22,7 +22,7 @@ import queue
|
|||
from traceback import format_exc
|
||||
from multiprocessing import Process, current_process, active_children, Pool, util, connection
|
||||
from multiprocessing.process import AuthenticationString
|
||||
from multiprocessing.forking import exit, Popen, ForkingPickler
|
||||
from multiprocessing.forking import Popen, ForkingPickler
|
||||
from time import time as _time
|
||||
|
||||
#
|
||||
|
@ -140,28 +140,38 @@ class Server(object):
|
|||
self.id_to_obj = {'0': (None, ())}
|
||||
self.id_to_refcount = {}
|
||||
self.mutex = threading.RLock()
|
||||
self.stop = 0
|
||||
|
||||
def serve_forever(self):
|
||||
'''
|
||||
Run the server forever
|
||||
'''
|
||||
self.stop_event = threading.Event()
|
||||
current_process()._manager_server = self
|
||||
try:
|
||||
accepter = threading.Thread(target=self.accepter)
|
||||
accepter.daemon = True
|
||||
accepter.start()
|
||||
try:
|
||||
while 1:
|
||||
try:
|
||||
c = self.listener.accept()
|
||||
except (OSError, IOError):
|
||||
continue
|
||||
t = threading.Thread(target=self.handle_request, args=(c,))
|
||||
t.daemon = True
|
||||
t.start()
|
||||
while not self.stop_event.is_set():
|
||||
self.stop_event.wait(1)
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
pass
|
||||
finally:
|
||||
self.stop = 999
|
||||
self.listener.close()
|
||||
if sys.stdout != sys.__stdout__:
|
||||
util.debug('resetting stdout, stderr')
|
||||
sys.stdout = sys.__stdout__
|
||||
sys.stderr = sys.__stderr__
|
||||
sys.exit(0)
|
||||
|
||||
def accepter(self):
|
||||
while True:
|
||||
try:
|
||||
c = self.listener.accept()
|
||||
except (OSError, IOError):
|
||||
continue
|
||||
t = threading.Thread(target=self.handle_request, args=(c,))
|
||||
t.daemon = True
|
||||
t.start()
|
||||
|
||||
def handle_request(self, c):
|
||||
'''
|
||||
|
@ -208,7 +218,7 @@ class Server(object):
|
|||
send = conn.send
|
||||
id_to_obj = self.id_to_obj
|
||||
|
||||
while not self.stop:
|
||||
while not self.stop_event.is_set():
|
||||
|
||||
try:
|
||||
methodname = obj = None
|
||||
|
@ -318,32 +328,13 @@ class Server(object):
|
|||
Shutdown this process
|
||||
'''
|
||||
try:
|
||||
try:
|
||||
util.debug('manager received shutdown message')
|
||||
c.send(('#RETURN', None))
|
||||
|
||||
if sys.stdout != sys.__stdout__:
|
||||
util.debug('resetting stdout, stderr')
|
||||
sys.stdout = sys.__stdout__
|
||||
sys.stderr = sys.__stderr__
|
||||
|
||||
util._run_finalizers(0)
|
||||
|
||||
for p in active_children():
|
||||
util.debug('terminating a child process of manager')
|
||||
p.terminate()
|
||||
|
||||
for p in active_children():
|
||||
util.debug('terminating a child process of manager')
|
||||
p.join()
|
||||
|
||||
util._run_finalizers()
|
||||
util.info('manager exiting with exitcode 0')
|
||||
except:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
util.debug('manager received shutdown message')
|
||||
c.send(('#RETURN', None))
|
||||
except:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
finally:
|
||||
exit(0)
|
||||
self.stop_event.set()
|
||||
|
||||
def create(self, c, typeid, *args, **kwds):
|
||||
'''
|
||||
|
|
|
@ -269,21 +269,24 @@ _exiting = False
|
|||
def _exit_function():
|
||||
global _exiting
|
||||
|
||||
info('process shutting down')
|
||||
debug('running all "atexit" finalizers with priority >= 0')
|
||||
_run_finalizers(0)
|
||||
if not _exiting:
|
||||
_exiting = True
|
||||
|
||||
for p in active_children():
|
||||
if p._daemonic:
|
||||
info('calling terminate() for daemon %s', p.name)
|
||||
p._popen.terminate()
|
||||
info('process shutting down')
|
||||
debug('running all "atexit" finalizers with priority >= 0')
|
||||
_run_finalizers(0)
|
||||
|
||||
for p in active_children():
|
||||
info('calling join() for process %s', p.name)
|
||||
p.join()
|
||||
for p in active_children():
|
||||
if p._daemonic:
|
||||
info('calling terminate() for daemon %s', p.name)
|
||||
p._popen.terminate()
|
||||
|
||||
debug('running the remaining "atexit" finalizers')
|
||||
_run_finalizers()
|
||||
for p in active_children():
|
||||
info('calling join() for process %s', p.name)
|
||||
p.join()
|
||||
|
||||
debug('running the remaining "atexit" finalizers')
|
||||
_run_finalizers()
|
||||
|
||||
atexit.register(_exit_function)
|
||||
|
||||
|
|
|
@ -1593,7 +1593,7 @@ def strip_python_stderr(stderr):
|
|||
This will typically be run on the result of the communicate() method
|
||||
of a subprocess.Popen object.
|
||||
"""
|
||||
stderr = re.sub(br"\[\d+ refs\]\r?\n?$", b"", stderr).strip()
|
||||
stderr = re.sub(br"\[\d+ refs\]\r?\n?", b"", stderr).strip()
|
||||
return stderr
|
||||
|
||||
def args_from_interpreter_flags():
|
||||
|
|
|
@ -1564,6 +1564,11 @@ class _TestMyManager(BaseTestCase):
|
|||
|
||||
manager.shutdown()
|
||||
|
||||
# If the manager process exited cleanly then the exitcode
|
||||
# will be zero. Otherwise (after a short timeout)
|
||||
# terminate() is used, resulting in an exitcode of -SIGTERM.
|
||||
self.assertEqual(manager._process.exitcode, 0)
|
||||
|
||||
#
|
||||
# Test of connecting to a remote server and using xmlrpclib for serialization
|
||||
#
|
||||
|
|
Loading…
Reference in New Issue