MCPcopy Index your code
hub / github.com/python/cpython / _ModuleLock

Class _ModuleLock

Lib/importlib/_bootstrap.py:226–389  ·  view source on GitHub ↗

A recursive lock implementation which is able to detect deadlocks (e.g. thread 1 trying to take locks A then B, and thread 2 trying to take locks B then A).

Source from the content-addressed store, hash-verified

224
225
226class _ModuleLock:
227 """A recursive lock implementation which is able to detect deadlocks
228 (e.g. thread 1 trying to take locks A then B, and thread 2 trying to
229 take locks B then A).
230 """
231
232 def __init__(self, name):
233 # Create an RLock for protecting the import process for the
234 # corresponding module. Since it is an RLock, a single thread will be
235 # able to take it more than once. This is necessary to support
236 # re-entrancy in the import system that arises from (at least) signal
237 # handlers and the garbage collector. Consider the case of:
238 #
239 # import foo
240 # -> ...
241 # -> importlib._bootstrap._ModuleLock.acquire
242 # -> ...
243 # -> <garbage collector>
244 # -> __del__
245 # -> import foo
246 # -> ...
247 # -> importlib._bootstrap._ModuleLock.acquire
248 # -> _BlockingOnManager.__enter__
249 #
250 # If a different thread than the running one holds the lock then the
251 # thread will have to block on taking the lock, which is what we want
252 # for thread safety.
253 self.lock = _thread.RLock()
254 self.wakeup = _thread.allocate_lock()
255
256 # The name of the module for which this is a lock.
257 self.name = name
258
259 # Can end up being set to None if this lock is not owned by any thread
260 # or the thread identifier for the owning thread.
261 self.owner = None
262
263 # Represent the number of times the owning thread has acquired this lock
264 # via a list of True. This supports RLock-like ("re-entrant lock")
265 # behavior, necessary in case a single thread is following a circular
266 # import dependency and needs to take the lock for a single module
267 # more than once.
268 #
269 # Counts are represented as a list of True because list.append(True)
270 # and list.pop() are both atomic and thread-safe in CPython and it's hard
271 # to find another primitive with the same properties.
272 self.count = []
273
274 # This is a count of the number of threads that are blocking on
275 # self.wakeup.acquire() awaiting to get their turn holding this module
276 # lock. When the module lock is released, if this is greater than
277 # zero, it is decremented and `self.wakeup` is released one time. The
278 # intent is that this will let one other thread make more progress on
279 # acquiring this module lock. This repeats until all the threads have
280 # gotten a turn.
281 #
282 # This is incremented in self.acquire() when a thread notices it is
283 # going to have to wait for another thread to finish.

Callers 1

_get_module_lockFunction · 0.85

Calls

no outgoing calls

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…