pidlock.py
133 lines
| 4.0 KiB
| text/x-python
|
PythonLexer
r547 | import os, time | |||
import sys | ||||
from warnings import warn | ||||
from multiprocessing.util import Finalize | ||||
import errno | ||||
r1194 | from rhodecode import __platform__, PLATFORM_WIN | |||
if __platform__ in PLATFORM_WIN: | ||||
import ctypes | ||||
def kill(pid): | ||||
"""kill function for Win32""" | ||||
kernel32 = ctypes.windll.kernel32 | ||||
handle = kernel32.OpenProcess(1, 0, pid) | ||||
return (0 != kernel32.TerminateProcess(handle, 0)) | ||||
else: | ||||
kill = os.kill | ||||
r547 | class LockHeld(Exception):pass | |||
class DaemonLock(object): | ||||
"""daemon locking | ||||
USAGE: | ||||
try: | ||||
l = DaemonLock(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()) | ||||
r1194 | ||||
r547 | pidfile.close() | |||
r1194 | ||||
r547 | 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: | ||||
r1194 | kill(running_pid, 0) | |||
r547 | except OSError, exc: | |||
if exc.errno in (errno.ESRCH, errno.EPERM): | ||||
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 | ||||
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) | ||||
pidfile = open(self.pidfile, "wb") | ||||
pidfile.write(lockname) | ||||
pidfile.close | ||||
self.held = True | ||||