Skip to content
Snippets Groups Projects
Commit 907fe912 authored by Todd Gamblin's avatar Todd Gamblin
Browse files

Make llnl.util.lock use file objects instead of low-level OS fds.

- Make sure we write, truncate, flush when setting PID and owning host in
  the file.
parent f2292908
No related branches found
No related tags found
No related merge requests found
...@@ -54,7 +54,7 @@ class Lock(object): ...@@ -54,7 +54,7 @@ class Lock(object):
def __init__(self, file_path): def __init__(self, file_path):
self._file_path = file_path self._file_path = file_path
self._fd = None self._file = None
self._reads = 0 self._reads = 0
self._writes = 0 self._writes = 0
...@@ -75,21 +75,23 @@ def _lock(self, op, timeout): ...@@ -75,21 +75,23 @@ def _lock(self, op, timeout):
try: try:
# If this is already open read-only and we want to # If this is already open read-only and we want to
# upgrade to an exclusive write lock, close first. # upgrade to an exclusive write lock, close first.
if self._fd is not None: if self._file is not None:
flags = fcntl.fcntl(self._fd, fcntl.F_GETFL) if op == fcntl.LOCK_EX and self._file.mode == 'r':
if op == fcntl.LOCK_EX and flags | os.O_RDONLY: self._file.close()
os.close(self._fd) self._file = None
self._fd = None
# Open reader locks read-only if possible.
if self._fd is None: # lock doesn't exist, open RW + create if it doesn't exist.
mode = os.O_RDWR if op == fcntl.LOCK_EX else os.O_RDONLY if self._file is None:
self._fd = os.open(self._file_path, mode) mode = 'r+' if op == fcntl.LOCK_EX else 'r'
self._file = open(self._file_path, mode)
fcntl.lockf(self._fd, op | fcntl.LOCK_NB)
fcntl.lockf(self._file, op | fcntl.LOCK_NB)
if op == fcntl.LOCK_EX: if op == fcntl.LOCK_EX:
os.write( self._file.write(
self._fd,
"pid=%s,host=%s" % (os.getpid(), socket.getfqdn())) "pid=%s,host=%s" % (os.getpid(), socket.getfqdn()))
self._file.truncate()
self._file.flush()
return return
except IOError as error: except IOError as error:
...@@ -108,9 +110,9 @@ def _unlock(self): ...@@ -108,9 +110,9 @@ def _unlock(self):
be masquerading as write locks, but this removes either. be masquerading as write locks, but this removes either.
""" """
fcntl.lockf(self._fd, fcntl.LOCK_UN) fcntl.lockf(self._file, fcntl.LOCK_UN)
os.close(self._fd) self._file.close()
self._fd = None self._file = None
def acquire_read(self, timeout=_default_timeout): def acquire_read(self, timeout=_default_timeout):
"""Acquires a recursive, shared lock for reading. """Acquires a recursive, shared lock for reading.
......
...@@ -184,7 +184,7 @@ def test_upgrade_read_to_write(self): ...@@ -184,7 +184,7 @@ def test_upgrade_read_to_write(self):
lock.release_read() lock.release_read()
self.assertTrue(lock._reads == 0) self.assertTrue(lock._reads == 0)
self.assertTrue(lock._writes == 0) self.assertTrue(lock._writes == 0)
self.assertTrue(lock._fd is None) self.assertTrue(lock._file is None)
# #
# Longer test case that ensures locks are reusable. Ordering is # Longer test case that ensures locks are reusable. Ordering is
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment