Package gofer :: Package agent :: Module lock
[hide private]
[frames] | no frames]

Source Code for Module gofer.agent.lock

  1  # 
  2  # Copyright (c) 2011 Red Hat, Inc. 
  3  # 
  4  # This software is licensed to you under the GNU Lesser General Public 
  5  # License as published by the Free Software Foundation; either version 
  6  # 2 of the License (LGPLv2) or (at your option) any later version. 
  7  # There is NO WARRANTY for this software, express or implied, 
  8  # including the implied warranties of MERCHANTABILITY, 
  9  # NON-INFRINGEMENT, or FITNESS FOR A PARTICULAR PURPOSE. You should 
 10  # have received a copy of LGPLv2 along with this software; if not, see 
 11  # http://www.gnu.org/licenses/old-licenses/lgpl-2.0.txt. 
 12  # 
 13  # Jeff Ortel <jortel@redhat.com> 
 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 
 25   
 26   
27 -class LockFailed(Exception):
28 pass
29
30 -class NotLocked(Exception):
31 pass
32 33
34 -class LockFile:
35 """ 36 File based locking. 37 @ivar path: The absolute path to the lock file. 38 @type path: str 39 @ivar __fp: The I{file pointer} to the lock file. 40 @type __fp: I{file-like} pointer. 41 """ 42
43 - def __init__(self, path):
44 """ 45 @param path: The absolute path to the lock file. 46 @type path: str 47 """ 48 self.path = path 49 self.__fp = None 50 self.__mkdir(path)
51
52 - def acquire(self, blocking=True):
53 """ 54 Acquire the lockfile. 55 @param blocking: Wait for the lock. 56 @type blocking: bool 57 @return: self 58 @rtype: L{LockFile} 59 """ 60 fp = open(self.path, 'w') 61 if not blocking: 62 try: 63 fcntl.flock(fp.fileno(), fcntl.LOCK_EX|fcntl.LOCK_NB) 64 except IOError: 65 fp.close() 66 raise LockFailed(self.path) 67 else: 68 fcntl.flock(fp.fileno(), fcntl.LOCK_EX) 69 self.__fp = fp 70 self.setpid() 71 return self
72
73 - def release(self):
74 """ 75 Release the lockfile. 76 """ 77 try: 78 if self.__fp.closed: 79 return 80 fd = self.__fp.fileno() 81 self.__fp.close() 82 except: 83 pass
84
85 - def getpid(self):
86 """ 87 Get the process id. 88 @return: The pid in the lock file, else the current pid. 89 @rtype: int 90 """ 91 pid = 0 92 fp = open(self.path) 93 content = fp.read() 94 if content: 95 pid = int(content) 96 return pid
97
98 - def setpid(self, pid=os.getpid()):
99 """ 100 Write our procecss id and flush. 101 @param pid: The process ID. 102 @type pid: int 103 """ 104 self.__fp.seek(0) 105 self.__fp.write(str(pid)) 106 self.__fp.flush()
107
108 - def __mkdir(self, path):
109 dir = os.path.dirname(path) 110 if not os.path.exists(dir): 111 os.makedirs(dir)
112 113
114 -class Lock:
115 """ 116 File backed Reentrant lock. 117 """ 118
119 - def __init__(self, path):
120 self.__depth = 0 121 self.__mutex = RLock() 122 self.__lockf = LockFile(path)
123
124 - def acquire(self, blocking=1):
125 """ 126 Acquire the lock. 127 Acquire the mutex; acquire the lockfile. 128 @param blocking: Wait for the lock. 129 @type blocking: bool 130 @return: self 131 @rtype: L{Lock} 132 """ 133 self.__lock(blocking) 134 if self.__push() == 1: 135 try: 136 self.__lockf.acquire(blocking) 137 except: 138 self.__pop() 139 raise 140 return self
141
142 - def release(self):
143 """ 144 Release the lock. 145 Release the lockfile; release the mutex. 146 """ 147 if self.__pop() == 0: 148 self.__lockf.release() 149 self.__unlock() 150 return self
151
152 - def setpid(self, pid):
153 """ 154 Write our procecss id and flush. 155 @param pid: The process ID. 156 @type pid: int 157 """ 158 self.__lock() 159 try: 160 self.__lockf.setpid(pid) 161 finally: 162 self.__unlock()
163
164 - def __push(self):
165 """ 166 Increment the lock depth. 167 @return: The incremented depth 168 @rtype: int 169 """ 170 self.__lock() 171 try: 172 self.__depth += 1 173 return self.__depth 174 finally: 175 self.__unlock()
176
177 - def __pop(self):
178 """ 179 Decrement the lock depth. 180 @return: The decremented depth 181 @rtype: int 182 """ 183 self.__lock() 184 try: 185 if self.__depth > 0: 186 self.__depth -= 1 187 return self.__depth 188 finally: 189 self.__unlock()
190
191 - def __lock(self, blocking=1):
192 if not self.__mutex.acquire(blocking): 193 raise LockFailed()
194
195 - def __unlock(self):
196 self.__mutex.release()
197