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