@@ -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
129129class 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