Skip to content

Commit f8e27c0

Browse files
LuYanFCP0xnullpath
authored andcommitted
Fixed a deadlock issue in the bufferedIO module when using fork in Python
1 parent 58d305c commit f8e27c0

File tree

1 file changed

+66
-0
lines changed

1 file changed

+66
-0
lines changed

Modules/_io/bufferedio.c

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,8 @@ static PyObject *
737737
_bufferedreader_read_generic(buffered *self, Py_ssize_t);
738738
static Py_ssize_t
739739
_bufferedreader_raw_read(buffered *self, char *start, Py_ssize_t len);
740+
static int
741+
_buffered_init(buffered *self);
740742

741743
/*
742744
* Helpers
@@ -825,6 +827,60 @@ _buffered_raw_seek(buffered *self, Py_off_t target, int whence)
825827
return n;
826828
}
827829

830+
#ifdef HAVE_FORK
831+
832+
static PyObject*
833+
buffered_after_fork_child_impl(PyObject *self, PyObject *Py_UNUSED(ignored))
834+
{
835+
buffered *buf = (buffered *)self;
836+
if (_buffered_init(buf) < 0) {
837+
PyErr_SetString(PyExc_RuntimeError, "Failed to initialize buffer after fork");
838+
return NULL;
839+
}
840+
_bufferedreader_reset_buf(buf);
841+
Py_RETURN_NONE;
842+
}
843+
844+
static PyMethodDef buffered_fork_methods[] = {
845+
{"_after_fork_child", buffered_after_fork_child_impl, METH_NOARGS, NULL},
846+
{NULL, NULL}
847+
};
848+
849+
static int
850+
buffered_register_at_fork(buffered *self)
851+
{
852+
PyInterpreterState *interp = PyThreadState_Get()->interp;
853+
if (!interp) {
854+
PyErr_SetString(PyExc_RuntimeError, "Failed to get interpreter state");
855+
return -1;
856+
}
857+
858+
// Only register the fork handlers once
859+
if (!interp->after_forkers_child) {
860+
interp->after_forkers_child = PyList_New(0);
861+
if (!interp->after_forkers_child) {
862+
return -1;
863+
}
864+
}
865+
866+
/* Create method objects */
867+
PyObject *after_child = PyCFunction_New(&buffered_fork_methods[0], (PyObject *)self);
868+
if (!after_child) {
869+
return -1;
870+
}
871+
872+
/* Append callbacks to the lists */
873+
int status = 0;
874+
if (PyList_Append(interp->after_forkers_child, after_child) < 0) {
875+
status = -1;
876+
}
877+
878+
Py_DECREF(after_child);
879+
return status;
880+
}
881+
882+
#endif /* HAVE_FORK */
883+
828884
static int
829885
_buffered_init(buffered *self)
830886
{
@@ -859,6 +915,16 @@ _buffered_init(buffered *self)
859915
self->buffer_mask = 0;
860916
if (_buffered_raw_tell(self) == -1)
861917
PyErr_Clear();
918+
919+
#ifdef HAVE_FORK
920+
/* Register fork handlers */
921+
if (buffered_register_at_fork(self) < 0) {
922+
PyThread_free_lock(self->lock);
923+
self->lock = NULL;
924+
return -1;
925+
}
926+
#endif /* HAVE_FORK */
927+
862928
return 0;
863929
}
864930

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy