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
13 /*
14 * Function which raises exceptions based on error codes
15 */
16
17 PyObject *
_PyMp_SetError(PyObject * Type,int num)18 _PyMp_SetError(PyObject *Type, int num)
19 {
20 switch (num) {
21 #ifdef MS_WINDOWS
22 case MP_STANDARD_ERROR:
23 if (Type == NULL)
24 Type = PyExc_OSError;
25 PyErr_SetExcFromWindowsErr(Type, 0);
26 break;
27 case MP_SOCKET_ERROR:
28 if (Type == NULL)
29 Type = PyExc_OSError;
30 PyErr_SetExcFromWindowsErr(Type, WSAGetLastError());
31 break;
32 #else /* !MS_WINDOWS */
33 case MP_STANDARD_ERROR:
34 case MP_SOCKET_ERROR:
35 if (Type == NULL)
36 Type = PyExc_OSError;
37 PyErr_SetFromErrno(Type);
38 break;
39 #endif /* !MS_WINDOWS */
40 case MP_MEMORY_ERROR:
41 PyErr_NoMemory();
42 break;
43 case MP_EXCEPTION_HAS_BEEN_SET:
44 break;
45 default:
46 PyErr_Format(PyExc_RuntimeError,
47 "unknown error number %d", num);
48 }
49 return NULL;
50 }
51
52 #ifdef MS_WINDOWS
53 static PyObject *
multiprocessing_closesocket(PyObject * self,PyObject * args)54 multiprocessing_closesocket(PyObject *self, PyObject *args)
55 {
56 HANDLE handle;
57 int ret;
58
59 if (!PyArg_ParseTuple(args, F_HANDLE ":closesocket" , &handle))
60 return NULL;
61
62 Py_BEGIN_ALLOW_THREADS
63 ret = closesocket((SOCKET) handle);
64 Py_END_ALLOW_THREADS
65
66 if (ret)
67 return PyErr_SetExcFromWindowsErr(PyExc_OSError, WSAGetLastError());
68 Py_RETURN_NONE;
69 }
70
71 static PyObject *
multiprocessing_recv(PyObject * self,PyObject * args)72 multiprocessing_recv(PyObject *self, PyObject *args)
73 {
74 HANDLE handle;
75 int size, nread;
76 PyObject *buf;
77
78 if (!PyArg_ParseTuple(args, F_HANDLE "i:recv" , &handle, &size))
79 return NULL;
80
81 buf = PyBytes_FromStringAndSize(NULL, size);
82 if (!buf)
83 return NULL;
84
85 Py_BEGIN_ALLOW_THREADS
86 nread = recv((SOCKET) handle, PyBytes_AS_STRING(buf), size, 0);
87 Py_END_ALLOW_THREADS
88
89 if (nread < 0) {
90 Py_DECREF(buf);
91 return PyErr_SetExcFromWindowsErr(PyExc_OSError, WSAGetLastError());
92 }
93 _PyBytes_Resize(&buf, nread);
94 return buf;
95 }
96
97 static PyObject *
multiprocessing_send(PyObject * self,PyObject * args)98 multiprocessing_send(PyObject *self, PyObject *args)
99 {
100 HANDLE handle;
101 Py_buffer buf;
102 int ret, length;
103
104 if (!PyArg_ParseTuple(args, F_HANDLE "y*:send" , &handle, &buf))
105 return NULL;
106
107 length = (int)Py_MIN(buf.len, INT_MAX);
108
109 Py_BEGIN_ALLOW_THREADS
110 ret = send((SOCKET) handle, buf.buf, length, 0);
111 Py_END_ALLOW_THREADS
112
113 PyBuffer_Release(&buf);
114 if (ret < 0)
115 return PyErr_SetExcFromWindowsErr(PyExc_OSError, WSAGetLastError());
116 return PyLong_FromLong(ret);
117 }
118
119 #endif
120
121 /*
122 * Function table
123 */
124
125 static PyMethodDef module_methods[] = {
126 #ifdef MS_WINDOWS
127 {"closesocket", multiprocessing_closesocket, METH_VARARGS, ""},
128 {"recv", multiprocessing_recv, METH_VARARGS, ""},
129 {"send", multiprocessing_send, METH_VARARGS, ""},
130 #endif
131 #if !defined(POSIX_SEMAPHORES_NOT_ENABLED) && !defined(__ANDROID__)
132 {"sem_unlink", _PyMp_sem_unlink, METH_VARARGS, ""},
133 #endif
134 {NULL}
135 };
136
137
138 /*
139 * Initialize
140 */
141
142 static struct PyModuleDef multiprocessing_module = {
143 PyModuleDef_HEAD_INIT,
144 "_multiprocessing",
145 NULL,
146 -1,
147 module_methods,
148 NULL,
149 NULL,
150 NULL,
151 NULL
152 };
153
154
155 PyMODINIT_FUNC
PyInit__multiprocessing(void)156 PyInit__multiprocessing(void)
157 {
158 PyObject *module, *temp, *value = NULL;
159
160 /* Initialize module */
161 module = PyModule_Create(&multiprocessing_module);
162 if (!module)
163 return NULL;
164
165 #if defined(MS_WINDOWS) || \
166 (defined(HAVE_SEM_OPEN) && !defined(POSIX_SEMAPHORES_NOT_ENABLED))
167 /* Add _PyMp_SemLock type to module */
168 if (PyType_Ready(&_PyMp_SemLockType) < 0)
169 return NULL;
170 Py_INCREF(&_PyMp_SemLockType);
171 {
172 PyObject *py_sem_value_max;
173 /* Some systems define SEM_VALUE_MAX as an unsigned value that
174 * causes it to be negative when used as an int (NetBSD).
175 *
176 * Issue #28152: Use (0) instead of 0 to fix a warning on dead code
177 * when using clang -Wunreachable-code. */
178 if ((int)(SEM_VALUE_MAX) < (0))
179 py_sem_value_max = PyLong_FromLong(INT_MAX);
180 else
181 py_sem_value_max = PyLong_FromLong(SEM_VALUE_MAX);
182 if (py_sem_value_max == NULL)
183 return NULL;
184 PyDict_SetItemString(_PyMp_SemLockType.tp_dict, "SEM_VALUE_MAX",
185 py_sem_value_max);
186 }
187 PyModule_AddObject(module, "SemLock", (PyObject*)&_PyMp_SemLockType);
188 #endif
189
190 /* Add configuration macros */
191 temp = PyDict_New();
192 if (!temp)
193 return NULL;
194
195 #define ADD_FLAG(name) \
196 value = Py_BuildValue("i", name); \
197 if (value == NULL) { Py_DECREF(temp); return NULL; } \
198 if (PyDict_SetItemString(temp, #name, value) < 0) { \
199 Py_DECREF(temp); Py_DECREF(value); return NULL; } \
200 Py_DECREF(value)
201
202 #if defined(HAVE_SEM_OPEN) && !defined(POSIX_SEMAPHORES_NOT_ENABLED)
203 ADD_FLAG(HAVE_SEM_OPEN);
204 #endif
205 #ifdef HAVE_SEM_TIMEDWAIT
206 ADD_FLAG(HAVE_SEM_TIMEDWAIT);
207 #endif
208 #ifdef HAVE_BROKEN_SEM_GETVALUE
209 ADD_FLAG(HAVE_BROKEN_SEM_GETVALUE);
210 #endif
211 #ifdef HAVE_BROKEN_SEM_UNLINK
212 ADD_FLAG(HAVE_BROKEN_SEM_UNLINK);
213 #endif
214
215 if (PyModule_AddObject(module, "flags", temp) < 0)
216 return NULL;
217
218 return module;
219 }
220