pidlock.py
119 lines
| 3.7 KiB
| text/x-python
|
PythonLexer
r497 | import os, time | |||
import sys | ||||
from warnings import warn | ||||
r506 | from multiprocessing.util import Finalize | |||
import errno | ||||
r497 | ||||
class LockHeld(Exception):pass | ||||
class DaemonLock(object): | ||||
"""daemon locking | ||||
USAGE: | ||||
try: | ||||
r504 | l = DaemonLock(desc='test lock') | |||
r497 | 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() | ||||
r506 | self._finalize = Finalize(self, DaemonLock._on_finalize, | |||
args=(self, debug), exitpriority=10) | ||||
r497 | ||||
r506 | @staticmethod | |||
def _on_finalize(lock, debug): | ||||
if lock.held: | ||||
if debug: | ||||
print 'leck held finilazing and running lock.release()' | ||||
lock.release() | ||||
r497 | ||||
def lock(self): | ||||
r504 | """locking function, if lock is present it will raise LockHeld exception | |||
r497 | """ | |||
lockname = '%s' % (os.getpid()) | ||||
r506 | if self.debug: | |||
print 'running lock' | ||||
r497 | self.trylock() | |||
self.makelock(lockname, self.pidfile) | ||||
return True | ||||
def trylock(self): | ||||
running_pid = False | ||||
r506 | if self.debug: | |||
print 'checking for already running process' | ||||
r497 | try: | |||
pidfile = open(self.pidfile, "r") | ||||
pidfile.seek(0) | ||||
r506 | running_pid = int(pidfile.readline()) | |||
pidfile.close() | ||||
r497 | 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: | ||||
r506 | try: | |||
os.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() | ||||
raise | ||||
r497 | else: | |||
r506 | print "You already have an instance of the program running" | |||
print "It is running as process %s" % running_pid | ||||
raise LockHeld() | ||||
r497 | except IOError, e: | |||
if e.errno != 2: | ||||
raise | ||||
def release(self): | ||||
r504 | """releases the pid by removing the pidfile | |||
r497 | """ | |||
r506 | if self.debug: | |||
print 'trying to release the pidlock' | ||||
r497 | 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) | ||||
pidfile = open(self.pidfile, "wb") | ||||
pidfile.write(lockname) | ||||
pidfile.close | ||||
self.held = True | ||||