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