blob: c584f2b1cf2641940a3322edfe8d3bbce801680b [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;
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. */
100
101static PyObject *
102multiprocessing_sendfd(PyObject *self, PyObject *args)
103{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000104 int conn, fd, res;
105 char dummy_char;
106 char buf[CMSG_SPACE(sizeof(int))];
107 struct msghdr msg = {0};
108 struct iovec dummy_iov;
109 struct cmsghdr *cmsg;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000110
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000111 if (!PyArg_ParseTuple(args, "ii", &conn, &fd))
112 return NULL;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000113
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000114 dummy_iov.iov_base = &dummy_char;
115 dummy_iov.iov_len = 1;
116 msg.msg_control = buf;
117 msg.msg_controllen = sizeof(buf);
118 msg.msg_iov = &dummy_iov;
119 msg.msg_iovlen = 1;
120 cmsg = CMSG_FIRSTHDR(&msg);
121 cmsg->cmsg_level = SOL_SOCKET;
122 cmsg->cmsg_type = SCM_RIGHTS;
123 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
124 msg.msg_controllen = cmsg->cmsg_len;
125 *(int*)CMSG_DATA(cmsg) = fd;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000126
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000127 Py_BEGIN_ALLOW_THREADS
128 res = sendmsg(conn, &msg, 0);
129 Py_END_ALLOW_THREADS
Benjamin Petersonfa268032008-06-13 19:28:21 +0000130
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000131 if (res < 0)
132 return PyErr_SetFromErrno(PyExc_OSError);
133 Py_RETURN_NONE;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000134}
135
136static PyObject *
137multiprocessing_recvfd(PyObject *self, PyObject *args)
138{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000139 int conn, fd, res;
140 char dummy_char;
141 char buf[CMSG_SPACE(sizeof(int))];
142 struct msghdr msg = {0};
143 struct iovec dummy_iov;
144 struct cmsghdr *cmsg;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000145
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000146 if (!PyArg_ParseTuple(args, "i", &conn))
147 return NULL;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000148
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000149 dummy_iov.iov_base = &dummy_char;
150 dummy_iov.iov_len = 1;
151 msg.msg_control = buf;
152 msg.msg_controllen = sizeof(buf);
153 msg.msg_iov = &dummy_iov;
154 msg.msg_iovlen = 1;
155 cmsg = CMSG_FIRSTHDR(&msg);
156 cmsg->cmsg_level = SOL_SOCKET;
157 cmsg->cmsg_type = SCM_RIGHTS;
158 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
159 msg.msg_controllen = cmsg->cmsg_len;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000160
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000161 Py_BEGIN_ALLOW_THREADS
162 res = recvmsg(conn, &msg, 0);
163 Py_END_ALLOW_THREADS
Benjamin Petersonfa268032008-06-13 19:28:21 +0000164
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000165 if (res < 0)
166 return PyErr_SetFromErrno(PyExc_OSError);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000167
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000168 fd = *(int*)CMSG_DATA(cmsg);
169 return Py_BuildValue("i", fd);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000170}
171
172#endif /* HAVE_FD_TRANSFER */
173
174#endif /* !MS_WINDOWS */
175
176
177/*
178 * All platforms
179 */
180
181static PyObject*
182multiprocessing_address_of_buffer(PyObject *self, PyObject *obj)
183{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000184 void *buffer;
185 Py_ssize_t buffer_len;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000186
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000187 if (PyObject_AsWriteBuffer(obj, &buffer, &buffer_len) < 0)
188 return NULL;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000189
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000190 return Py_BuildValue("N" F_PY_SSIZE_T,
191 PyLong_FromVoidPtr(buffer), buffer_len);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000192}
193
194
195/*
196 * Function table
197 */
198
199static PyMethodDef module_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000200 {"address_of_buffer", multiprocessing_address_of_buffer, METH_O,
201 "address_of_buffer(obj) -> int\n"
202 "Return address of obj assuming obj supports buffer inteface"},
Benjamin Petersonfa268032008-06-13 19:28:21 +0000203#if HAVE_FD_TRANSFER
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000204 {"sendfd", multiprocessing_sendfd, METH_VARARGS,
205 "sendfd(sockfd, fd) -> None\n"
206 "Send file descriptor given by fd over the unix domain socket\n"
207 "whose file decriptor is sockfd"},
208 {"recvfd", multiprocessing_recvfd, METH_VARARGS,
209 "recvfd(sockfd) -> fd\n"
210 "Receive a file descriptor over a unix domain socket\n"
211 "whose file decriptor is sockfd"},
Benjamin Petersonfa268032008-06-13 19:28:21 +0000212#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000213 {NULL}
Benjamin Petersonfa268032008-06-13 19:28:21 +0000214};
215
216
217/*
218 * Initialize
219 */
220
221static struct PyModuleDef multiprocessing_module = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000222 PyModuleDef_HEAD_INIT,
223 "_multiprocessing",
224 NULL,
225 -1,
226 module_methods,
227 NULL,
228 NULL,
229 NULL,
230 NULL
Benjamin Petersonfa268032008-06-13 19:28:21 +0000231};
232
233
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000234PyMODINIT_FUNC
Benjamin Petersonfa268032008-06-13 19:28:21 +0000235PyInit__multiprocessing(void)
236{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000237 PyObject *module, *temp, *value;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000238
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000239 /* Initialize module */
240 module = PyModule_Create(&multiprocessing_module);
241 if (!module)
242 return NULL;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000243
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000244 /* Get copy of objects from pickle */
245 temp = PyImport_ImportModule(PICKLE_MODULE);
246 if (!temp)
247 return NULL;
248 pickle_dumps = PyObject_GetAttrString(temp, "dumps");
249 pickle_loads = PyObject_GetAttrString(temp, "loads");
250 pickle_protocol = PyObject_GetAttrString(temp, "HIGHEST_PROTOCOL");
251 Py_XDECREF(temp);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000252
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000253 /* Get copy of BufferTooShort */
254 temp = PyImport_ImportModule("multiprocessing");
255 if (!temp)
256 return NULL;
257 BufferTooShort = PyObject_GetAttrString(temp, "BufferTooShort");
258 Py_XDECREF(temp);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000259
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000260 /* Add connection type to module */
261 if (PyType_Ready(&ConnectionType) < 0)
262 return NULL;
263 Py_INCREF(&ConnectionType);
264 PyModule_AddObject(module, "Connection", (PyObject*)&ConnectionType);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000265
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000266#if defined(MS_WINDOWS) || \
Mark Dickinsona614f042009-11-28 12:48:43 +0000267 (defined(HAVE_SEM_OPEN) && !defined(POSIX_SEMAPHORES_NOT_ENABLED))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000268 /* Add SemLock type to module */
269 if (PyType_Ready(&SemLockType) < 0)
270 return NULL;
271 Py_INCREF(&SemLockType);
272 PyDict_SetItemString(SemLockType.tp_dict, "SEM_VALUE_MAX",
273 Py_BuildValue("i", SEM_VALUE_MAX));
274 PyModule_AddObject(module, "SemLock", (PyObject*)&SemLockType);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000275#endif
276
277#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000278 /* Add PipeConnection to module */
279 if (PyType_Ready(&PipeConnectionType) < 0)
280 return NULL;
281 Py_INCREF(&PipeConnectionType);
282 PyModule_AddObject(module, "PipeConnection",
283 (PyObject*)&PipeConnectionType);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000284
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000285 /* Initialize win32 class and add to multiprocessing */
286 temp = create_win32_namespace();
287 if (!temp)
288 return NULL;
289 PyModule_AddObject(module, "win32", temp);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000290
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000291 /* Initialize the event handle used to signal Ctrl-C */
292 sigint_event = CreateEvent(NULL, TRUE, FALSE, NULL);
293 if (!sigint_event) {
294 PyErr_SetFromWindowsErr(0);
295 return NULL;
296 }
297 if (!SetConsoleCtrlHandler(ProcessingCtrlHandler, TRUE)) {
298 PyErr_SetFromWindowsErr(0);
299 return NULL;
300 }
Benjamin Petersonfa268032008-06-13 19:28:21 +0000301#endif
302
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000303 /* Add configuration macros */
304 temp = PyDict_New();
305 if (!temp)
306 return NULL;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000307
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000308#define ADD_FLAG(name) \
309 value = Py_BuildValue("i", name); \
310 if (value == NULL) { Py_DECREF(temp); return NULL; } \
311 if (PyDict_SetItemString(temp, #name, value) < 0) { \
312 Py_DECREF(temp); Py_DECREF(value); return NULL; } \
313 Py_DECREF(value)
314
Mark Dickinsona614f042009-11-28 12:48:43 +0000315#if defined(HAVE_SEM_OPEN) && !defined(POSIX_SEMAPHORES_NOT_ENABLED)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000316 ADD_FLAG(HAVE_SEM_OPEN);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000317#endif
318#ifdef HAVE_SEM_TIMEDWAIT
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000319 ADD_FLAG(HAVE_SEM_TIMEDWAIT);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000320#endif
321#ifdef HAVE_FD_TRANSFER
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000322 ADD_FLAG(HAVE_FD_TRANSFER);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000323#endif
324#ifdef HAVE_BROKEN_SEM_GETVALUE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000325 ADD_FLAG(HAVE_BROKEN_SEM_GETVALUE);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000326#endif
327#ifdef HAVE_BROKEN_SEM_UNLINK
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000328 ADD_FLAG(HAVE_BROKEN_SEM_UNLINK);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000329#endif
330
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000331 if (PyModule_AddObject(module, "flags", temp) < 0)
332 return NULL;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000333
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000334 return module;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000335}