6 # of the GNU General Public License, incorporated herein by reference. |
6 # of the GNU General Public License, incorporated herein by reference. |
7 |
7 |
8 from demandload import * |
8 from demandload import * |
9 demandload(globals(), 'errno os socket time util') |
9 demandload(globals(), 'errno os socket time util') |
10 |
10 |
11 class LockException(Exception): |
11 class LockException(IOError): |
12 pass |
12 def __init__(self, errno, strerror, filename, desc): |
|
13 IOError.__init__(self, errno, strerror, filename) |
|
14 self.desc = desc |
|
15 |
13 class LockHeld(LockException): |
16 class LockHeld(LockException): |
14 pass |
17 def __init__(self, errno, filename, desc, locker): |
|
18 LockException.__init__(self, errno, 'Lock held', filename, desc) |
|
19 self.locker = locker |
|
20 |
15 class LockUnavailable(LockException): |
21 class LockUnavailable(LockException): |
16 pass |
22 pass |
17 |
23 |
18 class lock(object): |
24 class lock(object): |
19 # lock is symlink on platforms that support it, file on others. |
25 # lock is symlink on platforms that support it, file on others. |
22 # are atomic even over nfs. |
28 # are atomic even over nfs. |
23 |
29 |
24 # old-style lock: symlink to pid |
30 # old-style lock: symlink to pid |
25 # new-style lock: symlink to hostname:pid |
31 # new-style lock: symlink to hostname:pid |
26 |
32 |
27 def __init__(self, file, timeout=-1, releasefn=None): |
33 def __init__(self, file, timeout=-1, releasefn=None, desc=None): |
28 self.f = file |
34 self.f = file |
29 self.held = 0 |
35 self.held = 0 |
30 self.timeout = timeout |
36 self.timeout = timeout |
31 self.releasefn = releasefn |
37 self.releasefn = releasefn |
32 self.id = None |
38 self.id = None |
33 self.host = None |
39 self.host = None |
34 self.pid = None |
40 self.pid = None |
|
41 self.desc = desc |
35 self.lock() |
42 self.lock() |
36 |
43 |
37 def __del__(self): |
44 def __del__(self): |
38 self.release() |
45 self.release() |
39 |
46 |
62 self.held = 1 |
70 self.held = 1 |
63 except (OSError, IOError), why: |
71 except (OSError, IOError), why: |
64 if why.errno == errno.EEXIST: |
72 if why.errno == errno.EEXIST: |
65 locker = self.testlock() |
73 locker = self.testlock() |
66 if locker: |
74 if locker: |
67 raise LockHeld(locker) |
75 raise LockHeld(errno.EAGAIN, self.f, self.desc, |
|
76 locker) |
68 else: |
77 else: |
69 raise LockUnavailable(why) |
78 raise LockUnavailable(why.errno, why.strerror, |
|
79 why.filename, self.desc) |
70 |
80 |
71 def testlock(self): |
81 def testlock(self): |
72 '''return id of locker if lock is valid, else None.''' |
82 '''return id of locker if lock is valid, else None.''' |
73 # if old-style lock, we cannot tell what machine locker is on. |
83 # 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 |
84 # with new-style lock, if locker is on this machine, we can |