0
0
mirror of https://github.com/python/cpython.git synced 2024-12-01 03:01:36 +01:00
cpython/Modules/_multiprocessing/multiprocessing.c
Brett Simmers c2627d6eea
gh-116322: Add Py_mod_gil module slot (#116882)
This PR adds the ability to enable the GIL if it was disabled at
interpreter startup, and modifies the multi-phase module initialization
path to enable the GIL when loading a module, unless that module's spec
includes a slot indicating it can run safely without the GIL.

PEP 703 called the constant for the slot `Py_mod_gil_not_used`; I went
with `Py_MOD_GIL_NOT_USED` for consistency with gh-104148.

A warning will be issued up to once per interpreter for the first
GIL-using module that is loaded. If `-v` is given, a shorter message
will be printed to stderr every time a GIL-using module is loaded
(including the first one that issues a warning).
2024-05-03 11:30:55 -04:00

297 lines
7.2 KiB
C

/*
* Extension module used by multiprocessing package
*
* multiprocessing.c
*
* Copyright (c) 2006-2008, R Oudkerk
* Licensed to PSF under a Contributor Agreement.
*/
#include "multiprocessing.h"
/*[python input]
class HANDLE_converter(CConverter):
type = "HANDLE"
format_unit = '"F_HANDLE"'
def parse_arg(self, argname, displayname, *, limited_capi):
return self.format_code("""
{paramname} = PyLong_AsVoidPtr({argname});
if (!{paramname} && PyErr_Occurred()) {{{{
goto exit;
}}}}
""",
argname=argname)
[python start generated code]*/
/*[python end generated code: output=da39a3ee5e6b4b0d input=3cf0318efc6a8772]*/
/*[clinic input]
module _multiprocessing
[clinic start generated code]*/
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=01e0745f380ac6e3]*/
#include "clinic/multiprocessing.c.h"
/*
* Function which raises exceptions based on error codes
*/
PyObject *
_PyMp_SetError(PyObject *Type, int num)
{
switch (num) {
#ifdef MS_WINDOWS
case MP_STANDARD_ERROR:
if (Type == NULL)
Type = PyExc_OSError;
PyErr_SetExcFromWindowsErr(Type, 0);
break;
case MP_SOCKET_ERROR:
if (Type == NULL)
Type = PyExc_OSError;
PyErr_SetExcFromWindowsErr(Type, WSAGetLastError());
break;
#else /* !MS_WINDOWS */
case MP_STANDARD_ERROR:
case MP_SOCKET_ERROR:
if (Type == NULL)
Type = PyExc_OSError;
PyErr_SetFromErrno(Type);
break;
#endif /* !MS_WINDOWS */
case MP_MEMORY_ERROR:
PyErr_NoMemory();
break;
case MP_EXCEPTION_HAS_BEEN_SET:
break;
default:
PyErr_Format(PyExc_RuntimeError,
"unknown error number %d", num);
}
return NULL;
}
#ifdef MS_WINDOWS
/*[clinic input]
_multiprocessing.closesocket
handle: HANDLE
/
[clinic start generated code]*/
static PyObject *
_multiprocessing_closesocket_impl(PyObject *module, HANDLE handle)
/*[clinic end generated code: output=214f359f900966f4 input=8a20706dd386c6cc]*/
{
int ret;
Py_BEGIN_ALLOW_THREADS
ret = closesocket((SOCKET) handle);
Py_END_ALLOW_THREADS
if (ret)
return PyErr_SetExcFromWindowsErr(PyExc_OSError, WSAGetLastError());
Py_RETURN_NONE;
}
/*[clinic input]
_multiprocessing.recv
handle: HANDLE
size: int
/
[clinic start generated code]*/
static PyObject *
_multiprocessing_recv_impl(PyObject *module, HANDLE handle, int size)
/*[clinic end generated code: output=92322781ba9ff598 input=6a5b0834372cee5b]*/
{
int nread;
PyObject *buf;
buf = PyBytes_FromStringAndSize(NULL, size);
if (!buf)
return NULL;
Py_BEGIN_ALLOW_THREADS
nread = recv((SOCKET) handle, PyBytes_AS_STRING(buf), size, 0);
Py_END_ALLOW_THREADS
if (nread < 0) {
Py_DECREF(buf);
return PyErr_SetExcFromWindowsErr(PyExc_OSError, WSAGetLastError());
}
_PyBytes_Resize(&buf, nread);
return buf;
}
/*[clinic input]
_multiprocessing.send
handle: HANDLE
buf: Py_buffer
/
[clinic start generated code]*/
static PyObject *
_multiprocessing_send_impl(PyObject *module, HANDLE handle, Py_buffer *buf)
/*[clinic end generated code: output=52d7df0519c596cb input=41dce742f98d2210]*/
{
int ret, length;
length = (int)Py_MIN(buf->len, INT_MAX);
Py_BEGIN_ALLOW_THREADS
ret = send((SOCKET) handle, buf->buf, length, 0);
Py_END_ALLOW_THREADS
if (ret < 0)
return PyErr_SetExcFromWindowsErr(PyExc_OSError, WSAGetLastError());
return PyLong_FromLong(ret);
}
#endif
/*[clinic input]
_multiprocessing.sem_unlink
name: str
/
[clinic start generated code]*/
static PyObject *
_multiprocessing_sem_unlink_impl(PyObject *module, const char *name)
/*[clinic end generated code: output=fcbfeb1ed255e647 input=bf939aff9564f1d5]*/
{
return _PyMp_sem_unlink(name);
}
/*
* Function table
*/
static PyMethodDef module_methods[] = {
#ifdef MS_WINDOWS
_MULTIPROCESSING_CLOSESOCKET_METHODDEF
_MULTIPROCESSING_RECV_METHODDEF
_MULTIPROCESSING_SEND_METHODDEF
#endif
#if !defined(POSIX_SEMAPHORES_NOT_ENABLED)
_MULTIPROCESSING_SEM_UNLINK_METHODDEF
#endif
{NULL}
};
/*
* Initialize
*/
static int
multiprocessing_exec(PyObject *module)
{
#ifdef HAVE_MP_SEMAPHORE
PyTypeObject *semlock_type = (PyTypeObject *)PyType_FromModuleAndSpec(
module, &_PyMp_SemLockType_spec, NULL);
if (semlock_type == NULL) {
return -1;
}
int rc = PyModule_AddType(module, semlock_type);
Py_DECREF(semlock_type);
if (rc < 0) {
return -1;
}
PyObject *py_sem_value_max;
/* Some systems define SEM_VALUE_MAX as an unsigned value that
* causes it to be negative when used as an int (NetBSD).
*
* Issue #28152: Use (0) instead of 0 to fix a warning on dead code
* when using clang -Wunreachable-code. */
if ((int)(SEM_VALUE_MAX) < (0)) {
py_sem_value_max = PyLong_FromLong(INT_MAX);
}
else {
py_sem_value_max = PyLong_FromLong(SEM_VALUE_MAX);
}
if (py_sem_value_max == NULL) {
return -1;
}
if (PyDict_SetItemString(semlock_type->tp_dict, "SEM_VALUE_MAX",
py_sem_value_max) < 0) {
Py_DECREF(py_sem_value_max);
return -1;
}
Py_DECREF(py_sem_value_max);
#endif
/* Add configuration macros */
PyObject *flags = PyDict_New();
if (!flags) {
return -1;
}
#define ADD_FLAG(name) \
do { \
PyObject *value = PyLong_FromLong(name); \
if (value == NULL) { \
Py_DECREF(flags); \
return -1; \
} \
if (PyDict_SetItemString(flags, #name, value) < 0) { \
Py_DECREF(flags); \
Py_DECREF(value); \
return -1; \
} \
Py_DECREF(value); \
} while (0)
#if defined(HAVE_SEM_OPEN) && !defined(POSIX_SEMAPHORES_NOT_ENABLED)
ADD_FLAG(HAVE_SEM_OPEN);
#endif
#ifdef HAVE_SEM_TIMEDWAIT
ADD_FLAG(HAVE_SEM_TIMEDWAIT);
#endif
#ifdef HAVE_BROKEN_SEM_GETVALUE
ADD_FLAG(HAVE_BROKEN_SEM_GETVALUE);
#endif
#ifdef HAVE_BROKEN_SEM_UNLINK
ADD_FLAG(HAVE_BROKEN_SEM_UNLINK);
#endif
if (PyModule_Add(module, "flags", flags) < 0) {
return -1;
}
return 0;
}
static PyModuleDef_Slot multiprocessing_slots[] = {
{Py_mod_exec, multiprocessing_exec},
{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
{Py_mod_gil, Py_MOD_GIL_NOT_USED},
{0, NULL}
};
static struct PyModuleDef multiprocessing_module = {
PyModuleDef_HEAD_INIT,
.m_name = "_multiprocessing",
.m_size = 0,
.m_methods = module_methods,
.m_slots = multiprocessing_slots,
};
PyMODINIT_FUNC
PyInit__multiprocessing(void)
{
return PyModuleDef_Init(&multiprocessing_module);
}