2 * Extension module used by multiprocessing package
6 * Copyright (c) 2006-2008, R Oudkerk --- see COPYING.txt
9 #include "multiprocessing.h"
12 #define HAVE_FD_TRANSFER 1
14 #define HAVE_FD_TRANSFER 0
17 PyObject
*create_win32_namespace(void);
19 PyObject
*pickle_dumps
, *pickle_loads
, *pickle_protocol
;
20 PyObject
*ProcessError
, *BufferTooShort
;
23 * Function which raises exceptions based on error codes
27 mp_SetError(PyObject
*Type
, int num
)
31 case MP_STANDARD_ERROR
:
33 Type
= PyExc_WindowsError
;
34 PyErr_SetExcFromWindowsErr(Type
, 0);
38 Type
= PyExc_WindowsError
;
39 PyErr_SetExcFromWindowsErr(Type
, WSAGetLastError());
41 #else /* !MS_WINDOWS */
42 case MP_STANDARD_ERROR
:
46 PyErr_SetFromErrno(Type
);
48 #endif /* !MS_WINDOWS */
53 PyErr_SetNone(PyExc_EOFError
);
55 case MP_EARLY_END_OF_FILE
:
56 PyErr_SetString(PyExc_IOError
,
57 "got end of file during message");
59 case MP_BAD_MESSAGE_LENGTH
:
60 PyErr_SetString(PyExc_IOError
, "bad message length");
62 case MP_EXCEPTION_HAS_BEEN_SET
:
65 PyErr_Format(PyExc_RuntimeError
,
66 "unkown error number %d", num
);
78 /* On Windows we set an event to signal Ctrl-C; compare with timemodule.c */
80 HANDLE sigint_event
= NULL
;
83 ProcessingCtrlHandler(DWORD dwCtrlType
)
85 SetEvent(sigint_event
);
93 #else /* !MS_WINDOWS */
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. */
102 multiprocessing_sendfd(PyObject
*self
, PyObject
*args
)
106 char buf
[CMSG_SPACE(sizeof(int))];
107 struct msghdr msg
= {0};
108 struct iovec dummy_iov
;
109 struct cmsghdr
*cmsg
;
111 if (!PyArg_ParseTuple(args
, "ii", &conn
, &fd
))
114 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
;
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
;
127 Py_BEGIN_ALLOW_THREADS
128 res
= sendmsg(conn
, &msg
, 0);
132 return PyErr_SetFromErrno(PyExc_OSError
);
137 multiprocessing_recvfd(PyObject
*self
, PyObject
*args
)
141 char buf
[CMSG_SPACE(sizeof(int))];
142 struct msghdr msg
= {0};
143 struct iovec dummy_iov
;
144 struct cmsghdr
*cmsg
;
146 if (!PyArg_ParseTuple(args
, "i", &conn
))
149 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
;
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
;
161 Py_BEGIN_ALLOW_THREADS
162 res
= recvmsg(conn
, &msg
, 0);
166 return PyErr_SetFromErrno(PyExc_OSError
);
168 fd
= *(int*)CMSG_DATA(cmsg
);
169 return Py_BuildValue("i", fd
);
172 #endif /* HAVE_FD_TRANSFER */
174 #endif /* !MS_WINDOWS */
182 multiprocessing_address_of_buffer(PyObject
*self
, PyObject
*obj
)
185 Py_ssize_t buffer_len
;
187 if (PyObject_AsWriteBuffer(obj
, &buffer
, &buffer_len
) < 0)
190 return Py_BuildValue("N" F_PY_SSIZE_T
,
191 PyLong_FromVoidPtr(buffer
), buffer_len
);
199 static PyMethodDef module_methods
[] = {
200 {"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"},
204 {"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"},
222 init_multiprocessing(void)
224 PyObject
*module
, *temp
, *value
;
226 /* Initialize module */
227 module
= Py_InitModule("_multiprocessing", module_methods
);
231 /* Get copy of objects from pickle */
232 temp
= PyImport_ImportModule(PICKLE_MODULE
);
235 pickle_dumps
= PyObject_GetAttrString(temp
, "dumps");
236 pickle_loads
= PyObject_GetAttrString(temp
, "loads");
237 pickle_protocol
= PyObject_GetAttrString(temp
, "HIGHEST_PROTOCOL");
240 /* Get copy of BufferTooShort */
241 temp
= PyImport_ImportModule("multiprocessing");
244 BufferTooShort
= PyObject_GetAttrString(temp
, "BufferTooShort");
247 /* Add connection type to module */
248 if (PyType_Ready(&ConnectionType
) < 0)
250 Py_INCREF(&ConnectionType
);
251 PyModule_AddObject(module
, "Connection", (PyObject
*)&ConnectionType
);
253 #if defined(MS_WINDOWS) || defined(HAVE_SEM_OPEN)
254 /* Add SemLock type to module */
255 if (PyType_Ready(&SemLockType
) < 0)
257 Py_INCREF(&SemLockType
);
258 PyDict_SetItemString(SemLockType
.tp_dict
, "SEM_VALUE_MAX",
259 Py_BuildValue("i", SEM_VALUE_MAX
));
260 PyModule_AddObject(module
, "SemLock", (PyObject
*)&SemLockType
);
264 /* Add PipeConnection to module */
265 if (PyType_Ready(&PipeConnectionType
) < 0)
267 Py_INCREF(&PipeConnectionType
);
268 PyModule_AddObject(module
, "PipeConnection",
269 (PyObject
*)&PipeConnectionType
);
271 /* Initialize win32 class and add to multiprocessing */
272 temp
= create_win32_namespace();
275 PyModule_AddObject(module
, "win32", temp
);
277 /* Initialize the event handle used to signal Ctrl-C */
278 sigint_event
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
280 PyErr_SetFromWindowsErr(0);
283 if (!SetConsoleCtrlHandler(ProcessingCtrlHandler
, TRUE
)) {
284 PyErr_SetFromWindowsErr(0);
289 /* Add configuration macros */
293 #define ADD_FLAG(name) \
294 value = Py_BuildValue("i", name); \
295 if (value == NULL) { Py_DECREF(temp); return; } \
296 if (PyDict_SetItemString(temp, #name, value) < 0) { \
297 Py_DECREF(temp); Py_DECREF(value); return; } \
301 ADD_FLAG(HAVE_SEM_OPEN
);
303 #ifdef HAVE_SEM_TIMEDWAIT
304 ADD_FLAG(HAVE_SEM_TIMEDWAIT
);
306 #ifdef HAVE_FD_TRANSFER
307 ADD_FLAG(HAVE_FD_TRANSFER
);
309 #ifdef HAVE_BROKEN_SEM_GETVALUE
310 ADD_FLAG(HAVE_BROKEN_SEM_GETVALUE
);
312 #ifdef HAVE_BROKEN_SEM_UNLINK
313 ADD_FLAG(HAVE_BROKEN_SEM_UNLINK
);
315 if (PyModule_AddObject(module
, "flags", temp
) < 0)