/* * 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) && !defined(__ANDROID__) _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}, {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); }