summaryrefslogtreecommitdiffstats
path: root/Modules/_io
diff options
context:
space:
mode:
authorAntoine Pitrou <solipsis@pitrou.net>2015-04-13 17:48:19 (GMT)
committerAntoine Pitrou <solipsis@pitrou.net>2015-04-13 17:48:19 (GMT)
commitcb46f0ecb05ef3ccd3f53ced7f60748c0b3c710a (patch)
treebd7bf53350b0acbd12721bcfba898d6f6072fc1c /Modules/_io
parent9c680b07285867844927871ddcbf60c93e786e1f (diff)
parent25f85d4bd58d86d3e6ce99cb9f270e96bf5ba08f (diff)
downloadcpython-cb46f0ecb05ef3ccd3f53ced7f60748c0b3c710a.zip
cpython-cb46f0ecb05ef3ccd3f53ced7f60748c0b3c710a.tar.gz
cpython-cb46f0ecb05ef3ccd3f53ced7f60748c0b3c710a.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 ea9f533..7cf5dda 100644
--- a/Modules/_io/bufferedio.c
+++ b/Modules/_io/bufferedio.c
@@ -318,14 +318,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;
}