1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 """
17 Contains locking classes.
18 """
19
20 import os
21 import re
22 import time
23 import fcntl
24 from threading import RLock as Mutex
25
26
29
30
32 """
33 File based locking.
34 @ivar path: The absolute path to the lock file.
35 @type path: str
36 @ivar pid: current process id.
37 @type pid: int
38 @ivar fp: The I{file pointer} to the lock file.
39 @ivar fp: I{file-like} pointer.
40 """
41
43 """
44 @param path: The absolute path to the lock file.
45 @type path: str
46 """
47 self.path = path
48 self.pid = None
49 self.fp = None
50
52 """
53 Open the lock file.
54 Created in not exists. Opened with file locking.
55 """
56 if self.notcreated():
57 self.fp = open(self.path, 'w')
58 self.setpid()
59 self.close()
60 self.fp = open(self.path, 'r+')
61 fd = self.fp.fileno()
62 fcntl.flock(fd, fcntl.LOCK_EX)
63
65 """
66 Get the process id.
67 @return: The pid in the lock file, else the current pid.
68 @rtype: int
69 """
70 if self.pid is None:
71 content = self.fp.read().strip()
72 if content:
73 self.pid = int(content)
74 return self.pid
75
77 """
78 Write our procecss id and flush.
79 @param pid: The process ID.
80 @type pid: int
81 """
82 self.fp.seek(0)
83 content = str(pid)
84 self.fp.write(content)
85 self.fp.flush()
86
88 """
89 Get the current process id.
90 @return: This process id.
91 @rtype: int
92 """
93 return ( os.getpid() == self.getpid() )
94
96 """
97 Get whether the pid in the file is valid.
98 @return: True if valid.
99 @rtype: bool
100 """
101 status = False
102 try:
103 os.kill(self.getpid(), 0)
104 status = True
105 except Exception, e:
106 pass
107 return status
108
110 """
111 Delete the lock file.
112 """
113 if self.mypid() or not self.valid():
114 self.close()
115 os.unlink(self.path)
116
118 """
119 Close the file and release the file lock.
120 Reset pid & fp to (None).
121 """
122 try:
123 fd = self.fp.fileno()
124 fcntl.flock(fd, fcntl.LOCK_UN)
125 self.fp.close()
126 except:
127 pass
128 self.pid = None
129 self.fp = None
130
132 """
133 Get if file not created.
134 @return: True if file not created.
135 @rtype: bool
136 """
137 return ( not os.path.exists(self.path) )
138
140 """ cleanup """
141 self.close()
142
143
145 """
146 File backed Reentrant lock.
147 @cvar mutex: A thread mutex.
148 @type mutex: L{Mutex}
149 """
150
151 mutex = Mutex()
152
154 self.depth = 0
155 self.path = path
156 dir, fn = os.path.split(self.path)
157 if not os.path.exists(dir):
158 os.makedirs(dir)
159
161 """
162 Acquire the lock.
163 @param wait: Indicates call will block and wait for the lock.
164 @type wait: boolean
165 """
166 f = LockFile(self.path)
167 try:
168 while True:
169 f.open()
170 pid = f.getpid()
171 if f.mypid():
172 self.P()
173 return
174 if f.valid():
175 f.close()
176 if wait:
177 time.sleep(0.5)
178 else:
179 raise LockFailed()
180 else:
181 break
182 self.P()
183 f.setpid()
184 finally:
185 f.close()
186
188 """
189 Update the process ID.
190 @param pid: The process ID.
191 @type pid: int
192 """
193 if not self.acquired():
194 raise Exception, 'not acquired'
195 f = LockFile(self.path)
196 try:
197 f.open()
198 f.setpid(pid)
199 finally:
200 f.close()
201
203 """
204 Release the lock.
205 """
206 if not self.acquired():
207 return
208 self.V()
209 if self.acquired():
210 return
211 f = LockFile(self.path)
212 try:
213 f.open()
214 f.delete()
215 finally:
216 f.close()
217
219 """
220 Test to see if acquired.
221 @return: True if acquired.
222 @rtype: bool
223 """
224 mutex = self.mutex
225 mutex.acquire()
226 try:
227 return ( self.depth > 0 )
228 finally:
229 mutex.release()
230
232 """
233 Do semiphore (P) operation.
234 @return: self
235 @rtype: L{Lock}
236 """
237 mutex = self.mutex
238 mutex.acquire()
239 try:
240 self.depth += 1
241 finally:
242 mutex.release()
243 return self
244
246 """
247 Do semiphore (V) operation.
248 @return: self
249 @rtype: L{Lock}
250 """
251 mutex = self.mutex
252 mutex.acquire()
253 try:
254 if self.acquired():
255 self.depth -= 1
256 finally:
257 mutex.release()
258 return self
259
261 try:
262 self.release()
263 except:
264 pass
265