Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/util.py @ 36724:d77c3b023393
lock: block signal interrupt while making a lock file
On Windows where symlink isn't supported, util.makelock() could leave an empty
file if interrupted immediately after os.open(). This empty lock never dies
as it has no process id recorded.
ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
# an interrupt may occur here
os.write(ld, info)
os.close(ld)
This was a long-standing bug of TortoiseHg which runs a command-server and
kills it by CTRL_C_EVENT, reported by random Windows users.
https://bitbucket.org/tortoisehg/thg/issues/4873/#comment-43591129
At first, I tried to fix makelock() to clean up a stale lock file, which
turned out to be hard because any instructions may be interrupted by a
signal.
ld = None
try:
# CALL_FUNCTION # os.open(...)
# an interrupt may occur here
# STORE_FAST # ld = ...
ld = os.open(pathname, os.O_CREAT | os.O_WRONLY | os.O_EXCL)
os.write(ld, info)
...
return True
except:
if ld:
...
os.unlink(pathname)
return False
So I decided to block signals by temporarily replacing the signal handlers
so makelcok() and held = 1 will never be interrupted.
Many thanks to Fernando Najera for investigating the issue.
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Sat, 03 Mar 2018 23:49:39 -0500 |
parents | aa9c5d447980 |
children | ca201470abb4 |
comparison
equal
deleted
inserted
replaced
36723:e437de3881c1 | 36724:d77c3b023393 |
---|---|
1674 | 1674 |
1675 if safehasattr(time, "perf_counter"): | 1675 if safehasattr(time, "perf_counter"): |
1676 timer = time.perf_counter | 1676 timer = time.perf_counter |
1677 | 1677 |
1678 def makelock(info, pathname): | 1678 def makelock(info, pathname): |
1679 """Create a lock file atomically if possible | |
1680 | |
1681 This may leave a stale lock file if symlink isn't supported and signal | |
1682 interrupt is enabled. | |
1683 """ | |
1679 try: | 1684 try: |
1680 return os.symlink(info, pathname) | 1685 return os.symlink(info, pathname) |
1681 except OSError as why: | 1686 except OSError as why: |
1682 if why.errno == errno.EEXIST: | 1687 if why.errno == errno.EEXIST: |
1683 raise | 1688 raise |