blob: 5d1cf5661aa5b5b8d64247adc484a62e502ca134 [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. */
89
90static PyObject *
91multiprocessing_sendfd(PyObject *self, PyObject *args)
92{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000093 int conn, fd, res;
94 char dummy_char;
95 char buf[CMSG_SPACE(sizeof(int))];
96 struct msghdr msg = {0};
97 struct iovec dummy_iov;
98 struct cmsghdr *cmsg;
Benjamin Petersonfa268032008-06-13 19:28:21 +000099
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000100 if (!PyArg_ParseTuple(args, "ii", &conn, &fd))
101 return NULL;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000102
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000103 dummy_iov.iov_base = &dummy_char;
104 dummy_iov.iov_len = 1;
105 msg.msg_control = buf;
106 msg.msg_controllen = sizeof(buf);
107 msg.msg_iov = &dummy_iov;
108 msg.msg_iovlen = 1;
109 cmsg = CMSG_FIRSTHDR(&msg);
110 cmsg->cmsg_level = SOL_SOCKET;
111 cmsg->cmsg_type = SCM_RIGHTS;
112 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
113 msg.msg_controllen = cmsg->cmsg_len;
Benjamin Peterson223f0912010-10-17 21:12:18 +0000114 *CMSG_DATA(cmsg) = fd;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000115
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000116 Py_BEGIN_ALLOW_THREADS
117 res = sendmsg(conn, &msg, 0);
118 Py_END_ALLOW_THREADS
Benjamin Petersonfa268032008-06-13 19:28:21 +0000119
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000120 if (res < 0)
121 return PyErr_SetFromErrno(PyExc_OSError);
122 Py_RETURN_NONE;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000123}
124
125static PyObject *
126multiprocessing_recvfd(PyObject *self, PyObject *args)
127{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000128 int conn, fd, res;
129 char dummy_char;
130 char buf[CMSG_SPACE(sizeof(int))];
131 struct msghdr msg = {0};
132 struct iovec dummy_iov;
133 struct cmsghdr *cmsg;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000134
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000135 if (!PyArg_ParseTuple(args, "i", &conn))
136 return NULL;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000137
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000138 dummy_iov.iov_base = &dummy_char;
139 dummy_iov.iov_len = 1;
140 msg.msg_control = buf;
141 msg.msg_controllen = sizeof(buf);
142 msg.msg_iov = &dummy_iov;
143 msg.msg_iovlen = 1;
144 cmsg = CMSG_FIRSTHDR(&msg);
145 cmsg->cmsg_level = SOL_SOCKET;
146 cmsg->cmsg_type = SCM_RIGHTS;
147 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
148 msg.msg_controllen = cmsg->cmsg_len;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000149
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000150 Py_BEGIN_ALLOW_THREADS
151 res = recvmsg(conn, &msg, 0);
152 Py_END_ALLOW_THREADS
Benjamin Petersonfa268032008-06-13 19:28:21 +0000153
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000154 if (res < 0)
155 return PyErr_SetFromErrno(PyExc_OSError);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000156
Benjamin Peterson223f0912010-10-17 21:12:18 +0000157 fd = *CMSG_DATA(cmsg);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000158 return Py_BuildValue("i", fd);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000159}
160
161#endif /* HAVE_FD_TRANSFER */
162
163#endif /* !MS_WINDOWS */
164
165
166/*
167 * All platforms
168 */
169
170static PyObject*
171multiprocessing_address_of_buffer(PyObject *self, PyObject *obj)
172{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000173 void *buffer;
174 Py_ssize_t buffer_len;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000175
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000176 if (PyObject_AsWriteBuffer(obj, &buffer, &buffer_len) < 0)
177 return NULL;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000178
Antoine Pitrou2341f9b2011-05-09 20:55:03 +0200179 return Py_BuildValue("Nn",
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000180 PyLong_FromVoidPtr(buffer), buffer_len);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000181}
182
183
184/*
185 * Function table
186 */
187
188static PyMethodDef module_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000189 {"address_of_buffer", multiprocessing_address_of_buffer, METH_O,
190 "address_of_buffer(obj) -> int\n"
191 "Return address of obj assuming obj supports buffer inteface"},
Benjamin Petersonfa268032008-06-13 19:28:21 +0000192#if HAVE_FD_TRANSFER
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000193 {"sendfd", multiprocessing_sendfd, METH_VARARGS,
194 "sendfd(sockfd, fd) -> None\n"
195 "Send file descriptor given by fd over the unix domain socket\n"
196 "whose file decriptor is sockfd"},
197 {"recvfd", multiprocessing_recvfd, METH_VARARGS,
198 "recvfd(sockfd) -> fd\n"
199 "Receive a file descriptor over a unix domain socket\n"
200 "whose file decriptor is sockfd"},
Benjamin Petersonfa268032008-06-13 19:28:21 +0000201#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000202 {NULL}
Benjamin Petersonfa268032008-06-13 19:28:21 +0000203};
204
205
206/*
207 * Initialize
208 */
209
210static struct PyModuleDef multiprocessing_module = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000211 PyModuleDef_HEAD_INIT,
212 "_multiprocessing",
213 NULL,
214 -1,
215 module_methods,
216 NULL,
217 NULL,
218 NULL,
219 NULL
Benjamin Petersonfa268032008-06-13 19:28:21 +0000220};
221
222
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000223PyMODINIT_FUNC
Benjamin Petersonfa268032008-06-13 19:28:21 +0000224PyInit__multiprocessing(void)
225{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000226 PyObject *module, *temp, *value;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000227
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000228 /* Initialize module */
229 module = PyModule_Create(&multiprocessing_module);
230 if (!module)
231 return NULL;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000232
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000233 /* Get copy of BufferTooShort */
234 temp = PyImport_ImportModule("multiprocessing");
235 if (!temp)
236 return NULL;
237 BufferTooShort = PyObject_GetAttrString(temp, "BufferTooShort");
238 Py_XDECREF(temp);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000239
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000240#if defined(MS_WINDOWS) || \
Mark Dickinsona614f042009-11-28 12:48:43 +0000241 (defined(HAVE_SEM_OPEN) && !defined(POSIX_SEMAPHORES_NOT_ENABLED))
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000242 /* Add SemLock type to module */
243 if (PyType_Ready(&SemLockType) < 0)
244 return NULL;
245 Py_INCREF(&SemLockType);
Gregory P. Smith68e01352010-10-17 02:14:36 +0000246 {
247 PyObject *py_sem_value_max;
248 /* Some systems define SEM_VALUE_MAX as an unsigned value that
249 * causes it to be negative when used as an int (NetBSD). */
250 if ((int)(SEM_VALUE_MAX) < 0)
251 py_sem_value_max = PyLong_FromLong(INT_MAX);
252 else
253 py_sem_value_max = PyLong_FromLong(SEM_VALUE_MAX);
254 if (py_sem_value_max == NULL)
255 return NULL;
256 PyDict_SetItemString(SemLockType.tp_dict, "SEM_VALUE_MAX",
257 py_sem_value_max);
258 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000259 PyModule_AddObject(module, "SemLock", (PyObject*)&SemLockType);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000260#endif
261
262#ifdef MS_WINDOWS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000263 /* Initialize win32 class and add to multiprocessing */
264 temp = create_win32_namespace();
265 if (!temp)
266 return NULL;
267 PyModule_AddObject(module, "win32", temp);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000268
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000269 /* Initialize the event handle used to signal Ctrl-C */
270 sigint_event = CreateEvent(NULL, TRUE, FALSE, NULL);
271 if (!sigint_event) {
272 PyErr_SetFromWindowsErr(0);
273 return NULL;
274 }
275 if (!SetConsoleCtrlHandler(ProcessingCtrlHandler, TRUE)) {
276 PyErr_SetFromWindowsErr(0);
277 return NULL;
278 }
Benjamin Petersonfa268032008-06-13 19:28:21 +0000279#endif
280
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000281 /* Add configuration macros */
282 temp = PyDict_New();
283 if (!temp)
284 return NULL;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000285
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000286#define ADD_FLAG(name) \
287 value = Py_BuildValue("i", name); \
288 if (value == NULL) { Py_DECREF(temp); return NULL; } \
289 if (PyDict_SetItemString(temp, #name, value) < 0) { \
290 Py_DECREF(temp); Py_DECREF(value); return NULL; } \
291 Py_DECREF(value)
292
Mark Dickinsona614f042009-11-28 12:48:43 +0000293#if defined(HAVE_SEM_OPEN) && !defined(POSIX_SEMAPHORES_NOT_ENABLED)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000294 ADD_FLAG(HAVE_SEM_OPEN);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000295#endif
296#ifdef HAVE_SEM_TIMEDWAIT
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000297 ADD_FLAG(HAVE_SEM_TIMEDWAIT);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000298#endif
299#ifdef HAVE_FD_TRANSFER
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000300 ADD_FLAG(HAVE_FD_TRANSFER);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000301#endif
302#ifdef HAVE_BROKEN_SEM_GETVALUE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000303 ADD_FLAG(HAVE_BROKEN_SEM_GETVALUE);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000304#endif
305#ifdef HAVE_BROKEN_SEM_UNLINK
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000306 ADD_FLAG(HAVE_BROKEN_SEM_UNLINK);
Benjamin Petersonfa268032008-06-13 19:28:21 +0000307#endif
308
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000309 if (PyModule_AddObject(module, "flags", temp) < 0)
310 return NULL;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000311
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000312 return module;
Benjamin Petersonfa268032008-06-13 19:28:21 +0000313}