blob: a1e6ed5986dea0fc8be36e08ec5e31f6f5b7440e [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
Benjamin Peterson965ce872009-04-05 21:24:58 +000011#ifdef 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
Benjamin Petersonfa268032008-06-13 19:28:21 +000019PyObject *ProcessError, *BufferTooShort;
20
21/*
22 * Function which raises exceptions based on error codes
23 */
24
25PyObject *
26mp_SetError(PyObject *Type, int num)
27{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000028 switch (num) {
Benjamin Petersonfa268032008-06-13 19:28:21 +000029#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000030 case MP_STANDARD_ERROR:
31 if (Type == NULL)
32 Type = PyExc_WindowsError;
33 PyErr_SetExcFromWindowsErr(Type, 0);
34 break;
35 case MP_SOCKET_ERROR:
36 if (Type == NULL)
37 Type = PyExc_WindowsError;
38 PyErr_SetExcFromWindowsErr(Type, WSAGetLastError());
39 break;
Benjamin Petersonfa268032008-06-13 19:28:21 +000040#else /* !MS_WINDOWS */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000041 case MP_STANDARD_ERROR:
42 case MP_SOCKET_ERROR:
43 if (Type == NULL)
44 Type = PyExc_OSError;
45 PyErr_SetFromErrno(Type);
46 break;
Benjamin Petersonfa268032008-06-13 19:28:21 +000047#endif /* !MS_WINDOWS */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000048 case MP_MEMORY_ERROR:
49 PyErr_NoMemory();
50 break;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000051 case MP_EXCEPTION_HAS_BEEN_SET:
52 break;
53 default:
54 PyErr_Format(PyExc_RuntimeError,
55 "unkown error number %d", num);
56 }
57 return NULL;
Benjamin Petersonfa268032008-06-13 19:28:21 +000058}
59
60
61/*
62 * Windows only
63 */
64
65#ifdef MS_WINDOWS
66
67/* On Windows we set an event to signal Ctrl-C; compare with timemodule.c */
68
69HANDLE sigint_event = NULL;
70
71static BOOL WINAPI
72ProcessingCtrlHandler(DWORD dwCtrlType)
73{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000074 SetEvent(sigint_event);
75 return FALSE;
Benjamin Petersonfa268032008-06-13 19:28:21 +000076}
77
78/*
79 * Unix only
80 */
81
82#else /* !MS_WINDOWS */
83
84#if HAVE_FD_TRANSFER
85
86/* Functions for transferring file descriptors between processes.
87 Reimplements some of the functionality of the fdcred
88 module at http://www.mca-ltd.com/resources/fdcred_1.tgz. */
Jesus Ceabbd8bec2011-09-10 04:04:09 +020089/* Based in http://resin.csoft.net/cgi-bin/man.cgi?section=3&topic=CMSG_DATA */
Benjamin Petersonfa268032008-06-13 19:28:21 +000090
91static PyObject *
92multiprocessing_sendfd(PyObject *self, PyObject *args)
93{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000094 int conn, fd, res;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000095 struct iovec dummy_iov;
Jesus Ceabbd8bec2011-09-10 04:04:09 +020096 char dummy_char;
97 struct msghdr msg;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000098 struct cmsghdr *cmsg;
Jesus Ceabbd8bec2011-09-10 04:04:09 +020099 union {
100 struct cmsghdr hdr;
101 unsigned char buf[CMSG_SPACE(sizeof(int))];
102 } cmsgbuf;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000103
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000104 if (!PyArg_ParseTuple(args, "ii", &conn, &fd))
105 return NULL;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000106
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000107 dummy_iov.iov_base = &dummy_char;
108 dummy_iov.iov_len = 1;
Jesus Ceabbd8bec2011-09-10 04:04:09 +0200109
110 memset(&msg, 0, sizeof(msg));
111 msg.msg_control = &cmsgbuf.buf;
112 msg.msg_controllen = sizeof(cmsgbuf.buf);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000113 msg.msg_iov = &dummy_iov;
114 msg.msg_iovlen = 1;
Jesus Ceabbd8bec2011-09-10 04:04:09 +0200115
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000116 cmsg = CMSG_FIRSTHDR(&msg);
Jesus Ceabbd8bec2011-09-10 04:04:09 +0200117 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000118 cmsg->cmsg_level = SOL_SOCKET;
119 cmsg->cmsg_type = SCM_RIGHTS;
Antoine Pitroubcb39d42011-08-23 19:46:22 +0200120 * (int *) CMSG_DATA(cmsg) = fd;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000121
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000122 Py_BEGIN_ALLOW_THREADS
123 res = sendmsg(conn, &msg, 0);
124 Py_END_ALLOW_THREADS
Benjamin Petersonfa268032008-06-13 19:28:21 +0000125
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000126 if (res < 0)
127 return PyErr_SetFromErrno(PyExc_OSError);
128 Py_RETURN_NONE;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000129}
130
131static PyObject *
132multiprocessing_recvfd(PyObject *self, PyObject *args)
133{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000134 int conn, fd, res;
135 char dummy_char;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000136 struct iovec dummy_iov;
Jesus Ceabbd8bec2011-09-10 04:04:09 +0200137 struct msghdr msg = {0};
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000138 struct cmsghdr *cmsg;
Jesus Ceabbd8bec2011-09-10 04:04:09 +0200139 union {
140 struct cmsghdr hdr;
141 unsigned char buf[CMSG_SPACE(sizeof(int))];
142 } cmsgbuf;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000143
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000144 if (!PyArg_ParseTuple(args, "i", &conn))
145 return NULL;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000146
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000147 dummy_iov.iov_base = &dummy_char;
148 dummy_iov.iov_len = 1;
Jesus Ceabbd8bec2011-09-10 04:04:09 +0200149
150 memset(&msg, 0, sizeof(msg));
151 msg.msg_control = &cmsgbuf.buf;
152 msg.msg_controllen = sizeof(cmsgbuf.buf);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000153 msg.msg_iov = &dummy_iov;
154 msg.msg_iovlen = 1;
Jesus Ceabbd8bec2011-09-10 04:04:09 +0200155
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000156 cmsg = CMSG_FIRSTHDR(&msg);
157 cmsg->cmsg_level = SOL_SOCKET;
158 cmsg->cmsg_type = SCM_RIGHTS;
159 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
160 msg.msg_controllen = cmsg->cmsg_len;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000161
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000162 Py_BEGIN_ALLOW_THREADS
163 res = recvmsg(conn, &msg, 0);
164 Py_END_ALLOW_THREADS
Benjamin Petersonfa268032008-06-13 19:28:21 +0000165
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000166 if (res < 0)
167 return PyErr_SetFromErrno(PyExc_OSError);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000168
Jesus Cea4507e642011-09-21 03:53:25 +0200169 if (msg.msg_controllen < CMSG_LEN(sizeof(int)) ||
170 (cmsg = CMSG_FIRSTHDR(&msg)) == NULL ||
171 cmsg->cmsg_level != SOL_SOCKET ||
172 cmsg->cmsg_type != SCM_RIGHTS ||
173 cmsg->cmsg_len < CMSG_LEN(sizeof(int))) {
174 /* If at least one control message is present, there should be
175 no room for any further data in the buffer. */
176 PyErr_SetString(PyExc_RuntimeError, "No file descriptor received");
177 return NULL;
178 }
179
Antoine Pitroubcb39d42011-08-23 19:46:22 +0200180 fd = * (int *) CMSG_DATA(cmsg);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000181 return Py_BuildValue("i", fd);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000182}
183
184#endif /* HAVE_FD_TRANSFER */
185
186#endif /* !MS_WINDOWS */
187
188
189/*
190 * All platforms
191 */
192
193static PyObject*
194multiprocessing_address_of_buffer(PyObject *self, PyObject *obj)
195{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000196 void *buffer;
197 Py_ssize_t buffer_len;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000198
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000199 if (PyObject_AsWriteBuffer(obj, &buffer, &buffer_len) < 0)
200 return NULL;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000201
Antoine Pitrou2341f9b2011-05-09 20:55:03 +0200202 return Py_BuildValue("Nn",
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000203 PyLong_FromVoidPtr(buffer), buffer_len);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000204}
205
206
207/*
208 * Function table
209 */
210
211static PyMethodDef module_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000212 {"address_of_buffer", multiprocessing_address_of_buffer, METH_O,
213 "address_of_buffer(obj) -> int\n"
214 "Return address of obj assuming obj supports buffer inteface"},
Benjamin Petersonfa268032008-06-13 19:28:21 +0000215#if HAVE_FD_TRANSFER
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000216 {"sendfd", multiprocessing_sendfd, METH_VARARGS,
217 "sendfd(sockfd, fd) -> None\n"
218 "Send file descriptor given by fd over the unix domain socket\n"
219 "whose file decriptor is sockfd"},
220 {"recvfd", multiprocessing_recvfd, METH_VARARGS,
221 "recvfd(sockfd) -> fd\n"
222 "Receive a file descriptor over a unix domain socket\n"
223 "whose file decriptor is sockfd"},
Benjamin Petersonfa268032008-06-13 19:28:21 +0000224#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000225 {NULL}
Benjamin Petersonfa268032008-06-13 19:28:21 +0000226};
227
228
229/*
230 * Initialize
231 */
232
233static struct PyModuleDef multiprocessing_module = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000234 PyModuleDef_HEAD_INIT,
235 "_multiprocessing",
236 NULL,
237 -1,
238 module_methods,
239 NULL,
240 NULL,
241 NULL,
242 NULL
Benjamin Petersonfa268032008-06-13 19:28:21 +0000243};
244
245
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000246PyMODINIT_FUNC
Benjamin Petersonfa268032008-06-13 19:28:21 +0000247PyInit__multiprocessing(void)
248{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000249 PyObject *module, *temp, *value;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000250
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000251 /* Initialize module */
252 module = PyModule_Create(&multiprocessing_module);
253 if (!module)
254 return NULL;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000255
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000256 /* Get copy of BufferTooShort */
257 temp = PyImport_ImportModule("multiprocessing");
258 if (!temp)
259 return NULL;
260 BufferTooShort = PyObject_GetAttrString(temp, "BufferTooShort");
261 Py_XDECREF(temp);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000262
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000263#if defined(MS_WINDOWS) || \
Mark Dickinsona614f042009-11-28 12:48:43 +0000264 (defined(HAVE_SEM_OPEN) && !defined(POSIX_SEMAPHORES_NOT_ENABLED))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000265 /* Add SemLock type to module */
266 if (PyType_Ready(&SemLockType) < 0)
267 return NULL;
268 Py_INCREF(&SemLockType);
Gregory P. Smith68e01352010-10-17 02:14:36 +0000269 {
270 PyObject *py_sem_value_max;
271 /* Some systems define SEM_VALUE_MAX as an unsigned value that
272 * causes it to be negative when used as an int (NetBSD). */
273 if ((int)(SEM_VALUE_MAX) < 0)
274 py_sem_value_max = PyLong_FromLong(INT_MAX);
275 else
276 py_sem_value_max = PyLong_FromLong(SEM_VALUE_MAX);
277 if (py_sem_value_max == NULL)
278 return NULL;
279 PyDict_SetItemString(SemLockType.tp_dict, "SEM_VALUE_MAX",
280 py_sem_value_max);
281 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000282 PyModule_AddObject(module, "SemLock", (PyObject*)&SemLockType);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000283#endif
284
285#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000286 /* Initialize win32 class and add to multiprocessing */
287 temp = create_win32_namespace();
288 if (!temp)
289 return NULL;
290 PyModule_AddObject(module, "win32", temp);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000291
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000292 /* Initialize the event handle used to signal Ctrl-C */
293 sigint_event = CreateEvent(NULL, TRUE, FALSE, NULL);
294 if (!sigint_event) {
295 PyErr_SetFromWindowsErr(0);
296 return NULL;
297 }
298 if (!SetConsoleCtrlHandler(ProcessingCtrlHandler, TRUE)) {
299 PyErr_SetFromWindowsErr(0);
300 return NULL;
301 }
Benjamin Petersonfa268032008-06-13 19:28:21 +0000302#endif
303
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000304 /* Add configuration macros */
305 temp = PyDict_New();
306 if (!temp)
307 return NULL;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000308
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000309#define ADD_FLAG(name) \
310 value = Py_BuildValue("i", name); \
311 if (value == NULL) { Py_DECREF(temp); return NULL; } \
312 if (PyDict_SetItemString(temp, #name, value) < 0) { \
313 Py_DECREF(temp); Py_DECREF(value); return NULL; } \
314 Py_DECREF(value)
315
Mark Dickinsona614f042009-11-28 12:48:43 +0000316#if defined(HAVE_SEM_OPEN) && !defined(POSIX_SEMAPHORES_NOT_ENABLED)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000317 ADD_FLAG(HAVE_SEM_OPEN);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000318#endif
319#ifdef HAVE_SEM_TIMEDWAIT
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000320 ADD_FLAG(HAVE_SEM_TIMEDWAIT);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000321#endif
322#ifdef HAVE_FD_TRANSFER
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000323 ADD_FLAG(HAVE_FD_TRANSFER);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000324#endif
325#ifdef HAVE_BROKEN_SEM_GETVALUE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000326 ADD_FLAG(HAVE_BROKEN_SEM_GETVALUE);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000327#endif
328#ifdef HAVE_BROKEN_SEM_UNLINK
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000329 ADD_FLAG(HAVE_BROKEN_SEM_UNLINK);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000330#endif
331
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000332 if (PyModule_AddObject(module, "flags", temp) < 0)
333 return NULL;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000334
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000335 return module;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000336}