comparison mercurial/util.py @ 10344:9501cde4c034

util: make spawndetached() handle subprocess early terminations The file-based synchronization introduced by e22695b4472f hangs when the child process fails before terminating the handshake, which the previous pipe-based version handled correctly. To fix this, the parent polling loop was fixed to detect premature terminations of the child process.
author Patrick Mezard <pmezard@gmail.com>
date Sat, 06 Feb 2010 16:50:00 +0100
parents 08a0f04b56bd
children 600142e7a028
comparison
equal deleted inserted replaced
10343:b8e3aeb7542c 10344:9501cde4c034
14 """ 14 """
15 15
16 from i18n import _ 16 from i18n import _
17 import error, osutil, encoding 17 import error, osutil, encoding
18 import cStringIO, errno, re, shutil, sys, tempfile, traceback 18 import cStringIO, errno, re, shutil, sys, tempfile, traceback
19 import os, stat, time, calendar, textwrap 19 import os, stat, time, calendar, textwrap, signal
20 import imp 20 import imp
21 21
22 # Python compatibility 22 # Python compatibility
23 23
24 def sha1(s): 24 def sha1(s):
1306 get either the python call or current executable. 1306 get either the python call or current executable.
1307 """ 1307 """
1308 if main_is_frozen(): 1308 if main_is_frozen():
1309 return [sys.executable] 1309 return [sys.executable]
1310 return gethgcmd() 1310 return gethgcmd()
1311
1312 def rundetached(args, condfn):
1313 """Execute the argument list in a detached process.
1314
1315 condfn is a callable which is called repeatedly and should return
1316 True once the child process is known to have started successfully.
1317 At this point, the child process PID is returned. If the child
1318 process fails to start or finishes before condfn() evaluates to
1319 True, return -1.
1320 """
1321 # Windows case is easier because the child process is either
1322 # successfully starting and validating the condition or exiting
1323 # on failure. We just poll on its PID. On Unix, if the child
1324 # process fails to start, it will be left in a zombie state until
1325 # the parent wait on it, which we cannot do since we expect a long
1326 # running process on success. Instead we listen for SIGCHLD telling
1327 # us our child process terminated.
1328 terminated = set()
1329 def handler(signum, frame):
1330 terminated.add(os.wait())
1331 prevhandler = None
1332 if hasattr(signal, 'SIGCHLD'):
1333 prevhandler = signal.signal(signal.SIGCHLD, handler)
1334 try:
1335 pid = spawndetached(args)
1336 while not condfn():
1337 if ((pid in terminated or not testpid(pid))
1338 and not condfn()):
1339 return -1
1340 time.sleep(0.1)
1341 return pid
1342 finally:
1343 if prevhandler is not None:
1344 signal.signal(signal.SIGCHLD, prevhandler)