serve: add and use portable spawnvp replacement
authorPatrick Mezard <pmezard@gmail.com>
Fri, 10 Apr 2009 21:20:25 +0200
changeset 10237 2f7a38f336f4
parent 10236 49a8625b8cac
child 10238 e22695b4472f
serve: add and use portable spawnvp replacement There is no standard python command to really detach a process under Windows. Instead we use the low level API wrapped by subprocess module with all necessary options to avoid any kind of context inheritance. Unfortunately, this version still opens a new window for the child process. The following have been tried: - os.spawnv(os.P_NOWAIT): works but the child process is killed when parent console terminates. - os.spawnv(os.P_DETACH): works on python25, hang on python26 when writing to the hgweb output socket. - subprocess.CreateProcess() hack without shell mode: similar to os.spawnv(os.P_DETACH). Fix 1/3 for issue421
mercurial/cmdutil.py
mercurial/posix.py
mercurial/windows.py
--- a/mercurial/cmdutil.py	Tue Jan 12 15:12:53 2010 +0100
+++ b/mercurial/cmdutil.py	Fri Apr 10 21:20:25 2009 +0200
@@ -580,8 +580,7 @@
             elif runargs[i].startswith('--cwd'):
                 del runargs[i:i+2]
                 break
-        pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
-                         runargs[0], runargs)
+        pid = util.spawndetached(runargs)
         os.close(wfd)
         os.read(rfd, 1)
         if parentfn:
--- a/mercurial/posix.py	Tue Jan 12 15:12:53 2010 +0100
+++ b/mercurial/posix.py	Fri Apr 10 21:20:25 2009 +0200
@@ -257,3 +257,8 @@
         return grp.getgrgid(gid)[0]
     except KeyError:
         return str(gid)
+
+def spawndetached(args):
+    return os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
+                      args[0], args)
+
--- a/mercurial/windows.py	Tue Jan 12 15:12:53 2010 +0100
+++ b/mercurial/windows.py	Fri Apr 10 21:20:25 2009 +0200
@@ -7,7 +7,7 @@
 
 from i18n import _
 import osutil, error
-import errno, msvcrt, os, re, sys, random
+import errno, msvcrt, os, re, sys, random, subprocess
 
 nulldev = 'NUL:'
 umask = 002
@@ -321,6 +321,37 @@
             pass
         os.rename(src, dst)
 
+def spawndetached(args):
+    # No standard library function really spawns a fully detached
+    # process under win32 because they allocate pipes or other objects
+    # to handle standard streams communications. Passing these objects
+    # to the child process requires handle inheritance to be enabled
+    # which makes really detached processes impossible.
+    class STARTUPINFO:
+        dwFlags = subprocess.STARTF_USESHOWWINDOW
+        hStdInput = None
+        hStdOutput = None
+        hStdError = None
+        wShowWindow = subprocess.SW_HIDE
+        
+    args = subprocess.list2cmdline(args)
+    # Not running the command in shell mode makes python26 hang when
+    # writing to hgweb output socket.
+    comspec = os.environ.get("COMSPEC", "cmd.exe")
+    args = comspec + " /c " + args
+    hp, ht, pid, tid = subprocess.CreateProcess(
+        None, args,
+        # no special security
+        None, None,
+        # Do not inherit handles
+        0,
+        # DETACHED_PROCESS
+        0x00000008,
+        os.environ,
+        os.getcwd(),
+        STARTUPINFO())
+    return pid
+
 try:
     # override functions with win32 versions if possible
     from win32 import *