diff options
author | Antoine Pitrou <solipsis@pitrou.net> | 2015-04-13 17:41:47 (GMT) |
---|---|---|
committer | Antoine Pitrou <solipsis@pitrou.net> | 2015-04-13 17:41:47 (GMT) |
commit | 25f85d4bd58d86d3e6ce99cb9f270e96bf5ba08f (patch) | |
tree | c6b252f8cde6d114360560f412044a5b0e46d999 /Modules | |
parent | f3b990e48c698154fb2eaa990ee22a6962e041ac (diff) | |
download | cpython-25f85d4bd58d86d3e6ce99cb9f270e96bf5ba08f.zip cpython-25f85d4bd58d86d3e6ce99cb9f270e96bf5ba08f.tar.gz cpython-25f85d4bd58d86d3e6ce99cb9f270e96bf5ba08f.tar.bz2 |
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.
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/_io/bufferedio.c | 23 |
1 files changed, 22 insertions, 1 deletions
diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 445c870..3606cc8 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -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; } |