summaryrefslogtreecommitdiffstats
path: root/Modules/_io
diff options
context:
space:
mode:
authorAntoine Pitrou <solipsis@pitrou.net>2015-04-13 17:41:47 (GMT)
committerAntoine Pitrou <solipsis@pitrou.net>2015-04-13 17:41:47 (GMT)
commit25f85d4bd58d86d3e6ce99cb9f270e96bf5ba08f (patch)
treec6b252f8cde6d114360560f412044a5b0e46d999 /Modules/_io
parentf3b990e48c698154fb2eaa990ee22a6962e041ac (diff)
downloadcpython-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/_io')
-rw-r--r--Modules/_io/bufferedio.c23
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;
}