pidlock.py
144 lines
| 4.5 KiB
| text/x-python
|
PythonLexer
Bradley M. Kuhn
|
r4116 | # -*- coding: utf-8 -*- | ||
# This program is free software: you can redistribute it and/or modify | ||||
# it under the terms of the GNU General Public License as published by | ||||
# the Free Software Foundation, either version 3 of the License, or | ||||
# (at your option) any later version. | ||||
# | ||||
# This program is distributed in the hope that it will be useful, | ||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
# GNU General Public License for more details. | ||||
# | ||||
# You should have received a copy of the GNU General Public License | ||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||
from __future__ import with_statement | ||||
r1307 | import os | |||
import errno | ||||
r547 | 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): | |||
Bradley M. Kuhn
|
r4116 | lock_name = os.path.join(os.path.dirname(__file__), 'running.lock') | ||
self.pidfile = file_ if file_ else lock_name | ||||
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, | ||||
Bradley M. Kuhn
|
r4116 | args=(self, debug), exitpriority=10) | ||
r547 | ||||
@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: | ||||
Bradley M. Kuhn
|
r4116 | with open(self.pidfile, 'r') as f: | ||
try: | ||||
running_pid = int(f.readline()) | ||||
except ValueError: | ||||
running_pid = -1 | ||||
r1194 | ||||
r547 | if self.debug: | |||
r1307 | print ('lock file present running_pid: %s, ' | |||
Bradley M. Kuhn
|
r4116 | '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_) | ||||
Bradley M. Kuhn
|
r4116 | with open(self.pidfile, 'wb') as f: | ||
f.write(lockname) | ||||
r547 | self.held = True | |||