mirror of https://github.com/python/cpython
Backport r57216 (see issue #1731).
Add a hack (originally devised in a slightly different form by Thomas Wouters) to prevent spurious tracebacks when a daemon thread's cleanup happens to wake up when the world around it has already been destroyed. This also backports other small changes to this file, essentially making it identical to the trunk version.
This commit is contained in:
parent
b234ceb1ac
commit
62bceeccdd
|
@ -85,9 +85,10 @@ class _RLock(_Verbose):
|
||||||
self.__count = 0
|
self.__count = 0
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
owner = self.__owner
|
||||||
return "<%s(%s, %d)>" % (
|
return "<%s(%s, %d)>" % (
|
||||||
self.__class__.__name__,
|
self.__class__.__name__,
|
||||||
self.__owner and self.__owner.getName(),
|
owner and owner.getName(),
|
||||||
self.__count)
|
self.__count)
|
||||||
|
|
||||||
def acquire(self, blocking=1):
|
def acquire(self, blocking=1):
|
||||||
|
@ -111,8 +112,8 @@ class _RLock(_Verbose):
|
||||||
__enter__ = acquire
|
__enter__ = acquire
|
||||||
|
|
||||||
def release(self):
|
def release(self):
|
||||||
me = currentThread()
|
if self.__owner is not currentThread():
|
||||||
assert self.__owner is me, "release() of un-acquire()d lock"
|
raise RuntimeError("cannot release un-aquired lock")
|
||||||
self.__count = count = self.__count - 1
|
self.__count = count = self.__count - 1
|
||||||
if not count:
|
if not count:
|
||||||
self.__owner = None
|
self.__owner = None
|
||||||
|
@ -204,7 +205,8 @@ class _Condition(_Verbose):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def wait(self, timeout=None):
|
def wait(self, timeout=None):
|
||||||
assert self._is_owned(), "wait() of un-acquire()d lock"
|
if not self._is_owned():
|
||||||
|
raise RuntimeError("cannot wait on un-aquired lock")
|
||||||
waiter = _allocate_lock()
|
waiter = _allocate_lock()
|
||||||
waiter.acquire()
|
waiter.acquire()
|
||||||
self.__waiters.append(waiter)
|
self.__waiters.append(waiter)
|
||||||
|
@ -245,7 +247,8 @@ class _Condition(_Verbose):
|
||||||
self._acquire_restore(saved_state)
|
self._acquire_restore(saved_state)
|
||||||
|
|
||||||
def notify(self, n=1):
|
def notify(self, n=1):
|
||||||
assert self._is_owned(), "notify() of un-acquire()d lock"
|
if not self._is_owned():
|
||||||
|
raise RuntimeError("cannot notify on un-aquired lock")
|
||||||
__waiters = self.__waiters
|
__waiters = self.__waiters
|
||||||
waiters = __waiters[:n]
|
waiters = __waiters[:n]
|
||||||
if not waiters:
|
if not waiters:
|
||||||
|
@ -273,7 +276,8 @@ class _Semaphore(_Verbose):
|
||||||
# After Tim Peters' semaphore class, but not quite the same (no maximum)
|
# After Tim Peters' semaphore class, but not quite the same (no maximum)
|
||||||
|
|
||||||
def __init__(self, value=1, verbose=None):
|
def __init__(self, value=1, verbose=None):
|
||||||
assert value >= 0, "Semaphore initial value must be >= 0"
|
if value < 0:
|
||||||
|
raise ValueError("semaphore initial value must be >= 0")
|
||||||
_Verbose.__init__(self, verbose)
|
_Verbose.__init__(self, verbose)
|
||||||
self.__cond = Condition(Lock())
|
self.__cond = Condition(Lock())
|
||||||
self.__value = value
|
self.__value = value
|
||||||
|
@ -424,8 +428,10 @@ class Thread(_Verbose):
|
||||||
return "<%s(%s, %s)>" % (self.__class__.__name__, self.__name, status)
|
return "<%s(%s, %s)>" % (self.__class__.__name__, self.__name, status)
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
assert self.__initialized, "Thread.__init__() not called"
|
if not self.__initialized:
|
||||||
assert not self.__started, "thread already started"
|
raise RuntimeError("thread.__init__() not called")
|
||||||
|
if self.__started:
|
||||||
|
raise RuntimeError("thread already started")
|
||||||
if __debug__:
|
if __debug__:
|
||||||
self._note("%s.start(): starting thread", self)
|
self._note("%s.start(): starting thread", self)
|
||||||
_active_limbo_lock.acquire()
|
_active_limbo_lock.acquire()
|
||||||
|
@ -440,6 +446,26 @@ class Thread(_Verbose):
|
||||||
self.__target(*self.__args, **self.__kwargs)
|
self.__target(*self.__args, **self.__kwargs)
|
||||||
|
|
||||||
def __bootstrap(self):
|
def __bootstrap(self):
|
||||||
|
# Wrapper around the real bootstrap code that ignores
|
||||||
|
# exceptions during interpreter cleanup. Those typically
|
||||||
|
# happen when a daemon thread wakes up at an unfortunate
|
||||||
|
# moment, finds the world around it destroyed, and raises some
|
||||||
|
# random exception *** while trying to report the exception in
|
||||||
|
# __bootstrap_inner() below ***. Those random exceptions
|
||||||
|
# don't help anybody, and they confuse users, so we suppress
|
||||||
|
# them. We suppress them only when it appears that the world
|
||||||
|
# indeed has already been destroyed, so that exceptions in
|
||||||
|
# __bootstrap_inner() during normal business hours are properly
|
||||||
|
# reported. Also, we only suppress them for daemonic threads;
|
||||||
|
# if a non-daemonic encounters this, something else is wrong.
|
||||||
|
try:
|
||||||
|
self.__bootstrap_inner()
|
||||||
|
except:
|
||||||
|
if self.__daemonic and _sys is None:
|
||||||
|
return
|
||||||
|
raise
|
||||||
|
|
||||||
|
def __bootstrap_inner(self):
|
||||||
try:
|
try:
|
||||||
self.__started = True
|
self.__started = True
|
||||||
_active_limbo_lock.acquire()
|
_active_limbo_lock.acquire()
|
||||||
|
@ -545,9 +571,13 @@ class Thread(_Verbose):
|
||||||
_active_limbo_lock.release()
|
_active_limbo_lock.release()
|
||||||
|
|
||||||
def join(self, timeout=None):
|
def join(self, timeout=None):
|
||||||
assert self.__initialized, "Thread.__init__() not called"
|
if not self.__initialized:
|
||||||
assert self.__started, "cannot join thread before it is started"
|
raise RuntimeError("Thread.__init__() not called")
|
||||||
assert self is not currentThread(), "cannot join current thread"
|
if not self.__started:
|
||||||
|
raise RuntimeError("cannot join thread before it is started")
|
||||||
|
if self is currentThread():
|
||||||
|
raise RuntimeError("cannot join current thread")
|
||||||
|
|
||||||
if __debug__:
|
if __debug__:
|
||||||
if not self.__stopped:
|
if not self.__stopped:
|
||||||
self._note("%s.join(): waiting until thread stops", self)
|
self._note("%s.join(): waiting until thread stops", self)
|
||||||
|
@ -590,8 +620,10 @@ class Thread(_Verbose):
|
||||||
return self.__daemonic
|
return self.__daemonic
|
||||||
|
|
||||||
def setDaemon(self, daemonic):
|
def setDaemon(self, daemonic):
|
||||||
assert self.__initialized, "Thread.__init__() not called"
|
if not self.__initialized:
|
||||||
assert not self.__started, "cannot set daemon status of active thread"
|
raise RuntimeError("Thread.__init__() not called")
|
||||||
|
if self.__started:
|
||||||
|
raise RuntimeError("cannot set daemon status of active thread");
|
||||||
self.__daemonic = daemonic
|
self.__daemonic = daemonic
|
||||||
|
|
||||||
# The timer class was contributed by Itamar Shtull-Trauring
|
# The timer class was contributed by Itamar Shtull-Trauring
|
||||||
|
|
Loading…
Reference in New Issue