import os import sys import time import errno from warnings import warn from multiprocessing.util import Finalize from rhodecode.lib.compat import kill class LockHeld(Exception): pass class DaemonLock(object): """daemon locking USAGE: try: l = DaemonLock(file_='/path/tolockfile',desc='test lock') main() l.release() except LockHeld: sys.exit(1) """ def __init__(self, file_=None, callbackfn=None, desc='daemon lock', debug=False): self.pidfile = file_ if file_ else os.path.join( os.path.dirname(__file__), 'running.lock') self.callbackfn = callbackfn self.desc = desc self.debug = debug self.held = False #run the lock automatically ! self.lock() self._finalize = Finalize(self, DaemonLock._on_finalize, args=(self, debug), exitpriority=10) @staticmethod def _on_finalize(lock, debug): if lock.held: if debug: print 'leck held finilazing and running lock.release()' lock.release() def lock(self): """ locking function, if lock is present it will raise LockHeld exception """ lockname = '%s' % (os.getpid()) if self.debug: print 'running lock' self.trylock() self.makelock(lockname, self.pidfile) return True def trylock(self): running_pid = False if self.debug: print 'checking for already running process' try: pidfile = open(self.pidfile, "r") pidfile.seek(0) running_pid = int(pidfile.readline()) pidfile.close() if self.debug: print ('lock file present running_pid: %s, ' 'checking for execution') % running_pid # Now we check the PID from lock file matches to the current # process PID if running_pid: try: kill(running_pid, 0) except OSError, exc: if exc.errno in (errno.ESRCH, errno.EPERM): print ("Lock File is there but" " the program is not running") print "Removing lock file for the: %s" % running_pid self.release() else: raise else: print "You already have an instance of the program running" print "It is running as process %s" % running_pid raise LockHeld() except IOError, e: if e.errno != 2: raise def release(self): """releases the pid by removing the pidfile """ if self.debug: print 'trying to release the pidlock' if self.callbackfn: #execute callback function on release if self.debug: print 'executing callback function %s' % self.callbackfn self.callbackfn() try: if self.debug: print 'removing pidfile %s' % self.pidfile os.remove(self.pidfile) self.held = False except OSError, e: if self.debug: print 'removing pidfile failed %s' % e pass def makelock(self, lockname, pidfile): """ this function will make an actual lock :param lockname: acctual pid of file :param pidfile: the file to write the pid in """ if self.debug: print 'creating a file %s and pid: %s' % (pidfile, lockname) dir_, file_ = os.path.split(pidfile) if not os.path.isdir(dir_): os.makedirs(dir_) pidfile = open(self.pidfile, "wb") pidfile.write(lockname) pidfile.close self.held = True