2 * Extension module used by multiprocessing package
6 * Copyright (c) 2006-2008, R Oudkerk --- see COPYING.txt
9 #include "multiprocessing.h"
11 PyObject
*create_win32_namespace(void);
13 PyObject
*pickle_dumps
, *pickle_loads
, *pickle_protocol
;
14 PyObject
*ProcessError
, *BufferTooShort
;
17 * Function which raises exceptions based on error codes
21 mp_SetError(PyObject
*Type
, int num
)
25 case MP_STANDARD_ERROR
:
27 Type
= PyExc_WindowsError
;
28 PyErr_SetExcFromWindowsErr(Type
, 0);
32 Type
= PyExc_WindowsError
;
33 PyErr_SetExcFromWindowsErr(Type
, WSAGetLastError());
35 #else /* !MS_WINDOWS */
36 case MP_STANDARD_ERROR
:
40 PyErr_SetFromErrno(Type
);
42 #endif /* !MS_WINDOWS */
47 PyErr_SetNone(PyExc_EOFError
);
49 case MP_EARLY_END_OF_FILE
:
50 PyErr_SetString(PyExc_IOError
,
51 "got end of file during message");
53 case MP_BAD_MESSAGE_LENGTH
:
54 PyErr_SetString(PyExc_IOError
, "bad message length");
56 case MP_EXCEPTION_HAS_BEEN_SET
:
59 PyErr_Format(PyExc_RuntimeError
,
60 "unkown error number %d", num
);
72 /* On Windows we set an event to signal Ctrl-C; compare with timemodule.c */
74 HANDLE sigint_event
= NULL
;
77 ProcessingCtrlHandler(DWORD dwCtrlType
)
79 SetEvent(sigint_event
);
87 #else /* !MS_WINDOWS */
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. */
96 multiprocessing_sendfd(PyObject
*self
, PyObject
*args
)
100 char buf
[CMSG_SPACE(sizeof(int))];
101 struct msghdr msg
= {0};
102 struct iovec dummy_iov
;
103 struct cmsghdr
*cmsg
;
105 if (!PyArg_ParseTuple(args
, "ii", &conn
, &fd
))
108 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
;
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
;
121 Py_BEGIN_ALLOW_THREADS
122 res
= sendmsg(conn
, &msg
, 0);
126 return PyErr_SetFromErrno(PyExc_OSError
);
131 multiprocessing_recvfd(PyObject
*self
, PyObject
*args
)
135 char buf
[CMSG_SPACE(sizeof(int))];
136 struct msghdr msg
= {0};
137 struct iovec dummy_iov
;
138 struct cmsghdr
*cmsg
;
140 if (!PyArg_ParseTuple(args
, "i", &conn
))
143 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
;
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
;
155 Py_BEGIN_ALLOW_THREADS
156 res
= recvmsg(conn
, &msg
, 0);
160 return PyErr_SetFromErrno(PyExc_OSError
);
162 fd
= *(int*)CMSG_DATA(cmsg
);
163 return Py_BuildValue("i", fd
);
166 #endif /* HAVE_FD_TRANSFER */
168 #endif /* !MS_WINDOWS */
176 multiprocessing_address_of_buffer(PyObject
*self
, PyObject
*obj
)
179 Py_ssize_t buffer_len
;
181 if (PyObject_AsWriteBuffer(obj
, &buffer
, &buffer_len
) < 0)
184 return Py_BuildValue("N" F_PY_SSIZE_T
,
185 PyLong_FromVoidPtr(buffer
), buffer_len
);
193 static PyMethodDef module_methods
[] = {
194 {"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"},
198 {"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"},
216 init_multiprocessing(void)
218 PyObject
*module
, *temp
, *value
;
220 /* Initialize module */
221 module
= Py_InitModule("_multiprocessing", module_methods
);
225 /* Get copy of objects from pickle */
226 temp
= PyImport_ImportModule(PICKLE_MODULE
);
229 pickle_dumps
= PyObject_GetAttrString(temp
, "dumps");
230 pickle_loads
= PyObject_GetAttrString(temp
, "loads");
231 pickle_protocol
= PyObject_GetAttrString(temp
, "HIGHEST_PROTOCOL");
234 /* Get copy of BufferTooShort */
235 temp
= PyImport_ImportModule("multiprocessing");
238 BufferTooShort
= PyObject_GetAttrString(temp
, "BufferTooShort");
241 /* Add connection type to module */
242 if (PyType_Ready(&ConnectionType
) < 0)
244 Py_INCREF(&ConnectionType
);
245 PyModule_AddObject(module
, "Connection", (PyObject
*)&ConnectionType
);
247 #if defined(MS_WINDOWS) || HAVE_SEM_OPEN
248 /* Add SemLock type to module */
249 if (PyType_Ready(&SemLockType
) < 0)
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
);
258 /* Add PipeConnection to module */
259 if (PyType_Ready(&PipeConnectionType
) < 0)
261 Py_INCREF(&PipeConnectionType
);
262 PyModule_AddObject(module
, "PipeConnection",
263 (PyObject
*)&PipeConnectionType
);
265 /* Initialize win32 class and add to multiprocessing */
266 temp
= create_win32_namespace();
269 PyModule_AddObject(module
, "win32", temp
);
271 /* Initialize the event handle used to signal Ctrl-C */
272 sigint_event
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
274 PyErr_SetFromWindowsErr(0);
277 if (!SetConsoleCtrlHandler(ProcessingCtrlHandler
, TRUE
)) {
278 PyErr_SetFromWindowsErr(0);
283 /* Add configuration macros */
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; } \
295 ADD_FLAG(HAVE_SEM_OPEN
);
297 #ifdef HAVE_SEM_TIMEDWAIT
298 ADD_FLAG(HAVE_SEM_TIMEDWAIT
);
300 #ifdef HAVE_FD_TRANSFER
301 ADD_FLAG(HAVE_FD_TRANSFER
);
303 #ifdef HAVE_BROKEN_SEM_GETVALUE
304 ADD_FLAG(HAVE_BROKEN_SEM_GETVALUE
);
306 #ifdef HAVE_BROKEN_SEM_UNLINK
307 ADD_FLAG(HAVE_BROKEN_SEM_UNLINK
);
309 if (PyModule_AddObject(module
, "flags", temp
) < 0)