From: Ben Darnell Date: Thu, 5 Mar 2015 03:23:24 +0000 (-0500) Subject: Fix an error in autoreload on windows. X-Git-Tag: v4.2.0b1~83 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b52bb5c9e3b7f9e8bc93dbca4caa6ba0f0c23f02;p=thirdparty%2Ftornado.git Fix an error in autoreload on windows. Our pre-exec cleanup causes problems on platforms where we spawn a new process and call sys.exit. Closes #1360. --- diff --git a/tornado/autoreload.py b/tornado/autoreload.py index a548cf026..8856b8c77 100644 --- a/tornado/autoreload.py +++ b/tornado/autoreload.py @@ -100,6 +100,14 @@ try: except ImportError: signal = None +# os.execv is broken on Windows and can't properly parse command line +# arguments and executable name if they contain whitespaces. subprocess +# fixes that behavior. +# This distinction is also important because when we use execv, we want to +# close the IOLoop and all its file descriptors, to guard against any +# file descriptors that were not set CLOEXEC. When execv is not available, +# we must not close the IOLoop because we want the process to exit cleanly. +_has_execv = sys.platform != 'win32' _watched_files = set() _reload_hooks = [] @@ -119,7 +127,8 @@ def start(io_loop=None, check_time=500): _io_loops[io_loop] = True if len(_io_loops) > 1: gen_log.warning("tornado.autoreload started more than once in the same process") - add_reload_hook(functools.partial(io_loop.close, all_fds=True)) + if _has_execv: + add_reload_hook(functools.partial(io_loop.close, all_fds=True)) modify_times = {} callback = functools.partial(_reload_on_update, modify_times) scheduler = ioloop.PeriodicCallback(callback, check_time, io_loop=io_loop) @@ -215,10 +224,7 @@ def _reload(): not os.environ.get("PYTHONPATH", "").startswith(path_prefix)): os.environ["PYTHONPATH"] = (path_prefix + os.environ.get("PYTHONPATH", "")) - if sys.platform == 'win32': - # os.execv is broken on Windows and can't properly parse command line - # arguments and executable name if they contain whitespaces. subprocess - # fixes that behavior. + if not _has_execv: subprocess.Popen([sys.executable] + sys.argv) sys.exit(0) else: @@ -238,7 +244,10 @@ def _reload(): # this error specifically. os.spawnv(os.P_NOWAIT, sys.executable, [sys.executable] + sys.argv) - sys.exit(0) + # At this point the IOLoop has been closed and finally + # blocks will experience errors if we allow the stack to + # unwind, so just exit uncleanly. + os._exit(0) _USAGE = """\ Usage: