Gaudi Framework, version v23r2

Home   Generated: Thu Jun 28 2012

locker.py

Go to the documentation of this file.
00001 ##########################################################
00002 ## stolen and (slighty) adapted from:
00003 ##  http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65203
00004 ##
00005 
00006 import os, time
00007 
00008 if os.name == 'nt':
00009     import msvcrt
00010 elif os.name == 'posix':
00011     import fcntl
00012     LOCK_EX = fcntl.F_WRLCK
00013     LOCK_SH = fcntl.F_RDLCK
00014     LOCK_NB = fcntl.F_UNLCK
00015 else:
00016     raise RuntimeError("Locker only defined for nt and posix platforms")
00017 
00018 if os.name == 'nt':
00019     def lock(file):
00020         """
00021         Lock first 10 bytes of a file.
00022         """ 
00023         pos = file.tell() # remember current position
00024         file.seek(0)
00025         # By default, python tries about 10 times, then throws an exception.
00026         # We want to wait forever.
00027         acquired = False
00028         while not acquired:
00029             try:
00030                 msvcrt.locking(file.fileno(),msvcrt.LK_LOCK,10)
00031                 acquired = True
00032             except IOError, x:
00033                 if x.errno != 36: # 36, AKA 'Resource deadlock avoided', is normal
00034                     raise
00035         file.seek(pos) # reset position
00036 
00037     def unlock(file):
00038         """
00039         Unlock first 10 bytes of a file.
00040         """ 
00041         pos = file.tell() # remember current position
00042         file.seek(0)
00043         msvcrt.locking(file.fileno(),msvcrt.LK_UNLCK,10)
00044         file.seek(pos) # reset position
00045 
00046 elif os.name =='posix':
00047     import socket, errno
00048 
00049     def _tmpFileName(fileName):
00050         return "%s.%s.%d" % ( fileName, socket.gethostname(), os.getpid() )
00051     def _lckFileName(fileName):
00052         return "%s.lock" % fileName
00053 
00054     def _linkCount( lockFileName ):
00055         try:
00056             return os.stat(lockFileName).st_nlink
00057         except OSError, e:
00058             if e.errno != errno.ENOENT:
00059                 raise
00060             return -1
00061     def _read(fileName):
00062         try:
00063             fp = open(fileName)
00064             try:     readFileName = fp.read()
00065             finally: fp.close()
00066             return readFileName
00067         except EnvironmentError, e:
00068             if e.errno != errno.ENOENT:
00069                 raise
00070             return None
00071             
00072     def _sleep(): time.sleep(8)
00073 
00074     def lock(file):
00075         fileName = file.name
00076         tmpFileName = _tmpFileName(fileName)
00077         fp = open( tmpFileName, "w" )
00078         fp.write( tmpFileName )
00079         fp.close()
00080 
00081         lockFileName = _lckFileName( fileName )
00082         while True:
00083             if _linkCount(lockFileName) != -1: _sleep()
00084             try:
00085                 os.link( tmpFileName, lockFileName )
00086                 # we acquired the lock
00087                 return
00088             except OSError, e:
00089                 if e.errno == errno.ENOENT:
00090                     pass
00091                 elif e.errno != errno.EEXIST:
00092                     os.unlink(tmpFileName)
00093                     raise
00094                 elif _linkCount( lockFileName ) != 2:
00095                     pass
00096                 elif _read(lockFileName) == tmpFileName:
00097                     raise
00098                 else:
00099                     # someone else owns that lock
00100                     pass
00101             ## didn't get the lock !!
00102             ## say something ?
00103             #print _id_()," failed to acquire the lock ..."
00104             _sleep()
00105             pass
00106         return
00107     
00108     def unlock(file):
00109         fileName = file.name
00110         tmpFileName  = _tmpFileName(fileName)
00111         lockFileName = _lckFileName( fileName )
00112 
00113         try:
00114             os.unlink( lockFileName )
00115         except OSError, e:
00116             if e.errno != errno.ENOENT:
00117                 raise
00118         # remove the tmp file
00119         try:
00120             os.unlink( tmpFileName )
00121         except OSError, e:
00122             if e.errno != errno.ENOENT:
00123                 raise
00124         return
00125 
00126 import logging
00127 ## Lock a file.
00128 #  The file for the lock is created if it doesn't exists and it the "temporary"
00129 #  argument is set to True it will also be deleted when the lock is not needed.
00130 #  The unlocking is done in the destructor (RAII pattern).
00131 class LockFile(object):
00132     def __init__(self, name, temporary = False):
00133         self.name = name
00134         self.temporary = temporary
00135         self.file = None
00136         self.log = logging.getLogger("LockFile")
00137         self.log.info("%s - Locking on %s", time.strftime("%Y-%m-%d_%H:%M:%S"), self.name)
00138         if not os.path.exists(name):
00139             mode = "w"
00140         else:
00141             self.temporary = False # I do not want to delete a file I didn't create
00142             mode = "r+"
00143         try:
00144             self.file = open(self.name, mode)
00145             lock(self.file)
00146         except:
00147             self.log.warning("Cannot acquire lock on %s", self.name)
00148     def __del__(self):
00149         if self.file:
00150             unlock(self.file)
00151             self.file.close()
00152             if self.temporary:
00153                 try:
00154                     os.remove(self.name)
00155                 except:
00156                     pass
00157             self.log.info("%s - Lock on %s released", time.strftime("%Y-%m-%d_%H:%M:%S"), self.name)
00158 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines

Generated at Thu Jun 28 2012 23:27:26 for Gaudi Framework, version v23r2 by Doxygen version 1.7.2 written by Dimitri van Heesch, © 1997-2004