blob: f6c2259815802e7d8a0bee52dbdbbbb2fe92797a [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
Antoine Pitroubcb39d42011-08-23 19:46:22 +0200169 fd = * (int *) CMSG_DATA(cmsg);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000170 return Py_BuildValue("i", fd);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000171}
172
173#endif /* HAVE_FD_TRANSFER */
174
175#endif /* !MS_WINDOWS */
176
177
178/*
179 * All platforms
180 */
181
182static PyObject*
183multiprocessing_address_of_buffer(PyObject *self, PyObject *obj)
184{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000185 void *buffer;
186 Py_ssize_t buffer_len;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000187
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000188 if (PyObject_AsWriteBuffer(obj, &buffer, &buffer_len) < 0)
189 return NULL;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000190
Antoine Pitrou2341f9b2011-05-09 20:55:03 +0200191 return Py_BuildValue("Nn",
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000192 PyLong_FromVoidPtr(buffer), buffer_len);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000193}
194
195
196/*
197 * Function table
198 */
199
200static PyMethodDef module_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000201 {"address_of_buffer", multiprocessing_address_of_buffer, METH_O,
202 "address_of_buffer(obj) -> int\n"
203 "Return address of obj assuming obj supports buffer inteface"},
Benjamin Petersonfa268032008-06-13 19:28:21 +0000204#if HAVE_FD_TRANSFER
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000205 {"sendfd", multiprocessing_sendfd, METH_VARARGS,
206 "sendfd(sockfd, fd) -> None\n"
207 "Send file descriptor given by fd over the unix domain socket\n"
208 "whose file decriptor is sockfd"},
209 {"recvfd", multiprocessing_recvfd, METH_VARARGS,
210 "recvfd(sockfd) -> fd\n"
211 "Receive a file descriptor over a unix domain socket\n"
212 "whose file decriptor is sockfd"},
Benjamin Petersonfa268032008-06-13 19:28:21 +0000213#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000214 {NULL}
Benjamin Petersonfa268032008-06-13 19:28:21 +0000215};
216
217
218/*
219 * Initialize
220 */
221
222static struct PyModuleDef multiprocessing_module = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000223 PyModuleDef_HEAD_INIT,
224 "_multiprocessing",
225 NULL,
226 -1,
227 module_methods,
228 NULL,
229 NULL,
230 NULL,
231 NULL
Benjamin Petersonfa268032008-06-13 19:28:21 +0000232};
233
234
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000235PyMODINIT_FUNC
Benjamin Petersonfa268032008-06-13 19:28:21 +0000236PyInit__multiprocessing(void)
237{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000238 PyObject *module, *temp, *value;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000239
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000240 /* Initialize module */
241 module = PyModule_Create(&multiprocessing_module);
242 if (!module)
243 return NULL;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000244
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000245 /* Get copy of BufferTooShort */
246 temp = PyImport_ImportModule("multiprocessing");
247 if (!temp)
248 return NULL;
249 BufferTooShort = PyObject_GetAttrString(temp, "BufferTooShort");
250 Py_XDECREF(temp);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000251
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000252#if defined(MS_WINDOWS) || \
Mark Dickinsona614f042009-11-28 12:48:43 +0000253 (defined(HAVE_SEM_OPEN) && !defined(POSIX_SEMAPHORES_NOT_ENABLED))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000254 /* Add SemLock type to module */
255 if (PyType_Ready(&SemLockType) < 0)
256 return NULL;
257 Py_INCREF(&SemLockType);
Gregory P. Smith68e01352010-10-17 02:14:36 +0000258 {
259 PyObject *py_sem_value_max;
260 /* Some systems define SEM_VALUE_MAX as an unsigned value that
261 * causes it to be negative when used as an int (NetBSD). */
262 if ((int)(SEM_VALUE_MAX) < 0)
263 py_sem_value_max = PyLong_FromLong(INT_MAX);
264 else
265 py_sem_value_max = PyLong_FromLong(SEM_VALUE_MAX);
266 if (py_sem_value_max == NULL)
267 return NULL;
268 PyDict_SetItemString(SemLockType.tp_dict, "SEM_VALUE_MAX",
269 py_sem_value_max);
270 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000271 PyModule_AddObject(module, "SemLock", (PyObject*)&SemLockType);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000272#endif
273
274#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000275 /* Initialize win32 class and add to multiprocessing */
276 temp = create_win32_namespace();
277 if (!temp)
278 return NULL;
279 PyModule_AddObject(module, "win32", temp);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000280
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000281 /* Initialize the event handle used to signal Ctrl-C */
282 sigint_event = CreateEvent(NULL, TRUE, FALSE, NULL);
283 if (!sigint_event) {
284 PyErr_SetFromWindowsErr(0);
285 return NULL;
286 }
287 if (!SetConsoleCtrlHandler(ProcessingCtrlHandler, TRUE)) {
288 PyErr_SetFromWindowsErr(0);
289 return NULL;
290 }
Benjamin Petersonfa268032008-06-13 19:28:21 +0000291#endif
292
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000293 /* Add configuration macros */
294 temp = PyDict_New();
295 if (!temp)
296 return NULL;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000297
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000298#define ADD_FLAG(name) \
299 value = Py_BuildValue("i", name); \
300 if (value == NULL) { Py_DECREF(temp); return NULL; } \
301 if (PyDict_SetItemString(temp, #name, value) < 0) { \
302 Py_DECREF(temp); Py_DECREF(value); return NULL; } \
303 Py_DECREF(value)
304
Mark Dickinsona614f042009-11-28 12:48:43 +0000305#if defined(HAVE_SEM_OPEN) && !defined(POSIX_SEMAPHORES_NOT_ENABLED)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000306 ADD_FLAG(HAVE_SEM_OPEN);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000307#endif
308#ifdef HAVE_SEM_TIMEDWAIT
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000309 ADD_FLAG(HAVE_SEM_TIMEDWAIT);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000310#endif
311#ifdef HAVE_FD_TRANSFER
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000312 ADD_FLAG(HAVE_FD_TRANSFER);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000313#endif
314#ifdef HAVE_BROKEN_SEM_GETVALUE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000315 ADD_FLAG(HAVE_BROKEN_SEM_GETVALUE);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000316#endif
317#ifdef HAVE_BROKEN_SEM_UNLINK
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000318 ADD_FLAG(HAVE_BROKEN_SEM_UNLINK);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000319#endif
320
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000321 if (PyModule_AddObject(module, "flags", temp) < 0)
322 return NULL;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000323
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000324 return module;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000325}