blob: 5685517fc06c10940369a63cf41a8abe5591369b [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
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;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000052 case MP_EXCEPTION_HAS_BEEN_SET:
53 break;
54 default:
55 PyErr_Format(PyExc_RuntimeError,
56 "unkown error number %d", num);
57 }
58 return NULL;
Benjamin Petersonfa268032008-06-13 19:28:21 +000059}
60
61
62/*
63 * Windows only
64 */
65
66#ifdef MS_WINDOWS
67
68/* On Windows we set an event to signal Ctrl-C; compare with timemodule.c */
69
70HANDLE sigint_event = NULL;
71
72static BOOL WINAPI
73ProcessingCtrlHandler(DWORD dwCtrlType)
74{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000075 SetEvent(sigint_event);
76 return FALSE;
Benjamin Petersonfa268032008-06-13 19:28:21 +000077}
78
79/*
80 * Unix only
81 */
82
83#else /* !MS_WINDOWS */
84
85#if HAVE_FD_TRANSFER
86
87/* Functions for transferring file descriptors between processes.
88 Reimplements some of the functionality of the fdcred
89 module at http://www.mca-ltd.com/resources/fdcred_1.tgz. */
90
91static PyObject *
92multiprocessing_sendfd(PyObject *self, PyObject *args)
93{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000094 int conn, fd, res;
95 char dummy_char;
96 char buf[CMSG_SPACE(sizeof(int))];
97 struct msghdr msg = {0};
98 struct iovec dummy_iov;
99 struct cmsghdr *cmsg;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000100
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000101 if (!PyArg_ParseTuple(args, "ii", &conn, &fd))
102 return NULL;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000103
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000104 dummy_iov.iov_base = &dummy_char;
105 dummy_iov.iov_len = 1;
106 msg.msg_control = buf;
107 msg.msg_controllen = sizeof(buf);
108 msg.msg_iov = &dummy_iov;
109 msg.msg_iovlen = 1;
110 cmsg = CMSG_FIRSTHDR(&msg);
111 cmsg->cmsg_level = SOL_SOCKET;
112 cmsg->cmsg_type = SCM_RIGHTS;
113 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
114 msg.msg_controllen = cmsg->cmsg_len;
Benjamin Peterson223f0912010-10-17 21:12:18 +0000115 *CMSG_DATA(cmsg) = fd;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000116
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000117 Py_BEGIN_ALLOW_THREADS
118 res = sendmsg(conn, &msg, 0);
119 Py_END_ALLOW_THREADS
Benjamin Petersonfa268032008-06-13 19:28:21 +0000120
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000121 if (res < 0)
122 return PyErr_SetFromErrno(PyExc_OSError);
123 Py_RETURN_NONE;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000124}
125
126static PyObject *
127multiprocessing_recvfd(PyObject *self, PyObject *args)
128{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000129 int conn, fd, res;
130 char dummy_char;
131 char buf[CMSG_SPACE(sizeof(int))];
132 struct msghdr msg = {0};
133 struct iovec dummy_iov;
134 struct cmsghdr *cmsg;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000135
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000136 if (!PyArg_ParseTuple(args, "i", &conn))
137 return NULL;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000138
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000139 dummy_iov.iov_base = &dummy_char;
140 dummy_iov.iov_len = 1;
141 msg.msg_control = buf;
142 msg.msg_controllen = sizeof(buf);
143 msg.msg_iov = &dummy_iov;
144 msg.msg_iovlen = 1;
145 cmsg = CMSG_FIRSTHDR(&msg);
146 cmsg->cmsg_level = SOL_SOCKET;
147 cmsg->cmsg_type = SCM_RIGHTS;
148 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
149 msg.msg_controllen = cmsg->cmsg_len;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000150
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000151 Py_BEGIN_ALLOW_THREADS
152 res = recvmsg(conn, &msg, 0);
153 Py_END_ALLOW_THREADS
Benjamin Petersonfa268032008-06-13 19:28:21 +0000154
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000155 if (res < 0)
156 return PyErr_SetFromErrno(PyExc_OSError);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000157
Benjamin Peterson223f0912010-10-17 21:12:18 +0000158 fd = *CMSG_DATA(cmsg);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000159 return Py_BuildValue("i", fd);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000160}
161
162#endif /* HAVE_FD_TRANSFER */
163
164#endif /* !MS_WINDOWS */
165
166
167/*
168 * All platforms
169 */
170
171static PyObject*
172multiprocessing_address_of_buffer(PyObject *self, PyObject *obj)
173{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000174 void *buffer;
175 Py_ssize_t buffer_len;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000176
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000177 if (PyObject_AsWriteBuffer(obj, &buffer, &buffer_len) < 0)
178 return NULL;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000179
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000180 return Py_BuildValue("N" F_PY_SSIZE_T,
181 PyLong_FromVoidPtr(buffer), buffer_len);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000182}
183
184
185/*
186 * Function table
187 */
188
189static PyMethodDef module_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000190 {"address_of_buffer", multiprocessing_address_of_buffer, METH_O,
191 "address_of_buffer(obj) -> int\n"
192 "Return address of obj assuming obj supports buffer inteface"},
Benjamin Petersonfa268032008-06-13 19:28:21 +0000193#if HAVE_FD_TRANSFER
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000194 {"sendfd", multiprocessing_sendfd, METH_VARARGS,
195 "sendfd(sockfd, fd) -> None\n"
196 "Send file descriptor given by fd over the unix domain socket\n"
197 "whose file decriptor is sockfd"},
198 {"recvfd", multiprocessing_recvfd, METH_VARARGS,
199 "recvfd(sockfd) -> fd\n"
200 "Receive a file descriptor over a unix domain socket\n"
201 "whose file decriptor is sockfd"},
Benjamin Petersonfa268032008-06-13 19:28:21 +0000202#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000203 {NULL}
Benjamin Petersonfa268032008-06-13 19:28:21 +0000204};
205
206
207/*
208 * Initialize
209 */
210
211static struct PyModuleDef multiprocessing_module = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000212 PyModuleDef_HEAD_INIT,
213 "_multiprocessing",
214 NULL,
215 -1,
216 module_methods,
217 NULL,
218 NULL,
219 NULL,
220 NULL
Benjamin Petersonfa268032008-06-13 19:28:21 +0000221};
222
223
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000224PyMODINIT_FUNC
Benjamin Petersonfa268032008-06-13 19:28:21 +0000225PyInit__multiprocessing(void)
226{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000227 PyObject *module, *temp, *value;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000228
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000229 /* Initialize module */
230 module = PyModule_Create(&multiprocessing_module);
231 if (!module)
232 return NULL;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000233
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000234 /* Get copy of objects from pickle */
235 temp = PyImport_ImportModule(PICKLE_MODULE);
236 if (!temp)
237 return NULL;
238 pickle_dumps = PyObject_GetAttrString(temp, "dumps");
239 pickle_loads = PyObject_GetAttrString(temp, "loads");
240 pickle_protocol = PyObject_GetAttrString(temp, "HIGHEST_PROTOCOL");
241 Py_XDECREF(temp);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000242
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000243 /* Get copy of BufferTooShort */
244 temp = PyImport_ImportModule("multiprocessing");
245 if (!temp)
246 return NULL;
247 BufferTooShort = PyObject_GetAttrString(temp, "BufferTooShort");
248 Py_XDECREF(temp);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000249
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000250#if defined(MS_WINDOWS) || \
Mark Dickinsona614f042009-11-28 12:48:43 +0000251 (defined(HAVE_SEM_OPEN) && !defined(POSIX_SEMAPHORES_NOT_ENABLED))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000252 /* Add SemLock type to module */
253 if (PyType_Ready(&SemLockType) < 0)
254 return NULL;
255 Py_INCREF(&SemLockType);
Gregory P. Smith68e01352010-10-17 02:14:36 +0000256 {
257 PyObject *py_sem_value_max;
258 /* Some systems define SEM_VALUE_MAX as an unsigned value that
259 * causes it to be negative when used as an int (NetBSD). */
260 if ((int)(SEM_VALUE_MAX) < 0)
261 py_sem_value_max = PyLong_FromLong(INT_MAX);
262 else
263 py_sem_value_max = PyLong_FromLong(SEM_VALUE_MAX);
264 if (py_sem_value_max == NULL)
265 return NULL;
266 PyDict_SetItemString(SemLockType.tp_dict, "SEM_VALUE_MAX",
267 py_sem_value_max);
268 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000269 PyModule_AddObject(module, "SemLock", (PyObject*)&SemLockType);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000270#endif
271
272#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000273 /* Initialize win32 class and add to multiprocessing */
274 temp = create_win32_namespace();
275 if (!temp)
276 return NULL;
277 PyModule_AddObject(module, "win32", temp);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000278
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000279 /* Initialize the event handle used to signal Ctrl-C */
280 sigint_event = CreateEvent(NULL, TRUE, FALSE, NULL);
281 if (!sigint_event) {
282 PyErr_SetFromWindowsErr(0);
283 return NULL;
284 }
285 if (!SetConsoleCtrlHandler(ProcessingCtrlHandler, TRUE)) {
286 PyErr_SetFromWindowsErr(0);
287 return NULL;
288 }
Benjamin Petersonfa268032008-06-13 19:28:21 +0000289#endif
290
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000291 /* Add configuration macros */
292 temp = PyDict_New();
293 if (!temp)
294 return NULL;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000295
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000296#define ADD_FLAG(name) \
297 value = Py_BuildValue("i", name); \
298 if (value == NULL) { Py_DECREF(temp); return NULL; } \
299 if (PyDict_SetItemString(temp, #name, value) < 0) { \
300 Py_DECREF(temp); Py_DECREF(value); return NULL; } \
301 Py_DECREF(value)
302
Mark Dickinsona614f042009-11-28 12:48:43 +0000303#if defined(HAVE_SEM_OPEN) && !defined(POSIX_SEMAPHORES_NOT_ENABLED)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000304 ADD_FLAG(HAVE_SEM_OPEN);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000305#endif
306#ifdef HAVE_SEM_TIMEDWAIT
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000307 ADD_FLAG(HAVE_SEM_TIMEDWAIT);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000308#endif
309#ifdef HAVE_FD_TRANSFER
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000310 ADD_FLAG(HAVE_FD_TRANSFER);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000311#endif
312#ifdef HAVE_BROKEN_SEM_GETVALUE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000313 ADD_FLAG(HAVE_BROKEN_SEM_GETVALUE);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000314#endif
315#ifdef HAVE_BROKEN_SEM_UNLINK
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000316 ADD_FLAG(HAVE_BROKEN_SEM_UNLINK);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000317#endif
318
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000319 if (PyModule_AddObject(module, "flags", temp) < 0)
320 return NULL;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000321
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000322 return module;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000323}