pidlock.py
134 lines
| 4.0 KiB
| text/x-python
|
PythonLexer
r1307 | import os | |||
r547 | import sys | |||
r1307 | import time | |||
import errno | ||||
r547 | from warnings import warn | |||
from multiprocessing.util import Finalize | ||||
r1549 | from rhodecode.lib.compat import kill | |||
r1307 | ||||
r2568 | ||||
r1307 | class LockHeld(Exception): | |||
pass | ||||
r547 | ||||
class DaemonLock(object): | ||||
"""daemon locking | ||||
USAGE: | ||||
try: | ||||
r1540 | l = DaemonLock(file_='/path/tolockfile',desc='test lock') | |||
r547 | main() | |||
l.release() | ||||
except LockHeld: | ||||
sys.exit(1) | ||||
""" | ||||
r1540 | def __init__(self, file_=None, callbackfn=None, | |||
r547 | desc='daemon lock', debug=False): | |||
r1540 | self.pidfile = file_ if file_ else os.path.join( | |||
r1307 | os.path.dirname(__file__), | |||
'running.lock') | ||||
r547 | 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): | ||||
r1307 | """ | |||
locking function, if lock is present it | ||||
will raise LockHeld exception | ||||
r547 | """ | |||
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()) | ||||
r1194 | ||||
r547 | pidfile.close() | |||
r1194 | ||||
r547 | if self.debug: | |||
r1307 | print ('lock file present running_pid: %s, ' | |||
'checking for execution') % running_pid | ||||
r547 | # Now we check the PID from lock file matches to the current | |||
# process PID | ||||
if running_pid: | ||||
try: | ||||
r1194 | kill(running_pid, 0) | |||
r547 | except OSError, exc: | |||
if exc.errno in (errno.ESRCH, errno.EPERM): | ||||
r1307 | print ("Lock File is there but" | |||
" the program is not running") | ||||
r1194 | print "Removing lock file for the: %s" % running_pid | |||
r547 | self.release() | |||
else: | ||||
raise | ||||
else: | ||||
print "You already have an instance of the program running" | ||||
r1194 | print "It is running as process %s" % running_pid | |||
r547 | raise LockHeld() | |||
r1194 | ||||
r547 | 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' | ||||
r1194 | ||||
r547 | 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 | ||||
r1307 | ||||
r604 | :param lockname: acctual pid of file | |||
:param pidfile: the file to write the pid in | ||||
r547 | """ | |||
if self.debug: | ||||
print 'creating a file %s and pid: %s' % (pidfile, lockname) | ||||
r2568 | ||||
dir_, file_ = os.path.split(pidfile) | ||||
if not os.path.isdir(dir_): | ||||
os.makedirs(dir_) | ||||
r547 | pidfile = open(self.pidfile, "wb") | |||
pidfile.write(lockname) | ||||
pidfile.close | ||||
self.held = True | ||||