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 [python start generated code]*/
18 /*[python end generated code: output=da39a3ee5e6b4b0d input=9fad6080b79ace91]*/
19
20 /*[clinic input]
21 module _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
31 PyObject *
_PyMp_SetError(PyObject * Type,int num)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
75 static PyObject *
_multiprocessing_closesocket_impl(PyObject * module,HANDLE handle)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
99 static PyObject *
_multiprocessing_recv_impl(PyObject * module,HANDLE handle,int size)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
131 static PyObject *
_multiprocessing_send_impl(PyObject * module,HANDLE handle,Py_buffer * buf)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
158 static PyObject *
_multiprocessing_sem_unlink_impl(PyObject * module,const char * name)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
169 static 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
186 static int
multiprocessing_exec(PyObject * module)187 multiprocessing_exec(PyObject *module)
188 {
189 #if defined(MS_WINDOWS) || \
190 (defined(HAVE_SEM_OPEN) && !defined(POSIX_SEMAPHORES_NOT_ENABLED))
191
192 /* Add _PyMp_SemLock type to module */
193 if (PyModule_AddType(module, &_PyMp_SemLockType) < 0) {
194 return -1;
195 }
196
197 {
198 PyObject *py_sem_value_max;
199 /* Some systems define SEM_VALUE_MAX as an unsigned value that
200 * causes it to be negative when used as an int (NetBSD).
201 *
202 * Issue #28152: Use (0) instead of 0 to fix a warning on dead code
203 * when using clang -Wunreachable-code. */
204 if ((int)(SEM_VALUE_MAX) < (0))
205 py_sem_value_max = PyLong_FromLong(INT_MAX);
206 else
207 py_sem_value_max = PyLong_FromLong(SEM_VALUE_MAX);
208
209 if (py_sem_value_max == NULL) {
210 return -1;
211 }
212 if (PyDict_SetItemString(_PyMp_SemLockType.tp_dict, "SEM_VALUE_MAX",
213 py_sem_value_max) < 0) {
214 Py_DECREF(py_sem_value_max);
215 return -1;
216 }
217 Py_DECREF(py_sem_value_max);
218 }
219
220 #endif
221
222 /* Add configuration macros */
223 PyObject *flags = PyDict_New();
224 if (!flags) {
225 return -1;
226 }
227
228 #define ADD_FLAG(name) \
229 do { \
230 PyObject *value = PyLong_FromLong(name); \
231 if (value == NULL) { \
232 Py_DECREF(flags); \
233 return -1; \
234 } \
235 if (PyDict_SetItemString(flags, #name, value) < 0) { \
236 Py_DECREF(flags); \
237 Py_DECREF(value); \
238 return -1; \
239 } \
240 Py_DECREF(value); \
241 } while (0)
242
243 #if defined(HAVE_SEM_OPEN) && !defined(POSIX_SEMAPHORES_NOT_ENABLED)
244 ADD_FLAG(HAVE_SEM_OPEN);
245 #endif
246 #ifdef HAVE_SEM_TIMEDWAIT
247 ADD_FLAG(HAVE_SEM_TIMEDWAIT);
248 #endif
249 #ifdef HAVE_BROKEN_SEM_GETVALUE
250 ADD_FLAG(HAVE_BROKEN_SEM_GETVALUE);
251 #endif
252 #ifdef HAVE_BROKEN_SEM_UNLINK
253 ADD_FLAG(HAVE_BROKEN_SEM_UNLINK);
254 #endif
255
256 if (PyModule_AddObject(module, "flags", flags) < 0) {
257 Py_DECREF(flags);
258 return -1;
259 }
260
261 return 0;
262 }
263
264 static PyModuleDef_Slot multiprocessing_slots[] = {
265 {Py_mod_exec, multiprocessing_exec},
266 {0, NULL}
267 };
268
269 static struct PyModuleDef multiprocessing_module = {
270 PyModuleDef_HEAD_INIT,
271 .m_name = "_multiprocessing",
272 .m_methods = module_methods,
273 .m_slots = multiprocessing_slots,
274 };
275
276 PyMODINIT_FUNC
PyInit__multiprocessing(void)277 PyInit__multiprocessing(void)
278 {
279 return PyModuleDef_Init(&multiprocessing_module);
280 }
281