1/*
2 * Extension module used by multiprocessing package
3 *
4 * multiprocessing.c
5 *
6 * Copyright (c) 2006-2008, R Oudkerk
7 * Licensed to PSF under a Contributor Agreement.
8 */
9
10#include "multiprocessing.h"
11
12/*[python input]
13class HANDLE_converter(CConverter):
14    type = "HANDLE"
15    format_unit = '"F_HANDLE"'
16
17[python start generated code]*/
18/*[python end generated code: output=da39a3ee5e6b4b0d input=9fad6080b79ace91]*/
19
20/*[clinic input]
21module _multiprocessing
22[clinic start generated code]*/
23/*[clinic end generated code: output=da39a3ee5e6b4b0d input=01e0745f380ac6e3]*/
24
25#include "clinic/multiprocessing.c.h"
26
27/*
28 * Function which raises exceptions based on error codes
29 */
30
31PyObject *
32_PyMp_SetError(PyObject *Type, int num)
33{
34    switch (num) {
35#ifdef MS_WINDOWS
36    case MP_STANDARD_ERROR:
37        if (Type == NULL)
38            Type = PyExc_OSError;
39        PyErr_SetExcFromWindowsErr(Type, 0);
40        break;
41    case MP_SOCKET_ERROR:
42        if (Type == NULL)
43            Type = PyExc_OSError;
44        PyErr_SetExcFromWindowsErr(Type, WSAGetLastError());
45        break;
46#else /* !MS_WINDOWS */
47    case MP_STANDARD_ERROR:
48    case MP_SOCKET_ERROR:
49        if (Type == NULL)
50            Type = PyExc_OSError;
51        PyErr_SetFromErrno(Type);
52        break;
53#endif /* !MS_WINDOWS */
54    case MP_MEMORY_ERROR:
55        PyErr_NoMemory();
56        break;
57    case MP_EXCEPTION_HAS_BEEN_SET:
58        break;
59    default:
60        PyErr_Format(PyExc_RuntimeError,
61                     "unknown error number %d", num);
62    }
63    return NULL;
64}
65
66#ifdef MS_WINDOWS
67/*[clinic input]
68_multiprocessing.closesocket
69
70    handle: HANDLE
71    /
72
73[clinic start generated code]*/
74
75static PyObject *
76_multiprocessing_closesocket_impl(PyObject *module, HANDLE handle)
77/*[clinic end generated code: output=214f359f900966f4 input=8a20706dd386c6cc]*/
78{
79    int ret;
80
81    Py_BEGIN_ALLOW_THREADS
82    ret = closesocket((SOCKET) handle);
83    Py_END_ALLOW_THREADS
84
85    if (ret)
86        return PyErr_SetExcFromWindowsErr(PyExc_OSError, WSAGetLastError());
87    Py_RETURN_NONE;
88}
89
90/*[clinic input]
91_multiprocessing.recv
92
93    handle: HANDLE
94    size: int
95    /
96
97[clinic start generated code]*/
98
99static PyObject *
100_multiprocessing_recv_impl(PyObject *module, HANDLE handle, int size)
101/*[clinic end generated code: output=92322781ba9ff598 input=6a5b0834372cee5b]*/
102{
103    int nread;
104    PyObject *buf;
105
106    buf = PyBytes_FromStringAndSize(NULL, size);
107    if (!buf)
108        return NULL;
109
110    Py_BEGIN_ALLOW_THREADS
111    nread = recv((SOCKET) handle, PyBytes_AS_STRING(buf), size, 0);
112    Py_END_ALLOW_THREADS
113
114    if (nread < 0) {
115        Py_DECREF(buf);
116        return PyErr_SetExcFromWindowsErr(PyExc_OSError, WSAGetLastError());
117    }
118    _PyBytes_Resize(&buf, nread);
119    return buf;
120}
121
122/*[clinic input]
123_multiprocessing.send
124
125    handle: HANDLE
126    buf: Py_buffer
127    /
128
129[clinic start generated code]*/
130
131static PyObject *
132_multiprocessing_send_impl(PyObject *module, HANDLE handle, Py_buffer *buf)
133/*[clinic end generated code: output=52d7df0519c596cb input=41dce742f98d2210]*/
134{
135    int ret, length;
136
137    length = (int)Py_MIN(buf->len, INT_MAX);
138
139    Py_BEGIN_ALLOW_THREADS
140    ret = send((SOCKET) handle, buf->buf, length, 0);
141    Py_END_ALLOW_THREADS
142
143    if (ret < 0)
144        return PyErr_SetExcFromWindowsErr(PyExc_OSError, WSAGetLastError());
145    return PyLong_FromLong(ret);
146}
147
148#endif
149
150/*[clinic input]
151_multiprocessing.sem_unlink
152
153    name: str
154    /
155
156[clinic start generated code]*/
157
158static PyObject *
159_multiprocessing_sem_unlink_impl(PyObject *module, const char *name)
160/*[clinic end generated code: output=fcbfeb1ed255e647 input=bf939aff9564f1d5]*/
161{
162    return _PyMp_sem_unlink(name);
163}
164
165/*
166 * Function table
167 */
168
169static PyMethodDef module_methods[] = {
170#ifdef MS_WINDOWS
171    _MULTIPROCESSING_CLOSESOCKET_METHODDEF
172    _MULTIPROCESSING_RECV_METHODDEF
173    _MULTIPROCESSING_SEND_METHODDEF
174#endif
175#if !defined(POSIX_SEMAPHORES_NOT_ENABLED) && !defined(__ANDROID__)
176    _MULTIPROCESSING_SEM_UNLINK_METHODDEF
177#endif
178    {NULL}
179};
180
181
182/*
183 * Initialize
184 */
185
186static int
187multiprocessing_exec(PyObject *module)
188{
189#ifdef HAVE_MP_SEMAPHORE
190
191    /* Add _PyMp_SemLock type to module */
192    if (PyModule_AddType(module, &_PyMp_SemLockType) < 0) {
193        return -1;
194    }
195
196    {
197        PyObject *py_sem_value_max;
198        /* Some systems define SEM_VALUE_MAX as an unsigned value that
199         * causes it to be negative when used as an int (NetBSD).
200         *
201         * Issue #28152: Use (0) instead of 0 to fix a warning on dead code
202         * when using clang -Wunreachable-code. */
203        if ((int)(SEM_VALUE_MAX) < (0))
204            py_sem_value_max = PyLong_FromLong(INT_MAX);
205        else
206            py_sem_value_max = PyLong_FromLong(SEM_VALUE_MAX);
207
208        if (py_sem_value_max == NULL) {
209            return -1;
210        }
211        if (PyDict_SetItemString(_PyMp_SemLockType.tp_dict, "SEM_VALUE_MAX",
212                             py_sem_value_max) < 0) {
213            Py_DECREF(py_sem_value_max);
214            return -1;
215        }
216        Py_DECREF(py_sem_value_max);
217    }
218
219#endif
220
221    /* Add configuration macros */
222    PyObject *flags = PyDict_New();
223    if (!flags) {
224        return -1;
225    }
226
227#define ADD_FLAG(name)                                          \
228    do {                                                        \
229        PyObject *value = PyLong_FromLong(name);                \
230        if (value == NULL) {                                    \
231            Py_DECREF(flags);                                   \
232            return -1;                                          \
233        }                                                       \
234        if (PyDict_SetItemString(flags, #name, value) < 0) {    \
235            Py_DECREF(flags);                                   \
236            Py_DECREF(value);                                   \
237            return -1;                                          \
238        }                                                       \
239        Py_DECREF(value);                                       \
240    } while (0)
241
242#if defined(HAVE_SEM_OPEN) && !defined(POSIX_SEMAPHORES_NOT_ENABLED)
243    ADD_FLAG(HAVE_SEM_OPEN);
244#endif
245#ifdef HAVE_SEM_TIMEDWAIT
246    ADD_FLAG(HAVE_SEM_TIMEDWAIT);
247#endif
248#ifdef HAVE_BROKEN_SEM_GETVALUE
249    ADD_FLAG(HAVE_BROKEN_SEM_GETVALUE);
250#endif
251#ifdef HAVE_BROKEN_SEM_UNLINK
252    ADD_FLAG(HAVE_BROKEN_SEM_UNLINK);
253#endif
254
255    if (PyModule_AddObject(module, "flags", flags) < 0) {
256        Py_DECREF(flags);
257        return -1;
258    }
259
260    return 0;
261}
262
263static PyModuleDef_Slot multiprocessing_slots[] = {
264    {Py_mod_exec, multiprocessing_exec},
265    {0, NULL}
266};
267
268static struct PyModuleDef multiprocessing_module = {
269    PyModuleDef_HEAD_INIT,
270    .m_name = "_multiprocessing",
271    .m_methods = module_methods,
272    .m_slots = multiprocessing_slots,
273};
274
275PyMODINIT_FUNC
276PyInit__multiprocessing(void)
277{
278    return PyModuleDef_Init(&multiprocessing_module);
279}
280