]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
Fix an error in autoreload on windows.
authorBen Darnell <ben@bendarnell.com>
Thu, 5 Mar 2015 03:23:24 +0000 (22:23 -0500)
committerBen Darnell <ben@bendarnell.com>
Thu, 5 Mar 2015 03:23:24 +0000 (22:23 -0500)
Our pre-exec cleanup causes problems on platforms where we spawn
a new process and call sys.exit.

Closes #1360.

tornado/autoreload.py

index a548cf02624f1afc42edf15ea2fa5717f709d589..8856b8c77c6cf86ebff752d99113228264bfa9c2 100644 (file)
@@ -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: