blob: ee250e00439a05f5eda44a20bade590b4ad2e2b6 [file] [log] [blame]
Benjamin Petersonfa268032008-06-13 19:28:21 +00001/*
2 * Extension module used by multiprocessing package
3 *
4 * multiprocessing.c
5 *
6 * Copyright (c) 2006-2008, R Oudkerk --- see COPYING.txt
7 */
8
9#include "multiprocessing.h"
10
Charles-François Natali10db4de2011-12-14 18:39:09 +010011#if (defined(CMSG_LEN) && defined(SCM_RIGHTS))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000012 #define HAVE_FD_TRANSFER 1
Benjamin Peterson965ce872009-04-05 21:24:58 +000013#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000014 #define HAVE_FD_TRANSFER 0
Benjamin Peterson965ce872009-04-05 21:24:58 +000015#endif
16
Benjamin Petersonfa268032008-06-13 19:28:21 +000017PyObject *create_win32_namespace(void);
18
19PyObject *pickle_dumps, *pickle_loads, *pickle_protocol;
20PyObject *ProcessError, *BufferTooShort;
21
22/*
23 * Function which raises exceptions based on error codes
24 */
25
26PyObject *
27mp_SetError(PyObject *Type, int num)
28{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000029 switch (num) {
Benjamin Petersonfa268032008-06-13 19:28:21 +000030#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000031 case MP_STANDARD_ERROR:
32 if (Type == NULL)
33 Type = PyExc_WindowsError;
34 PyErr_SetExcFromWindowsErr(Type, 0);
35 break;
36 case MP_SOCKET_ERROR:
37 if (Type == NULL)
38 Type = PyExc_WindowsError;
39 PyErr_SetExcFromWindowsErr(Type, WSAGetLastError());
40 break;
Benjamin Petersonfa268032008-06-13 19:28:21 +000041#else /* !MS_WINDOWS */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000042 case MP_STANDARD_ERROR:
43 case MP_SOCKET_ERROR:
44 if (Type == NULL)
45 Type = PyExc_OSError;
46 PyErr_SetFromErrno(Type);
47 break;
Benjamin Petersonfa268032008-06-13 19:28:21 +000048#endif /* !MS_WINDOWS */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000049 case MP_MEMORY_ERROR:
50 PyErr_NoMemory();
51 break;
52 case MP_END_OF_FILE:
53 PyErr_SetNone(PyExc_EOFError);
54 break;
55 case MP_EARLY_END_OF_FILE:
56 PyErr_SetString(PyExc_IOError,
57 "got end of file during message");
58 break;
59 case MP_BAD_MESSAGE_LENGTH:
60 PyErr_SetString(PyExc_IOError, "bad message length");
61 break;
62 case MP_EXCEPTION_HAS_BEEN_SET:
63 break;
64 default:
65 PyErr_Format(PyExc_RuntimeError,
66 "unkown error number %d", num);
67 }
68 return NULL;
Benjamin Petersonfa268032008-06-13 19:28:21 +000069}
70
71
72/*
73 * Windows only
74 */
75
76#ifdef MS_WINDOWS
77
78/* On Windows we set an event to signal Ctrl-C; compare with timemodule.c */
79
80HANDLE sigint_event = NULL;
81
82static BOOL WINAPI
83ProcessingCtrlHandler(DWORD dwCtrlType)
84{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000085 SetEvent(sigint_event);
86 return FALSE;
Benjamin Petersonfa268032008-06-13 19:28:21 +000087}
88
89/*
90 * Unix only
91 */
92
93#else /* !MS_WINDOWS */
94
95#if HAVE_FD_TRANSFER
96
97/* Functions for transferring file descriptors between processes.
98 Reimplements some of the functionality of the fdcred
99 module at http://www.mca-ltd.com/resources/fdcred_1.tgz. */
Jesus Ceaab7060e2011-09-10 04:04:09 +0200100/* Based in http://resin.csoft.net/cgi-bin/man.cgi?section=3&topic=CMSG_DATA */
Benjamin Petersonfa268032008-06-13 19:28:21 +0000101
102static PyObject *
103multiprocessing_sendfd(PyObject *self, PyObject *args)
104{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000105 int conn, fd, res;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000106 struct iovec dummy_iov;
Jesus Ceaab7060e2011-09-10 04:04:09 +0200107 char dummy_char;
108 struct msghdr msg;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000109 struct cmsghdr *cmsg;
Jesus Ceaab7060e2011-09-10 04:04:09 +0200110 union {
111 struct cmsghdr hdr;
112 unsigned char buf[CMSG_SPACE(sizeof(int))];
113 } cmsgbuf;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000114
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000115 if (!PyArg_ParseTuple(args, "ii", &conn, &fd))
116 return NULL;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000117
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000118 dummy_iov.iov_base = &dummy_char;
119 dummy_iov.iov_len = 1;
Jesus Ceaab7060e2011-09-10 04:04:09 +0200120
121 memset(&msg, 0, sizeof(msg));
122 msg.msg_control = &cmsgbuf.buf;
123 msg.msg_controllen = sizeof(cmsgbuf.buf);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000124 msg.msg_iov = &dummy_iov;
125 msg.msg_iovlen = 1;
Jesus Ceaab7060e2011-09-10 04:04:09 +0200126
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000127 cmsg = CMSG_FIRSTHDR(&msg);
Jesus Ceaab7060e2011-09-10 04:04:09 +0200128 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000129 cmsg->cmsg_level = SOL_SOCKET;
130 cmsg->cmsg_type = SCM_RIGHTS;
Antoine Pitroubcb39d42011-08-23 19:46:22 +0200131 * (int *) CMSG_DATA(cmsg) = fd;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000132
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000133 Py_BEGIN_ALLOW_THREADS
134 res = sendmsg(conn, &msg, 0);
135 Py_END_ALLOW_THREADS
Benjamin Petersonfa268032008-06-13 19:28:21 +0000136
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000137 if (res < 0)
138 return PyErr_SetFromErrno(PyExc_OSError);
139 Py_RETURN_NONE;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000140}
141
142static PyObject *
143multiprocessing_recvfd(PyObject *self, PyObject *args)
144{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000145 int conn, fd, res;
146 char dummy_char;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000147 struct iovec dummy_iov;
Jesus Ceaab7060e2011-09-10 04:04:09 +0200148 struct msghdr msg = {0};
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000149 struct cmsghdr *cmsg;
Jesus Ceaab7060e2011-09-10 04:04:09 +0200150 union {
151 struct cmsghdr hdr;
152 unsigned char buf[CMSG_SPACE(sizeof(int))];
153 } cmsgbuf;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000154
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000155 if (!PyArg_ParseTuple(args, "i", &conn))
156 return NULL;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000157
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000158 dummy_iov.iov_base = &dummy_char;
159 dummy_iov.iov_len = 1;
Jesus Ceaab7060e2011-09-10 04:04:09 +0200160
161 memset(&msg, 0, sizeof(msg));
162 msg.msg_control = &cmsgbuf.buf;
163 msg.msg_controllen = sizeof(cmsgbuf.buf);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000164 msg.msg_iov = &dummy_iov;
165 msg.msg_iovlen = 1;
Jesus Ceaab7060e2011-09-10 04:04:09 +0200166
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000167 cmsg = CMSG_FIRSTHDR(&msg);
168 cmsg->cmsg_level = SOL_SOCKET;
169 cmsg->cmsg_type = SCM_RIGHTS;
170 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
171 msg.msg_controllen = cmsg->cmsg_len;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000172
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000173 Py_BEGIN_ALLOW_THREADS
174 res = recvmsg(conn, &msg, 0);
175 Py_END_ALLOW_THREADS
Benjamin Petersonfa268032008-06-13 19:28:21 +0000176
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000177 if (res < 0)
178 return PyErr_SetFromErrno(PyExc_OSError);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000179
Jesus Cea4507e642011-09-21 03:53:25 +0200180 if (msg.msg_controllen < CMSG_LEN(sizeof(int)) ||
181 (cmsg = CMSG_FIRSTHDR(&msg)) == NULL ||
182 cmsg->cmsg_level != SOL_SOCKET ||
183 cmsg->cmsg_type != SCM_RIGHTS ||
184 cmsg->cmsg_len < CMSG_LEN(sizeof(int))) {
185 /* If at least one control message is present, there should be
186 no room for any further data in the buffer. */
187 PyErr_SetString(PyExc_RuntimeError, "No file descriptor received");
188 return NULL;
189 }
190
Antoine Pitroubcb39d42011-08-23 19:46:22 +0200191 fd = * (int *) CMSG_DATA(cmsg);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000192 return Py_BuildValue("i", fd);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000193}
194
195#endif /* HAVE_FD_TRANSFER */
196
197#endif /* !MS_WINDOWS */
198
199
200/*
201 * All platforms
202 */
203
204static PyObject*
205multiprocessing_address_of_buffer(PyObject *self, PyObject *obj)
206{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000207 void *buffer;
208 Py_ssize_t buffer_len;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000209
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000210 if (PyObject_AsWriteBuffer(obj, &buffer, &buffer_len) < 0)
211 return NULL;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000212
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000213 return Py_BuildValue("N" F_PY_SSIZE_T,
214 PyLong_FromVoidPtr(buffer), buffer_len);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000215}
216
217
218/*
219 * Function table
220 */
221
222static PyMethodDef module_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000223 {"address_of_buffer", multiprocessing_address_of_buffer, METH_O,
224 "address_of_buffer(obj) -> int\n"
225 "Return address of obj assuming obj supports buffer inteface"},
Benjamin Petersonfa268032008-06-13 19:28:21 +0000226#if HAVE_FD_TRANSFER
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000227 {"sendfd", multiprocessing_sendfd, METH_VARARGS,
228 "sendfd(sockfd, fd) -> None\n"
229 "Send file descriptor given by fd over the unix domain socket\n"
230 "whose file decriptor is sockfd"},
231 {"recvfd", multiprocessing_recvfd, METH_VARARGS,
232 "recvfd(sockfd) -> fd\n"
233 "Receive a file descriptor over a unix domain socket\n"
234 "whose file decriptor is sockfd"},
Benjamin Petersonfa268032008-06-13 19:28:21 +0000235#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000236 {NULL}
Benjamin Petersonfa268032008-06-13 19:28:21 +0000237};
238
239
240/*
241 * Initialize
242 */
243
244static struct PyModuleDef multiprocessing_module = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000245 PyModuleDef_HEAD_INIT,
246 "_multiprocessing",
247 NULL,
248 -1,
249 module_methods,
250 NULL,
251 NULL,
252 NULL,
253 NULL
Benjamin Petersonfa268032008-06-13 19:28:21 +0000254};
255
256
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000257PyMODINIT_FUNC
Benjamin Petersonfa268032008-06-13 19:28:21 +0000258PyInit__multiprocessing(void)
259{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000260 PyObject *module, *temp, *value;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000261
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000262 /* Initialize module */
263 module = PyModule_Create(&multiprocessing_module);
264 if (!module)
265 return NULL;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000266
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000267 /* Get copy of objects from pickle */
268 temp = PyImport_ImportModule(PICKLE_MODULE);
269 if (!temp)
270 return NULL;
271 pickle_dumps = PyObject_GetAttrString(temp, "dumps");
272 pickle_loads = PyObject_GetAttrString(temp, "loads");
273 pickle_protocol = PyObject_GetAttrString(temp, "HIGHEST_PROTOCOL");
274 Py_XDECREF(temp);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000275
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000276 /* Get copy of BufferTooShort */
277 temp = PyImport_ImportModule("multiprocessing");
278 if (!temp)
279 return NULL;
280 BufferTooShort = PyObject_GetAttrString(temp, "BufferTooShort");
281 Py_XDECREF(temp);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000282
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000283 /* Add connection type to module */
284 if (PyType_Ready(&ConnectionType) < 0)
285 return NULL;
286 Py_INCREF(&ConnectionType);
287 PyModule_AddObject(module, "Connection", (PyObject*)&ConnectionType);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000288
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000289#if defined(MS_WINDOWS) || \
Mark Dickinsona614f042009-11-28 12:48:43 +0000290 (defined(HAVE_SEM_OPEN) && !defined(POSIX_SEMAPHORES_NOT_ENABLED))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000291 /* Add SemLock type to module */
292 if (PyType_Ready(&SemLockType) < 0)
293 return NULL;
294 Py_INCREF(&SemLockType);
Gregory P. Smith68e01352010-10-17 02:14:36 +0000295 {
296 PyObject *py_sem_value_max;
297 /* Some systems define SEM_VALUE_MAX as an unsigned value that
298 * causes it to be negative when used as an int (NetBSD). */
299 if ((int)(SEM_VALUE_MAX) < 0)
300 py_sem_value_max = PyLong_FromLong(INT_MAX);
301 else
302 py_sem_value_max = PyLong_FromLong(SEM_VALUE_MAX);
303 if (py_sem_value_max == NULL)
304 return NULL;
305 PyDict_SetItemString(SemLockType.tp_dict, "SEM_VALUE_MAX",
306 py_sem_value_max);
307 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000308 PyModule_AddObject(module, "SemLock", (PyObject*)&SemLockType);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000309#endif
310
311#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000312 /* Add PipeConnection to module */
313 if (PyType_Ready(&PipeConnectionType) < 0)
314 return NULL;
315 Py_INCREF(&PipeConnectionType);
316 PyModule_AddObject(module, "PipeConnection",
317 (PyObject*)&PipeConnectionType);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000318
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000319 /* Initialize win32 class and add to multiprocessing */
320 temp = create_win32_namespace();
321 if (!temp)
322 return NULL;
323 PyModule_AddObject(module, "win32", temp);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000324
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000325 /* Initialize the event handle used to signal Ctrl-C */
326 sigint_event = CreateEvent(NULL, TRUE, FALSE, NULL);
327 if (!sigint_event) {
328 PyErr_SetFromWindowsErr(0);
329 return NULL;
330 }
331 if (!SetConsoleCtrlHandler(ProcessingCtrlHandler, TRUE)) {
332 PyErr_SetFromWindowsErr(0);
333 return NULL;
334 }
Benjamin Petersonfa268032008-06-13 19:28:21 +0000335#endif
336
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000337 /* Add configuration macros */
338 temp = PyDict_New();
339 if (!temp)
340 return NULL;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000341
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000342#define ADD_FLAG(name) \
343 value = Py_BuildValue("i", name); \
344 if (value == NULL) { Py_DECREF(temp); return NULL; } \
345 if (PyDict_SetItemString(temp, #name, value) < 0) { \
346 Py_DECREF(temp); Py_DECREF(value); return NULL; } \
347 Py_DECREF(value)
348
Mark Dickinsona614f042009-11-28 12:48:43 +0000349#if defined(HAVE_SEM_OPEN) && !defined(POSIX_SEMAPHORES_NOT_ENABLED)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000350 ADD_FLAG(HAVE_SEM_OPEN);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000351#endif
352#ifdef HAVE_SEM_TIMEDWAIT
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000353 ADD_FLAG(HAVE_SEM_TIMEDWAIT);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000354#endif
355#ifdef HAVE_FD_TRANSFER
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000356 ADD_FLAG(HAVE_FD_TRANSFER);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000357#endif
358#ifdef HAVE_BROKEN_SEM_GETVALUE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000359 ADD_FLAG(HAVE_BROKEN_SEM_GETVALUE);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000360#endif
361#ifdef HAVE_BROKEN_SEM_UNLINK
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000362 ADD_FLAG(HAVE_BROKEN_SEM_UNLINK);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000363#endif
364
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000365 if (PyModule_AddObject(module, "flags", temp) < 0)
366 return NULL;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000367
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000368 return module;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000369}