Allow to give lock to multiple processes (#154)

* Check also son_of_locked for self
* Check again that we're son of locked when trying to acquire lock
* Support having multiple PIDs in lock file..
* Fix/improve son_of_lock detection
This commit is contained in:
Alexandre Aubin 2017-10-08 23:49:21 +02:00 committed by GitHub
parent ca580bbcfb
commit 0665cb4dd5

View file

@ -442,16 +442,21 @@ class MoulinetteLock(object):
start_time = time.time() start_time = time.time()
while True: while True:
lock_pid = self._lock_PID()
if lock_pid is None: lock_pids = self._lock_PIDs()
if self._is_son_of(lock_pids):
return
if lock_pids == []:
self._lock() self._lock()
break break
elif not self._stale_checked: elif not self._stale_checked:
self._stale_checked = True self._stale_checked = True
# Delete stale lock file # Check locked process still exist and take lock if it doesnt
if not lock_pid or not os.path.exists( # FIXME : what do in the context of multiple locks :|
os.path.join('/proc', lock_pid, 'exe')): first_lock = lock_pids[0]
if not os.path.exists(os.path.join('/proc', str(first_lock), 'exe')):
logger.debug('stale lock file found') logger.debug('stale lock file found')
self._lock() self._lock()
break break
@ -486,28 +491,32 @@ class MoulinetteLock(object):
moulinette.m18n.g('permission_denied'), moulinette.m18n.g('permission_denied'),
moulinette.m18n.g('root_required'))) moulinette.m18n.g('root_required')))
def _lock_PID(self): def _lock_PIDs(self):
if not os.path.isfile(self._lockfile): if not os.path.isfile(self._lockfile):
return None return []
with open(self._lockfile) as f: with open(self._lockfile) as f:
lock_pid = f.read().strip() lock_pids = f.read().strip().split('\n')
return lock_pid # Make sure to convert those pids to integers
lock_pids = [ int(pid) for pid in lock_pids ]
def _is_son_of_locked(self): return lock_pids
lock_pid = self._lock_PID()
if lock_pid is None: def _is_son_of(self, lock_pids):
if lock_pids == []:
return False return False
# Start with self
parent = psutil.Process() parent = psutil.Process()
# While this is not the very first process
while parent.parent() is not None: # While there is a parent... (e.g. init has no parent)
# If parent PID is the lock, the yes! we are a son of the process while parent is not None:
# If parent PID is the lock, then yes! we are a son of the process
# with the lock... # with the lock...
if parent.ppid() == int(lock_pid): if parent.pid in lock_pids:
return True return True
# Otherwise, try 'next' parent # Otherwise, try 'next' parent
parent = parent.parent() parent = parent.parent()
@ -515,7 +524,7 @@ class MoulinetteLock(object):
return False return False
def __enter__(self): def __enter__(self):
if not self._locked and not self._is_son_of_locked(): if not self._locked:
self.acquire() self.acquire()
return self return self