Commit 8f2ba439 authored by Vincent Pelletier's avatar Vincent Pelletier

Improve lock tracing:

- Don't complain about deadlocks when reentrant (they cannot happen on a single lock, and more complex deadlocks are just not reported here)
- Display a complete traceback when a deadlock is detected (just displaying the line acquiring the lock is sometimes not enough).


git-svn-id: https://svn.erp5.org/repos/neo/branches/prototype3@1110 71dcc9de-d417-0410-9af5-da40c76e7ee4
parent bba0e284
...@@ -38,7 +38,8 @@ if VERBOSE_LOCKING: ...@@ -38,7 +38,8 @@ if VERBOSE_LOCKING:
# limit=3 returns execution position in caller's caller # limit=3 returns execution position in caller's caller
# Additionnal level value (should be positive only) can be used when # Additionnal level value (should be positive only) can be used when
# more intermediate calls are involved # more intermediate calls are involved
path, line_number, func_name, line = traceback.extract_stack(limit=3 + level)[0] self.stack = stack = traceback.extract_stack()[:-(2 + level)]
path, line_number, func_name, line = stack[-1]
# Simplify path. Only keep 3 last path elements. It is enough for # Simplify path. Only keep 3 last path elements. It is enough for
# current Neo directory structure. # current Neo directory structure.
path = os.path.join('...', *path.split(os.path.sep)[-3:]) path = os.path.join('...', *path.split(os.path.sep)[-3:])
...@@ -50,8 +51,12 @@ if VERBOSE_LOCKING: ...@@ -50,8 +51,12 @@ if VERBOSE_LOCKING:
def __repr__(self): def __repr__(self):
return '%s@%s:%s %s' % (self.ident, self.caller[0], self.caller[1], self.caller[3]) return '%s@%s:%s %s' % (self.ident, self.caller[0], self.caller[1], self.caller[3])
def formatStack(self):
return ''.join(traceback.format_list(self.stack))
class VerboseLock(object): class VerboseLock(object):
def __init__(self): def __init__(self, reentrant=False):
self.reentrant = reentrant
self.owner = None self.owner = None
self.waiting = [] self.waiting = []
self._note('%s@%X created by %r', self.__class__.__name__, id(self), LockUser(1)) self._note('%s@%X created by %r', self.__class__.__name__, id(self), LockUser(1))
...@@ -71,8 +76,10 @@ if VERBOSE_LOCKING: ...@@ -71,8 +76,10 @@ if VERBOSE_LOCKING:
me = LockUser() me = LockUser()
owner = self._getOwner() owner = self._getOwner()
self._note('[%r]%s.acquire(%s) Waiting for lock. Owned by:%r Waiting:%r', me, self, blocking, owner, self.waiting) self._note('[%r]%s.acquire(%s) Waiting for lock. Owned by:%r Waiting:%r', me, self, blocking, owner, self.waiting)
if blocking and me == owner: if not self.reentrant and blocking and me == owner:
self._note('[%r]%s.acquire(%s): Deadlock detected: I already own this lock:%r', me, self, blocking, owner) self._note('[%r]%s.acquire(%s): Deadlock detected: I already own this lock:%r', me, self, blocking, owner)
self._note('Owner traceback:\n%s', owner.formatStack())
self._note('My traceback:\n%s', me.formatStack())
self.waiting.append(me) self.waiting.append(me)
try: try:
return self.lock.acquire(blocking) return self.lock.acquire(blocking)
...@@ -94,7 +101,7 @@ if VERBOSE_LOCKING: ...@@ -94,7 +101,7 @@ if VERBOSE_LOCKING:
class RLock(VerboseLock): class RLock(VerboseLock):
def __init__(self, verbose=None): def __init__(self, verbose=None):
VerboseLock.__init__(self) VerboseLock.__init__(self)#, reentrant=True)
self.lock = threading_RLock() self.lock = threading_RLock()
def _locked(self): def _locked(self):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment