Skip to content

Commit 28ce165

Browse files
author
Joel Collins
committed
Lock bug fixes
1 parent 1d3d846 commit 28ce165

File tree

1 file changed

+56
-21
lines changed

1 file changed

+56
-21
lines changed

labthings/core/lock.py

Lines changed: 56 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ def __repr__(self):
3131
self._owner,
3232
)
3333

34+
def locked(self):
35+
return self._block.locked()
36+
3437
def acquire(self, blocking=True, timeout=None):
3538
"""
3639
Acquire the mutex, blocking if *blocking* is true, for up to
@@ -68,22 +71,6 @@ def release(self):
6871
def __exit__(self, typ, value, tb):
6972
self.release()
7073

71-
# Internal methods used by condition variables
72-
73-
def _acquire_restore(self, count_owner):
74-
count, owner = count_owner
75-
self._block.acquire()
76-
self._count = count
77-
self._owner = owner
78-
79-
def _release_save(self):
80-
count = self._count
81-
self._count = 0
82-
owner = self._owner
83-
self._owner = None
84-
self._block.release()
85-
return (count, owner)
86-
8774
def _is_owned(self):
8875
return self._owner is getcurrent()
8976

@@ -109,8 +96,10 @@ def __init__(self, timeout=1, name=None):
10996
def locked(self):
11097
return self._lock.locked()
11198

112-
def acquire(self, blocking=True):
113-
return self._lock.acquire(blocking, timeout=self.timeout)
99+
def acquire(self, blocking=True, timeout=None):
100+
if not timeout:
101+
timeout = self.timeout
102+
return self._lock.acquire(blocking, timeout=timeout)
114103

115104
def __enter__(self):
116105
result = self._lock.acquire(blocking=True, timeout=self.timeout)
@@ -125,6 +114,17 @@ def __exit__(self, *args):
125114
def release(self):
126115
self._lock.release()
127116

117+
@property
118+
def _owner(self):
119+
return self._lock._owner
120+
121+
@_owner.setter
122+
def _owner(self, new_owner):
123+
self._lock._owner = new_owner
124+
125+
def _is_owned(self):
126+
return self._lock._is_owned()
127+
128128

129129
class CompositeLock:
130130
"""
@@ -144,8 +144,19 @@ def __init__(self, locks, timeout=1):
144144
self.locks = locks
145145
self.timeout = timeout
146146

147-
def acquire(self, blocking=True):
148-
return (lock.acquire(blocking=blocking) for lock in self.locks)
147+
def acquire(self, blocking=True, timeout=None):
148+
if not timeout:
149+
timeout = self.timeout
150+
151+
lock_all = all(
152+
[lock.acquire(blocking=blocking, timeout=timeout) for lock in self.locks]
153+
)
154+
155+
if not lock_all:
156+
self._emergency_release()
157+
return False
158+
159+
return True
149160

150161
def __enter__(self):
151162
result = (lock.acquire(blocking=True) for lock in self.locks)
@@ -159,5 +170,29 @@ def __exit__(self, *args):
159170
lock.release()
160171

161172
def release(self):
173+
# If not all child locks are owner by caller
174+
if not all([owner is getcurrent() for owner in self._owner]):
175+
raise RuntimeError("cannot release un-acquired lock")
162176
for lock in self.locks:
163-
lock.release()
177+
if lock.locked():
178+
lock.release()
179+
180+
def _emergency_release(self):
181+
for lock in self.locks:
182+
if lock.locked() and lock._is_owned():
183+
lock.release()
184+
185+
def locked(self):
186+
return any([lock.locked() for lock in self.locks])
187+
188+
@property
189+
def _owner(self):
190+
return [lock._owner for lock in self.locks]
191+
192+
@_owner.setter
193+
def _owner(self, new_owner):
194+
for lock in self.locks:
195+
lock._owner = new_owner
196+
197+
def _is_owned(self):
198+
return all([lock._is_owned() for lock in self.locks])

0 commit comments

Comments
 (0)