|
@@ -6,47 +6,11 @@ import sys
|
|
|
import time
|
|
|
|
|
|
from .helpers import Error, ErrorWithTraceback
|
|
|
+from .platform import process_alive, get_process_id
|
|
|
|
|
|
ADD, REMOVE = 'add', 'remove'
|
|
|
SHARED, EXCLUSIVE = 'shared', 'exclusive'
|
|
|
|
|
|
-# only determine the PID and hostname once.
|
|
|
-# for FUSE mounts, we fork a child process that needs to release
|
|
|
-# the lock made by the parent, so it needs to use the same PID for that.
|
|
|
-_pid = os.getpid()
|
|
|
-_hostname = socket.gethostname()
|
|
|
-
|
|
|
-
|
|
|
-def get_id():
|
|
|
- """Get identification tuple for 'us'"""
|
|
|
-
|
|
|
- # If changing the thread_id to ever be non-zero, also revisit the check_lock_stale() below.
|
|
|
- thread_id = 0
|
|
|
- return _hostname, _pid, thread_id
|
|
|
-
|
|
|
-
|
|
|
-def check_lock_stale(host, pid, thread):
|
|
|
- """Check if the host, pid, thread combination corresponds to a dead process on our local node or not."""
|
|
|
- if host != _hostname:
|
|
|
- return False
|
|
|
-
|
|
|
- if thread != 0:
|
|
|
- # Currently thread is always 0, if we ever decide to set this to a non-zero value, this code needs to be revisited too to do a sensible thing
|
|
|
- return False
|
|
|
-
|
|
|
- try:
|
|
|
- # This may not work in Windows.
|
|
|
- # This does not kill anything, 0 means "see if we can send a signal to this process or not".
|
|
|
- # Possible errors: No such process (== stale lock) or permission denied (not a stale lock)
|
|
|
- # If the exception is not raised that means such a pid is valid and we can send a signal to it (== not a stale lock too).
|
|
|
- os.kill(pid, 0)
|
|
|
- return False
|
|
|
- except OSError as err:
|
|
|
- if err.errno != errno.ESRCH:
|
|
|
- return False
|
|
|
- pass
|
|
|
-
|
|
|
- return True
|
|
|
|
|
|
|
|
|
class TimeoutTimer:
|
|
@@ -141,7 +105,7 @@ class ExclusiveLock:
|
|
|
self.timeout = timeout
|
|
|
self.sleep = sleep
|
|
|
self.path = os.path.abspath(path)
|
|
|
- self.id = id or get_id()
|
|
|
+ self.id = id or get_process_id()
|
|
|
self.unique_name = os.path.join(self.path, "%s.%d-%x" % self.id)
|
|
|
self.ok_to_kill_stale_locks = kill_stale_locks
|
|
|
self.stale_warning_printed = False
|
|
@@ -194,7 +158,6 @@ class ExclusiveLock:
|
|
|
|
|
|
def kill_stale_lock(self):
|
|
|
for name in os.listdir(self.path):
|
|
|
-
|
|
|
try:
|
|
|
host_pid, thread_str = name.rsplit('-', 1)
|
|
|
host, pid_str = host_pid.rsplit('.', 1)
|
|
@@ -205,7 +168,7 @@ class ExclusiveLock:
|
|
|
# It's safer to just exit
|
|
|
return False
|
|
|
|
|
|
- if not check_lock_stale(host, pid, thread):
|
|
|
+ if not process_alive(host, pid, thread):
|
|
|
return False
|
|
|
|
|
|
if not self.ok_to_kill_stale_locks:
|
|
@@ -249,7 +212,7 @@ class LockRoster:
|
|
|
"""
|
|
|
def __init__(self, path, id=None, kill_stale_locks=False):
|
|
|
self.path = path
|
|
|
- self.id = id or get_id()
|
|
|
+ self.id = id or get_process_id()
|
|
|
self.ok_to_kill_zombie_locks = kill_stale_locks
|
|
|
|
|
|
def load(self):
|
|
@@ -264,7 +227,7 @@ class LockRoster:
|
|
|
try:
|
|
|
for e in data[key]:
|
|
|
(host, pid, thread) = e
|
|
|
- if not check_lock_stale(host, pid, thread):
|
|
|
+ if not process_alive(host, pid, thread):
|
|
|
elements.add(tuple(e))
|
|
|
else:
|
|
|
print(("Removed stale %s roster lock for pid %d." % (key, pid)), file=sys.stderr)
|
|
@@ -330,7 +293,7 @@ class Lock:
|
|
|
self.is_exclusive = exclusive
|
|
|
self.sleep = sleep
|
|
|
self.timeout = timeout
|
|
|
- self.id = id or get_id()
|
|
|
+ self.id = id or get_process_id()
|
|
|
# globally keeping track of shared and exclusive lockers:
|
|
|
self._roster = LockRoster(path + '.roster', id=id, kill_stale_locks=kill_stale_locks)
|
|
|
# an exclusive lock, used for:
|