mirror of
https://github.com/python/cpython.git
synced 2025-08-03 16:39:00 +00:00
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:
parent
f3b990e48c
commit
25f85d4bd5
5 changed files with 94 additions and 15 deletions
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue