diff options
author | shadchin <shadchin@yandex-team.com> | 2024-02-12 07:53:52 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@ydb.tech> | 2024-02-14 14:26:16 +0000 |
commit | 31f2a419764a8ba77c2a970cfc80056c6cd06756 (patch) | |
tree | c1995d239eba8571cefc640f6648e1d5dd4ce9e2 /contrib/tools/python3/src/Modules/selectmodule.c | |
parent | fe2ef02b38d9c85d80060963b265a1df9f38c3bb (diff) | |
download | ydb-31f2a419764a8ba77c2a970cfc80056c6cd06756.tar.gz |
Update Python from 3.11.8 to 3.12.2
Diffstat (limited to 'contrib/tools/python3/src/Modules/selectmodule.c')
-rw-r--r-- | contrib/tools/python3/src/Modules/selectmodule.c | 165 |
1 files changed, 150 insertions, 15 deletions
diff --git a/contrib/tools/python3/src/Modules/selectmodule.c b/contrib/tools/python3/src/Modules/selectmodule.c index 8210269867..b7c6b1b539 100644 --- a/contrib/tools/python3/src/Modules/selectmodule.c +++ b/contrib/tools/python3/src/Modules/selectmodule.c @@ -14,8 +14,16 @@ #include "Python.h" #include "pycore_fileutils.h" // _Py_set_inheritable() +#include "pycore_import.h" // _PyImport_GetModuleAttrString() +#include "pycore_time.h" // _PyTime_t #include "structmember.h" // PyMemberDef +#include <stdbool.h> +#include <stddef.h> // offsetof() +#ifndef MS_WINDOWS +# include <unistd.h> // close() +#endif + #ifdef HAVE_SYS_DEVPOLL_H #include <sys/resource.h> #include <sys/devpoll.h> @@ -57,8 +65,10 @@ extern void bzero(void *, int); #endif #ifdef MS_WINDOWS -# define WIN32_LEAN_AND_MEAN -# include <winsock.h> +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include <winsock2.h> #else # define SOCKET int #endif @@ -68,13 +78,26 @@ extern void bzero(void *, int); # define POLLPRI 0 #endif +#ifdef HAVE_KQUEUE +// Linked list to track kqueue objects with an open fd, so +// that we can invalidate them at fork; +typedef struct _kqueue_list_item { + struct kqueue_queue_Object *obj; + struct _kqueue_list_item *next; +} _kqueue_list_item, *_kqueue_list; +#endif + typedef struct { PyObject *close; PyTypeObject *poll_Type; PyTypeObject *devpoll_Type; PyTypeObject *pyEpoll_Type; +#ifdef HAVE_KQUEUE PyTypeObject *kqueue_event_Type; PyTypeObject *kqueue_queue_Type; + _kqueue_list kqueue_open_list; + bool kqueue_tracking_initialized; +#endif } _selectstate; static struct PyModuleDef selectmodule; @@ -1652,8 +1675,7 @@ select_epoll___enter___impl(pyEpoll_Object *self) if (self->epfd < 0) return pyepoll_err_closed(); - Py_INCREF(self); - return (PyObject *)self; + return Py_NewRef(self); } /*[clinic input] @@ -1748,7 +1770,7 @@ typedef struct { #define kqueue_event_Check(op, state) (PyObject_TypeCheck((op), state->kqueue_event_Type)) -typedef struct { +typedef struct kqueue_queue_Object { PyObject_HEAD SOCKET kqfd; /* kqueue control fd */ } kqueue_queue_Object; @@ -1848,14 +1870,11 @@ static PyObject * kqueue_event_repr(kqueue_event_Object *s) { - char buf[1024]; - PyOS_snprintf( - buf, sizeof(buf), + return PyUnicode_FromFormat( "<select.kevent ident=%zu filter=%d flags=0x%x fflags=0x%x " "data=0x%llx udata=%p>", (size_t)(s->e.ident), (int)s->e.filter, (unsigned int)s->e.flags, (unsigned int)s->e.fflags, (long long)(s->e.data), (void *)s->e.udata); - return PyUnicode_FromString(buf); } static int @@ -1937,6 +1956,107 @@ kqueue_queue_err_closed(void) return NULL; } +static PyObject* +kqueue_tracking_after_fork(PyObject *module) { + _selectstate *state = get_select_state(module); + _kqueue_list_item *item = state->kqueue_open_list; + state->kqueue_open_list = NULL; + while (item) { + // Safety: we hold the GIL, and references are removed from this list + // before the object is deallocated. + kqueue_queue_Object *obj = item->obj; + assert(obj->kqfd != -1); + obj->kqfd = -1; + _kqueue_list_item *next = item->next; + PyMem_Free(item); + item = next; + } + Py_RETURN_NONE; +} + +static PyMethodDef kqueue_tracking_after_fork_def = { + "kqueue_tracking_after_fork", (PyCFunction)kqueue_tracking_after_fork, + METH_NOARGS, "Invalidate open select.kqueue objects after fork." +}; + +static void +kqueue_tracking_init(PyObject *module) { + _selectstate *state = get_select_state(module); + assert(state->kqueue_open_list == NULL); + // Register a callback to invalidate kqueues with open fds after fork. + PyObject *register_at_fork = NULL, *cb = NULL, *args = NULL, + *kwargs = NULL, *result = NULL; + register_at_fork = _PyImport_GetModuleAttrString("posix", + "register_at_fork"); + if (register_at_fork == NULL) { + goto finally; + } + cb = PyCFunction_New(&kqueue_tracking_after_fork_def, module); + if (cb == NULL) { + goto finally; + } + args = PyTuple_New(0); + assert(args != NULL); + kwargs = Py_BuildValue("{sO}", "after_in_child", cb); + if (kwargs == NULL) { + goto finally; + } + result = PyObject_Call(register_at_fork, args, kwargs); + +finally: + if (PyErr_Occurred()) { + // There are a few reasons registration can fail, especially if someone + // touched posix.register_at_fork. But everything else still works so + // instead of raising we issue a warning and move along. + PyObject *exc = PyErr_GetRaisedException(); + PyObject *exctype = (PyObject*)Py_TYPE(exc); + PyErr_WarnFormat(PyExc_RuntimeWarning, 1, + "An exception of type %S was raised while registering an " + "after-fork handler for select.kqueue objects: %S", exctype, exc); + Py_DECREF(exc); + } + Py_XDECREF(register_at_fork); + Py_XDECREF(cb); + Py_XDECREF(args); + Py_XDECREF(kwargs); + Py_XDECREF(result); + state->kqueue_tracking_initialized = true; +} + +static int +kqueue_tracking_add(_selectstate *state, kqueue_queue_Object *self) { + if (!state->kqueue_tracking_initialized) { + kqueue_tracking_init(PyType_GetModule(Py_TYPE(self))); + } + assert(self->kqfd >= 0); + _kqueue_list_item *item = PyMem_New(_kqueue_list_item, 1); + if (item == NULL) { + PyErr_NoMemory(); + return -1; + } + item->obj = self; + item->next = state->kqueue_open_list; + state->kqueue_open_list = item; + return 0; +} + +static void +kqueue_tracking_remove(_selectstate *state, kqueue_queue_Object *self) { + _kqueue_list *listptr = &state->kqueue_open_list; + while (*listptr != NULL) { + _kqueue_list_item *item = *listptr; + if (item->obj == self) { + *listptr = item->next; + PyMem_Free(item); + return; + } + listptr = &item->next; + } + // The item should be in the list when we remove it, + // and it should only be removed once at close time. + assert(0); +} + static int kqueue_queue_internal_close(kqueue_queue_Object *self) { @@ -1944,6 +2064,8 @@ kqueue_queue_internal_close(kqueue_queue_Object *self) if (self->kqfd >= 0) { int kqfd = self->kqfd; self->kqfd = -1; + _selectstate *state = _selectstate_by_type(Py_TYPE(self)); + kqueue_tracking_remove(state, self); Py_BEGIN_ALLOW_THREADS if (close(kqfd) < 0) save_errno = errno; @@ -1984,6 +2106,13 @@ newKqueue_Object(PyTypeObject *type, SOCKET fd) return NULL; } } + + _selectstate *state = _selectstate_by_type(type); + if (kqueue_tracking_add(state, self) < 0) { + Py_DECREF(self); + return NULL; + } + return (PyObject *)self; } @@ -2014,13 +2143,11 @@ select_kqueue_impl(PyTypeObject *type) } static void -kqueue_queue_dealloc(kqueue_queue_Object *self) +kqueue_queue_finalize(kqueue_queue_Object *self) { - PyTypeObject* type = Py_TYPE(self); + PyObject* error = PyErr_GetRaisedException(); kqueue_queue_internal_close(self); - freefunc kqueue_free = PyType_GetSlot(type, Py_tp_free); - kqueue_free((PyObject *)self); - Py_DECREF((PyObject *)type); + PyErr_SetRaisedException(error); } /*[clinic input] @@ -2354,11 +2481,11 @@ static PyMethodDef kqueue_queue_methods[] = { }; static PyType_Slot kqueue_queue_Type_slots[] = { - {Py_tp_dealloc, kqueue_queue_dealloc}, {Py_tp_doc, (void*)select_kqueue__doc__}, {Py_tp_getset, kqueue_queue_getsetlist}, {Py_tp_methods, kqueue_queue_methods}, {Py_tp_new, select_kqueue}, + {Py_tp_finalize, kqueue_queue_finalize}, {0, 0}, }; @@ -2403,8 +2530,11 @@ _select_traverse(PyObject *module, visitproc visit, void *arg) Py_VISIT(state->poll_Type); Py_VISIT(state->devpoll_Type); Py_VISIT(state->pyEpoll_Type); +#ifdef HAVE_KQUEUE Py_VISIT(state->kqueue_event_Type); Py_VISIT(state->kqueue_queue_Type); + // state->kqueue_open_list only holds borrowed refs +#endif return 0; } @@ -2417,8 +2547,10 @@ _select_clear(PyObject *module) Py_CLEAR(state->poll_Type); Py_CLEAR(state->devpoll_Type); Py_CLEAR(state->pyEpoll_Type); +#ifdef HAVE_KQUEUE Py_CLEAR(state->kqueue_event_Type); Py_CLEAR(state->kqueue_queue_Type); +#endif return 0; } @@ -2552,6 +2684,8 @@ _select_exec(PyObject *m) #endif /* HAVE_EPOLL */ #ifdef HAVE_KQUEUE + state->kqueue_open_list = NULL; + state->kqueue_event_Type = (PyTypeObject *)PyType_FromModuleAndSpec( m, &kqueue_event_Type_spec, NULL); if (state->kqueue_event_Type == NULL) { @@ -2650,6 +2784,7 @@ _select_exec(PyObject *m) static PyModuleDef_Slot _select_slots[] = { {Py_mod_exec, _select_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; |