Mercurial > public > mercurial-scm > hg
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) |