##// END OF EJS Templates
change lock format to let us detect and break stale locks....
Vadim Gelfer -
r1877:d314a89f default
parent child Browse files
Show More
@@ -6,7 +6,7 b''
6 6 # of the GNU General Public License, incorporated herein by reference.
7 7
8 8 from demandload import *
9 demandload(globals(), 'errno os time util')
9 demandload(globals(), 'errno os socket time util')
10 10
11 11 class LockException(Exception):
12 12 pass
@@ -16,11 +16,22 b' class LockUnavailable(LockException):'
16 16 pass
17 17
18 18 class lock(object):
19 # lock is symlink on platforms that support it, file on others.
20
21 # symlink is used because create of directory entry and contents
22 # are atomic even over nfs.
23
24 # old-style lock: symlink to pid
25 # new-style lock: symlink to hostname:pid
26
19 27 def __init__(self, file, timeout=-1, releasefn=None):
20 28 self.f = file
21 29 self.held = 0
22 30 self.timeout = timeout
23 31 self.releasefn = releasefn
32 self.id = None
33 self.host = None
34 self.pid = None
24 35 self.lock()
25 36
26 37 def __del__(self):
@@ -41,15 +52,50 b' class lock(object):'
41 52 raise inst
42 53
43 54 def trylock(self):
44 pid = os.getpid()
55 if self.id is None:
56 self.host = socket.gethostname()
57 self.pid = os.getpid()
58 self.id = '%s:%s' % (self.host, self.pid)
59 while not self.held:
60 try:
61 util.makelock(self.id, self.f)
62 self.held = 1
63 except (OSError, IOError), why:
64 if why.errno == errno.EEXIST:
65 locker = self.testlock()
66 if locker:
67 raise LockHeld(locker)
68 else:
69 raise LockUnavailable(why)
70
71 def testlock(self):
72 '''return id of locker if lock is valid, else None.'''
73 # if old-style lock, we cannot tell what machine locker is on.
74 # with new-style lock, if locker is on this machine, we can
75 # see if locker is alive. if locker is on this machine but
76 # not alive, we can safely break lock.
77 locker = util.readlock(self.f)
78 c = locker.find(':')
79 if c == -1:
80 return locker
81 host = locker[:c]
82 if host != self.host:
83 return locker
45 84 try:
46 util.makelock(str(pid), self.f)
47 self.held = 1
48 except (OSError, IOError), why:
49 if why.errno == errno.EEXIST:
50 raise LockHeld(util.readlock(self.f))
51 else:
52 raise LockUnavailable(why)
85 pid = int(locker[c+1:])
86 except:
87 return locker
88 if util.testpid(pid):
89 return locker
90 # if locker dead, break lock. must do this with another lock
91 # held, or can race and break valid lock.
92 try:
93 l = lock(self.f + '.break')
94 l.trylock()
95 os.unlink(self.f)
96 l.release()
97 except (LockHeld, LockUnavailable):
98 return locker
53 99
54 100 def release(self):
55 101 if self.held:
@@ -499,7 +499,7 b" if os.name == 'nt':"
499 499 return pf
500 500
501 501 try: # ActivePython can create hard links using win32file module
502 import win32file
502 import win32api, win32con, win32file
503 503
504 504 def os_link(src, dst): # NB will only succeed on NTFS
505 505 win32file.CreateHardLink(dst, src)
@@ -516,8 +516,18 b" if os.name == 'nt':"
516 516 except:
517 517 return os.stat(pathname).st_nlink
518 518
519 def testpid(pid):
520 '''return False if pid is dead, True if running or not known'''
521 try:
522 win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION,
523 False, pid)
524 except:
525 return True
526
519 527 except ImportError:
520 pass
528 def testpid(pid):
529 '''return False if pid dead, True if running or not known'''
530 return True
521 531
522 532 def is_exec(f, last):
523 533 return last
@@ -614,6 +624,14 b' else:'
614 624 else:
615 625 raise
616 626
627 def testpid(pid):
628 '''return False if pid dead, True if running or not sure'''
629 try:
630 os.kill(pid, 0)
631 return True
632 except OSError, inst:
633 return inst.errno != errno.ESRCH
634
617 635 def explain_exit(code):
618 636 """return a 2-tuple (desc, code) describing a process's status"""
619 637 if os.WIFEXITED(code):
General Comments 0
You need to be logged in to leave comments. Login now