scripts/gestion/lock.py
bernat d593a7111a Deuxieme simplification
darcs-hash:20060205001905-d1718-9afcb0b1a3dfb7b0df0cf69be90eda7151a5a98d.gz
2006-02-05 01:19:05 +01:00

185 lines
5.7 KiB
Python
Executable file

#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-
""" Gestion de lock
Copyright (C) Frédéric Pauget
Licence : GPLv2
"""
import os,string,time,sys, affich_tools
from commands import getoutput
from user_tests import getuser
from fcntl import lockf, LOCK_EX, LOCK_NB, LOCK_UN
import errno, random
def wait_lock(lock_name, lock_comment='', d=None, retry=0.2):
"""Attend la disponibilité d'un lock en utilisant le framework Twisted.
Si d est de type Deferred, on est en mode asynchrone.
retry permet de réessayer dans `retry' secondes.
"""
from twisted.internet import reactor, defer
try:
try:
make_lock(lock_name, lock_comment, nowait=1, quiet=True)
except AssertionError:
raise
except:
print "*** Probleme lors de l'obtention du lock..."
import traceback
traceback.print_exc()
# On a sans doute pas le lock et c'est pas moi qui me tape
# à debugguer les trucs à Fred.
raise AssertionError
# On a le lock
if not d:
# On est en mode synchrone
return defer.succeed(None)
# On appelle le callback car on est en mode asynchrone
print "We got the lock, in asynchronous mode"
d.callback(None)
except AssertionError:
# On a pas le lock
if not d:
# On est en mode synchrone, on va passer en asynchrone
d = defer.Deferred()
# On essaie de nouveau plus tard
newretry = min(retry * 2, 4) + random.random() * 0.1 * retry
reactor.callLater(retry, wait_lock, lock_name, lock_comment, d, newretry)
return d
def make_lock(lock_name, lock_comment='',nowait=0, quiet=False) :
""" Création d'un lock
si nowait=1 fait un sys.exit(254) quand un ancien lock actif est rencontré
"""
return
lock_dir = '/var/lock/gestion'
try:
os.mkdir(lock_dir)
except OSError:
pass
lock_file = "%s/%s" % (lock_dir, lock_name)
# On créé une zone d'exclusion
lock_fd_dl=open("%s-dotlock" % lock_file, "w")
# On demande un verrou exclusif
try:
lockf(lock_fd_dl, LOCK_EX | LOCK_NB)
except IOError, e:
if e.errno not in [errno.EACCES, errno.EAGAIN]:
raise
if nowait:
if quiet:
# On va plutot lever une exception
raise AssertionError('In critical section')
else:
sys.stderr.write('\tpropriétaire : inconnu\n\tpid : inconnu\n\tdémarré depuis inconnu\n')
sys.exit(254)
else:
# La procédure de lock est deja en cours d'execution, on essaie un peu plus tard
time.sleep(0.5)
# On enleve le verrou système
lockf(lock_fd_dl, LOCK_UN)
lock_fd_dl.close()
return make_lock(lock_name, lock_comment)
if os.path.isfile(lock_file) :
### Lock existant
# Lecture du lock
fd = open(lock_file, "r")
pid= fd.readline().strip()
user = fd.readline().strip()
fd.close()
# Informations sur le processus lockant
if os.system( "ps ax | grep -q '^%s '" % pid ) :
# Le script lockant ne tourne plus
os.remove(lock_file)
elif nowait :
if not quiet:
sys.stderr.write('Lock : %s\n' % lock_file)
l=getoutput("ps ax -o pid,etime | awk '($1 == %s)'" % pid)
data = [ user , pid , l.strip() ]
# Formatate de etime
s = data[-1].split('-')
if len(s)==2 :
txt = '%s jour(s) ' % s[0]
s=s[1]
else :
txt = ''
s=s[0]
s = s.split(':')
if len(s) == 3 :
txt = '%sh%smin%ss' % tuple(s)
elif len(s) == 2 :
txt = '%smin%ss' % tuple(s)
else :
txt = '???'
data[-1]=txt
if not quiet:
sys.stderr.write('\tpropriétaire : %s\n\tpid : %s\n\tdémarré depuis %s\n' % tuple(data) )
sys.exit(254)
else:
# On va plutot lever une exception
raise AssertionError(tuple(data))
else :
# Il faut attendre
a = affich_tools.anim('\tattente du lock')
for i in range(8) :
time.sleep(1)
a.cycle()
sys.stdout.write('\r')
# On enleve le verrou système
lockf(lock_fd_dl, LOCK_UN)
lock_fd_dl.close()
return make_lock(lock_name, lock_comment)
### Prise du lock
lock_fd = file(lock_file,"w")
try:
utilisateur = getuser()
except:
utilisateur = "inconnu"
lock_fd.write("%s\n%s\n%s" % (os.getpid(), utilisateur, lock_comment) )
lock_fd.close()
# On enleve le verrou système
lockf(lock_fd_dl, LOCK_UN)
lock_fd_dl.close()
def remove_lock( lock_name ) :
""" Destruction du lock """
return
# On créé une zone d'exclusion
lock_dir = '/var/lock/gestion'
lock_file = "%s/%s" % (lock_dir, lock_name)
lock_fd_dl=open("%s-dotlock" % lock_file, "w")
# On demande un verrou exclusif
try:
lockf(lock_fd_dl, LOCK_EX | LOCK_NB)
except IOError, e:
if e.errno not in [errno.EACCES, errno.EAGAIN]:
raise
# Déjà locké
time.sleep(0.5)
return remove_lock(lock_name)
try :
fd = open(lock_file, "r")
if fd.readline().strip()=="%s" % os.getpid():
os.remove(lock_file)
fd.close()
except :
pass
# On enleve le verrou système
lockf(lock_fd_dl, LOCK_UN)
lock_fd_dl.close()