##// END OF EJS Templates
transplant: restore dirstate correctly at unexpected failure...
transplant: restore dirstate correctly at unexpected failure Before this patch, transplant can't restore dirstate as expected at failure other than one while patching. This causes: - unexpected file status - dirstate refers already rollback-ed parent (only at failure of transplanting the 2nd or later revision) To restore dirstate correctly also at unexpected failure, this patch encloses scope of store lock and transaction by 'dirstateguard'. This is temporary fixing for stable branch. See DirstateTransactionPlan wiki page for detail about the future plan to treat dirstate consistently around scope boundary of transaction. https://mercurial.selenic.com/wiki/DirstateTransactionPlan This patch also adds 'if lock' examination for safety 'lock.release()', because creating 'dirstateguard' object may fail unexpectedly (e.g. IOError for saving dirstate). BTW, in the test script, putting section header '[extensions]' into '.hg/hgrc' is needed to fix incomplete disabling 'abort' extension at 4d1382fd96ff.

File last commit:

r25473:123c9903 default
r25879:99e88320 stable
Show More
killdaemons.py
95 lines | 3.0 KiB | text/x-python | PythonLexer
Matt Mackall
tests: add killdaemons helper script
r7344 #!/usr/bin/env python
Patrick Mezard
killdaemons: take file argument explicitely...
r17466 import os, sys, time, errno, signal
Matt Mackall
tests: add killdaemons helper script
r7344
Patrick Mezard
killdaemons: add windows implementation
r17465 if os.name =='nt':
import ctypes
Simon Heimberg
tests: kill for windows in killdaemons.py checks return values...
r20493
def _check(ret, expectederr=None):
if ret == 0:
winerrno = ctypes.GetLastError()
if winerrno == expectederr:
return True
raise ctypes.WinError(winerrno)
Patrick Mezard
killdaemons: add windows implementation
r17465 def kill(pid, logfn, tryhard=True):
logfn('# Killing daemon process %d' % pid)
PROCESS_TERMINATE = 1
Simon Heimberg
tests: killdaemons.py for windows distinguishes access violation and terminated...
r20496 PROCESS_QUERY_INFORMATION = 0x400
Augie Fackler
killdaemons: drop superfluous L suffix from constant...
r20698 SYNCHRONIZE = 0x00100000
Simon Heimberg
tests: killdaemons.py for windows waits for killed process to terminate...
r20494 WAIT_OBJECT_0 = 0
WAIT_TIMEOUT = 258
Patrick Mezard
killdaemons: add windows implementation
r17465 handle = ctypes.windll.kernel32.OpenProcess(
Simon Heimberg
tests: killdaemons.py for windows distinguishes access violation and terminated...
r20496 PROCESS_TERMINATE|SYNCHRONIZE|PROCESS_QUERY_INFORMATION,
False, pid)
Simon Heimberg
tests: kill for windows in killdaemons.py checks return values...
r20493 if handle == 0:
Simon Heimberg
tests: killdaemons.py for checks reason when getting no process handle
r20495 _check(0, 87) # err 87 when process not found
Simon Heimberg
tests: kill for windows in killdaemons.py checks return values...
r20493 return # process not found, already finished
try:
Simon Heimberg
tests: killdaemons.py for windows distinguishes access violation and terminated...
r20496 r = ctypes.windll.kernel32.WaitForSingleObject(handle, 100)
if r == WAIT_OBJECT_0:
pass # terminated, but process handle still available
elif r == WAIT_TIMEOUT:
_check(ctypes.windll.kernel32.TerminateProcess(handle, -1))
else:
_check(r)
Simon Heimberg
tests: killdaemons.py for windows waits for killed process to terminate...
r20494
# TODO?: forcefully kill when timeout
# and ?shorter waiting time? when tryhard==True
r = ctypes.windll.kernel32.WaitForSingleObject(handle, 100)
# timeout = 100 ms
if r == WAIT_OBJECT_0:
pass # process is terminated
elif r == WAIT_TIMEOUT:
logfn('# Daemon process %d is stuck')
else:
Yuya Nishihara
killdaemons: correct typo of _check() function caught by pyflakes
r21194 _check(r) # any error
Simon Heimberg
tests: kill for windows in killdaemons.py checks return values...
r20493 except: #re-raises
ctypes.windll.kernel32.CloseHandle(handle) # no _check, keep error
raise
_check(ctypes.windll.kernel32.CloseHandle(handle))
Patrick Mezard
killdaemons: add windows implementation
r17465 else:
def kill(pid, logfn, tryhard=True):
try:
os.kill(pid, 0)
logfn('# Killing daemon process %d' % pid)
os.kill(pid, signal.SIGTERM)
if tryhard:
for i in range(10):
time.sleep(0.05)
os.kill(pid, 0)
else:
time.sleep(0.1)
os.kill(pid, 0)
logfn('# Daemon process %d is stuck - really killing it' % pid)
os.kill(pid, signal.SIGKILL)
Augie Fackler
python3: update killdaemons and run-tests print and exception syntax...
r25031 except OSError as err:
Patrick Mezard
killdaemons: add windows implementation
r17465 if err.errno != errno.ESRCH:
raise
Patrick Mezard
run-tests: do not duplicate killdaemons() code
r17464 def killdaemons(pidfile, tryhard=True, remove=False, logfn=None):
if not logfn:
logfn = lambda s: s
# Kill off any leftover daemon processes
try:
fp = open(pidfile)
for line in fp:
try:
pid = int(line)
except ValueError:
continue
Patrick Mezard
killdaemons: add windows implementation
r17465 kill(pid, logfn, tryhard)
Patrick Mezard
run-tests: do not duplicate killdaemons() code
r17464 fp.close()
if remove:
os.unlink(pidfile)
except IOError:
pass
if __name__ == '__main__':
Matt Mackall
tests: make killdaemons.py use DAEMON_PIDS by default
r25473 if len(sys.argv) > 1:
path, = sys.argv[1:]
else:
path = os.environ["DAEMON_PIDS"]
Patrick Mezard
killdaemons: take file argument explicitely...
r17466 killdaemons(path)