• 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 [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