Issue #23309: Avoid a deadlock at shutdown if a daemon thread is aborted

while it is holding a lock to a buffered I/O object, and the main thread
tries to use the same I/O object (typically stdout or stderr).  A fatal
error is emitted instead.
This commit is contained in:
Antoine Pitrou 2015-04-13 19:41:47 +02:00
parent f3b990e48c
commit 25f85d4bd5
5 changed files with 94 additions and 15 deletions

View file

@ -300,14 +300,35 @@ typedef struct {
static int
_enter_buffered_busy(buffered *self)
{
int relax_locking;
PyLockStatus st;
if (self->owner == PyThread_get_thread_ident()) {
PyErr_Format(PyExc_RuntimeError,
"reentrant call inside %R", self);
return 0;
}
relax_locking = (_Py_Finalizing != NULL);
Py_BEGIN_ALLOW_THREADS
PyThread_acquire_lock(self->lock, 1);
if (!relax_locking)
st = PyThread_acquire_lock(self->lock, 1);
else {
/* When finalizing, we don't want a deadlock to happen with daemon
* threads abruptly shut down while they owned the lock.
* Therefore, only wait for a grace period (1 s.).
* Note that non-daemon threads have already exited here, so this
* shouldn't affect carefully written threaded I/O code.
*/
st = PyThread_acquire_lock_timed(self->lock, 1e6, 0);
}
Py_END_ALLOW_THREADS
if (relax_locking && st != PY_LOCK_ACQUIRED) {
PyObject *msgobj = PyUnicode_FromFormat(
"could not acquire lock for %A at interpreter "
"shutdown, possibly due to daemon threads",
(PyObject *) self);
char *msg = PyUnicode_AsUTF8(msgobj);
Py_FatalError(msg);
}
return 1;
}