blob: e5939509750ff6ec61f877504c8380111e686e7b [file] [log] [blame]
Benjamin Petersondfd79492008-06-13 19:13:39 +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
11PyObject *create_win32_namespace(void);
12
13PyObject *pickle_dumps, *pickle_loads, *pickle_protocol;
14PyObject *ProcessError, *BufferTooShort;
15
16/*
17 * Function which raises exceptions based on error codes
18 */
19
20PyObject *
21mp_SetError(PyObject *Type, int num)
22{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +000023 switch (num) {
Benjamin Petersondfd79492008-06-13 19:13:39 +000024#ifdef MS_WINDOWS
Antoine Pitrouc7c96a92010-05-09 15:15:40 +000025 case MP_STANDARD_ERROR:
26 if (Type == NULL)
27 Type = PyExc_WindowsError;
28 PyErr_SetExcFromWindowsErr(Type, 0);
29 break;
30 case MP_SOCKET_ERROR:
31 if (Type == NULL)
32 Type = PyExc_WindowsError;
33 PyErr_SetExcFromWindowsErr(Type, WSAGetLastError());
34 break;
Benjamin Petersondfd79492008-06-13 19:13:39 +000035#else /* !MS_WINDOWS */
Antoine Pitrouc7c96a92010-05-09 15:15:40 +000036 case MP_STANDARD_ERROR:
37 case MP_SOCKET_ERROR:
38 if (Type == NULL)
39 Type = PyExc_OSError;
40 PyErr_SetFromErrno(Type);
41 break;
Benjamin Petersondfd79492008-06-13 19:13:39 +000042#endif /* !MS_WINDOWS */
Antoine Pitrouc7c96a92010-05-09 15:15:40 +000043 case MP_MEMORY_ERROR:
44 PyErr_NoMemory();
45 break;
46 case MP_END_OF_FILE:
47 PyErr_SetNone(PyExc_EOFError);
48 break;
49 case MP_EARLY_END_OF_FILE:
50 PyErr_SetString(PyExc_IOError,
51 "got end of file during message");
52 break;
53 case MP_BAD_MESSAGE_LENGTH:
54 PyErr_SetString(PyExc_IOError, "bad message length");
55 break;
56 case MP_EXCEPTION_HAS_BEEN_SET:
57 break;
58 default:
59 PyErr_Format(PyExc_RuntimeError,
60 "unkown error number %d", num);
61 }
62 return NULL;
Benjamin Petersondfd79492008-06-13 19:13:39 +000063}
64
65
66/*
67 * Windows only
68 */
69
70#ifdef MS_WINDOWS
71
72/* On Windows we set an event to signal Ctrl-C; compare with timemodule.c */
73
74HANDLE sigint_event = NULL;
75
76static BOOL WINAPI
77ProcessingCtrlHandler(DWORD dwCtrlType)
78{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +000079 SetEvent(sigint_event);
80 return FALSE;
Benjamin Petersondfd79492008-06-13 19:13:39 +000081}
82
83/*
84 * Unix only
85 */
86
87#else /* !MS_WINDOWS */
88
89#if HAVE_FD_TRANSFER
90
91/* Functions for transferring file descriptors between processes.
92 Reimplements some of the functionality of the fdcred
93 module at http://www.mca-ltd.com/resources/fdcred_1.tgz. */
94
95static PyObject *
96multiprocessing_sendfd(PyObject *self, PyObject *args)
97{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +000098 int conn, fd, res;
99 char dummy_char;
100 char buf[CMSG_SPACE(sizeof(int))];
101 struct msghdr msg = {0};
102 struct iovec dummy_iov;
103 struct cmsghdr *cmsg;
Benjamin Petersondfd79492008-06-13 19:13:39 +0000104
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000105 if (!PyArg_ParseTuple(args, "ii", &conn, &fd))
106 return NULL;
Benjamin Petersondfd79492008-06-13 19:13:39 +0000107
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000108 dummy_iov.iov_base = &dummy_char;
109 dummy_iov.iov_len = 1;
110 msg.msg_control = buf;
111 msg.msg_controllen = sizeof(buf);
112 msg.msg_iov = &dummy_iov;
113 msg.msg_iovlen = 1;
114 cmsg = CMSG_FIRSTHDR(&msg);
115 cmsg->cmsg_level = SOL_SOCKET;
116 cmsg->cmsg_type = SCM_RIGHTS;
117 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
118 msg.msg_controllen = cmsg->cmsg_len;
119 *(int*)CMSG_DATA(cmsg) = fd;
Benjamin Petersondfd79492008-06-13 19:13:39 +0000120
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000121 Py_BEGIN_ALLOW_THREADS
122 res = sendmsg(conn, &msg, 0);
123 Py_END_ALLOW_THREADS
Benjamin Petersondfd79492008-06-13 19:13:39 +0000124
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000125 if (res < 0)
126 return PyErr_SetFromErrno(PyExc_OSError);
127 Py_RETURN_NONE;
Benjamin Petersondfd79492008-06-13 19:13:39 +0000128}
129
130static PyObject *
131multiprocessing_recvfd(PyObject *self, PyObject *args)
132{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000133 int conn, fd, res;
134 char dummy_char;
135 char buf[CMSG_SPACE(sizeof(int))];
136 struct msghdr msg = {0};
137 struct iovec dummy_iov;
138 struct cmsghdr *cmsg;
Benjamin Petersondfd79492008-06-13 19:13:39 +0000139
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000140 if (!PyArg_ParseTuple(args, "i", &conn))
141 return NULL;
Benjamin Petersondfd79492008-06-13 19:13:39 +0000142
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000143 dummy_iov.iov_base = &dummy_char;
144 dummy_iov.iov_len = 1;
145 msg.msg_control = buf;
146 msg.msg_controllen = sizeof(buf);
147 msg.msg_iov = &dummy_iov;
148 msg.msg_iovlen = 1;
149 cmsg = CMSG_FIRSTHDR(&msg);
150 cmsg->cmsg_level = SOL_SOCKET;
151 cmsg->cmsg_type = SCM_RIGHTS;
152 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
153 msg.msg_controllen = cmsg->cmsg_len;
Benjamin Petersondfd79492008-06-13 19:13:39 +0000154
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000155 Py_BEGIN_ALLOW_THREADS
156 res = recvmsg(conn, &msg, 0);
157 Py_END_ALLOW_THREADS
Benjamin Petersondfd79492008-06-13 19:13:39 +0000158
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000159 if (res < 0)
160 return PyErr_SetFromErrno(PyExc_OSError);
Benjamin Petersondfd79492008-06-13 19:13:39 +0000161
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000162 fd = *(int*)CMSG_DATA(cmsg);
163 return Py_BuildValue("i", fd);
Benjamin Petersondfd79492008-06-13 19:13:39 +0000164}
165
166#endif /* HAVE_FD_TRANSFER */
167
168#endif /* !MS_WINDOWS */
169
170
171/*
172 * All platforms
173 */
174
175static PyObject*
176multiprocessing_address_of_buffer(PyObject *self, PyObject *obj)
177{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000178 void *buffer;
179 Py_ssize_t buffer_len;
Benjamin Petersondfd79492008-06-13 19:13:39 +0000180
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000181 if (PyObject_AsWriteBuffer(obj, &buffer, &buffer_len) < 0)
182 return NULL;
Benjamin Petersondfd79492008-06-13 19:13:39 +0000183
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000184 return Py_BuildValue("N" F_PY_SSIZE_T,
185 PyLong_FromVoidPtr(buffer), buffer_len);
Benjamin Petersondfd79492008-06-13 19:13:39 +0000186}
187
188
189/*
190 * Function table
191 */
192
193static PyMethodDef module_methods[] = {
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000194 {"address_of_buffer", multiprocessing_address_of_buffer, METH_O,
195 "address_of_buffer(obj) -> int\n"
196 "Return address of obj assuming obj supports buffer inteface"},
Benjamin Petersondfd79492008-06-13 19:13:39 +0000197#if HAVE_FD_TRANSFER
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000198 {"sendfd", multiprocessing_sendfd, METH_VARARGS,
199 "sendfd(sockfd, fd) -> None\n"
200 "Send file descriptor given by fd over the unix domain socket\n"
201 "whose file decriptor is sockfd"},
202 {"recvfd", multiprocessing_recvfd, METH_VARARGS,
203 "recvfd(sockfd) -> fd\n"
204 "Receive a file descriptor over a unix domain socket\n"
205 "whose file decriptor is sockfd"},
Benjamin Petersondfd79492008-06-13 19:13:39 +0000206#endif
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000207 {NULL}
Benjamin Petersondfd79492008-06-13 19:13:39 +0000208};
209
210
211/*
212 * Initialize
213 */
214
215PyMODINIT_FUNC
216init_multiprocessing(void)
217{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000218 PyObject *module, *temp, *value;
Benjamin Petersondfd79492008-06-13 19:13:39 +0000219
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000220 /* Initialize module */
221 module = Py_InitModule("_multiprocessing", module_methods);
222 if (!module)
223 return;
Benjamin Petersondfd79492008-06-13 19:13:39 +0000224
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000225 /* Get copy of objects from pickle */
226 temp = PyImport_ImportModule(PICKLE_MODULE);
227 if (!temp)
228 return;
229 pickle_dumps = PyObject_GetAttrString(temp, "dumps");
230 pickle_loads = PyObject_GetAttrString(temp, "loads");
231 pickle_protocol = PyObject_GetAttrString(temp, "HIGHEST_PROTOCOL");
232 Py_XDECREF(temp);
Benjamin Petersondfd79492008-06-13 19:13:39 +0000233
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000234 /* Get copy of BufferTooShort */
235 temp = PyImport_ImportModule("multiprocessing");
236 if (!temp)
237 return;
238 BufferTooShort = PyObject_GetAttrString(temp, "BufferTooShort");
239 Py_XDECREF(temp);
Benjamin Petersondfd79492008-06-13 19:13:39 +0000240
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000241 /* Add connection type to module */
242 if (PyType_Ready(&ConnectionType) < 0)
243 return;
244 Py_INCREF(&ConnectionType);
245 PyModule_AddObject(module, "Connection", (PyObject*)&ConnectionType);
Benjamin Petersondfd79492008-06-13 19:13:39 +0000246
247#if defined(MS_WINDOWS) || HAVE_SEM_OPEN
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000248 /* Add SemLock type to module */
249 if (PyType_Ready(&SemLockType) < 0)
250 return;
251 Py_INCREF(&SemLockType);
252 PyDict_SetItemString(SemLockType.tp_dict, "SEM_VALUE_MAX",
253 Py_BuildValue("i", SEM_VALUE_MAX));
254 PyModule_AddObject(module, "SemLock", (PyObject*)&SemLockType);
Benjamin Petersondfd79492008-06-13 19:13:39 +0000255#endif
256
257#ifdef MS_WINDOWS
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000258 /* Add PipeConnection to module */
259 if (PyType_Ready(&PipeConnectionType) < 0)
260 return;
261 Py_INCREF(&PipeConnectionType);
262 PyModule_AddObject(module, "PipeConnection",
263 (PyObject*)&PipeConnectionType);
Benjamin Petersondfd79492008-06-13 19:13:39 +0000264
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000265 /* Initialize win32 class and add to multiprocessing */
266 temp = create_win32_namespace();
267 if (!temp)
268 return;
269 PyModule_AddObject(module, "win32", temp);
Benjamin Petersondfd79492008-06-13 19:13:39 +0000270
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000271 /* Initialize the event handle used to signal Ctrl-C */
272 sigint_event = CreateEvent(NULL, TRUE, FALSE, NULL);
273 if (!sigint_event) {
274 PyErr_SetFromWindowsErr(0);
275 return;
276 }
277 if (!SetConsoleCtrlHandler(ProcessingCtrlHandler, TRUE)) {
278 PyErr_SetFromWindowsErr(0);
279 return;
280 }
Benjamin Petersondfd79492008-06-13 19:13:39 +0000281#endif
282
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000283 /* Add configuration macros */
284 temp = PyDict_New();
285 if (!temp)
286 return;
287#define ADD_FLAG(name) \
288 value = Py_BuildValue("i", name); \
289 if (value == NULL) { Py_DECREF(temp); return; } \
290 if (PyDict_SetItemString(temp, #name, value) < 0) { \
291 Py_DECREF(temp); Py_DECREF(value); return; } \
292 Py_DECREF(value)
293
Benjamin Petersondfd79492008-06-13 19:13:39 +0000294#ifdef HAVE_SEM_OPEN
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000295 ADD_FLAG(HAVE_SEM_OPEN);
Benjamin Petersondfd79492008-06-13 19:13:39 +0000296#endif
297#ifdef HAVE_SEM_TIMEDWAIT
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000298 ADD_FLAG(HAVE_SEM_TIMEDWAIT);
Benjamin Petersondfd79492008-06-13 19:13:39 +0000299#endif
300#ifdef HAVE_FD_TRANSFER
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000301 ADD_FLAG(HAVE_FD_TRANSFER);
Benjamin Petersondfd79492008-06-13 19:13:39 +0000302#endif
303#ifdef HAVE_BROKEN_SEM_GETVALUE
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000304 ADD_FLAG(HAVE_BROKEN_SEM_GETVALUE);
Benjamin Petersondfd79492008-06-13 19:13:39 +0000305#endif
306#ifdef HAVE_BROKEN_SEM_UNLINK
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000307 ADD_FLAG(HAVE_BROKEN_SEM_UNLINK);
Benjamin Petersondfd79492008-06-13 19:13:39 +0000308#endif
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000309 if (PyModule_AddObject(module, "flags", temp) < 0)
310 return;
Benjamin Petersondfd79492008-06-13 19:13:39 +0000311}