##// END OF EJS Templates
util: make spawndetached() handle subprocess early terminations...
Patrick Mezard -
r10344:9501cde4 default
parent child Browse files
Show More
@@ -584,9 +584,11 b' def service(opts, parentfn=None, initfn='
584 elif runargs[i].startswith('--cwd'):
584 elif runargs[i].startswith('--cwd'):
585 del runargs[i:i + 2]
585 del runargs[i:i + 2]
586 break
586 break
587 pid = util.spawndetached(runargs)
587 def condfn():
588 while os.path.exists(lockpath):
588 return not os.path.exists(lockpath)
589 time.sleep(0.1)
589 pid = util.rundetached(runargs, condfn)
590 if pid < 0:
591 raise util.Abort(_('child process failed to start'))
590 finally:
592 finally:
591 try:
593 try:
592 os.unlink(lockpath)
594 os.unlink(lockpath)
@@ -16,7 +16,7 b' hide platform-specific details from the '
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
@@ -1308,3 +1308,37 b' def hgcmd():'
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)
@@ -1,6 +1,6 b''
1 % fail
1 % fail
2 abort: inotify-server: cannot start: .hg/inotify.sock is a broken symlink
2 abort: inotify-server: cannot start: .hg/inotify.sock is a broken symlink
3 inotify-client: could not talk to new inotify server: No such file or directory
3 inotify-client: could not start inotify server: child process failed to start
4 abort: inotify-server: cannot start: .hg/inotify.sock is a broken symlink
4 abort: inotify-server: cannot start: .hg/inotify.sock is a broken symlink
5 % inserve
5 % inserve
6 % status
6 % status
General Comments 0
You need to be logged in to leave comments. Login now