[PATCH 1 of 3] serve: add and use portable spawnvp replacement

Steve Borho steve at borho.org
Sat Jan 9 00:09:38 CST 2010


On Wed, Jan 6, 2010 at 2:59 PM, Patrick Mezard <pmezard at gmail.com> wrote:
> # HG changeset patch
> # User Patrick Mezard <pmezard at gmail.com>
> # Date 1239391225 -7200
> # Node ID 92ac4240b6e0e3c1b959eb481f0e058e61ee705a
> # Parent  3ab391dd5ec5ab1f4af06169bde7a9c850a7f4ce
> 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.
>
> Fix 1/3 for issue421
>
> diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
> --- a/mercurial/cmdutil.py
> +++ b/mercurial/cmdutil.py
> @@ -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:
> diff --git a/mercurial/posix.py b/mercurial/posix.py
> --- a/mercurial/posix.py
> +++ b/mercurial/posix.py
> @@ -245,3 +245,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)
> +
> diff --git a/mercurial/windows.py b/mercurial/windows.py
> --- a/mercurial/windows.py
> +++ b/mercurial/windows.py
> @@ -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
> @@ -59,6 +59,16 @@
>             self.close()
>             raise IOError(errno.EPIPE, 'Broken pipe')
>
> +    # Standard streams descriptors are set to -1 in child processes
> +    # not inheriting their parent handles. And raise IOError instead of
> +    # ignoring read/write calls.
> +    if not hasattr(sys.stdin, 'fileno') or sys.stdin.fileno() == -1:
> +        sys.stdin = open(nulldev, 'r')
> +    if not hasattr(sys.stderr, 'fileno') or sys.stderr.fileno() == -1:
> +        sys.stderr = open(nulldev, 'w')
> +    if not hasattr(sys.stdout, 'fileno') or sys.stdout.fileno() == -1:
> +        sys.stdout = open(nulldev, 'w')
> +
>  sys.stdout = winstdout(sys.stdout)
>
>  def _is_win_9x():
> @@ -321,6 +331,35 @@
>             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 = 0
> +        hStdInput = None
> +        hStdOutput = None
> +        hStdError = None
> +        wShowWindow = 0
> +
> +    path = args[0]
> +    args = subprocess.list2cmdline(args)
> +    hp, ht, pid, tid = subprocess.CreateProcess(
> +        path, 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 *

hgtk has been using:

os.spawnve(os.P_NOWAIT, sys.executable, args, env)

to spawn new processes since about version 0.8.  Would that work for
the http daemon?

--
Steve Borho


More information about the Mercurial-devel mailing list