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 * |
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 * |
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 * |
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 * |
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 * |
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 |
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 |
277 | PyInit__multiprocessing(void) |
278 | { |
279 | return PyModuleDef_Init(&multiprocessing_module); |
280 | } |
281 | |