Benjamin Peterson | 190d56e | 2008-06-11 02:40:25 +0000 | [diff] [blame] | 1 | /*
|
Georg Brandl | e1f6646 | 2008-06-13 07:08:48 +0000 | [diff] [blame] | 2 | * Extension module used by multiprocessing package
|
Benjamin Peterson | 190d56e | 2008-06-11 02:40:25 +0000 | [diff] [blame] | 3 | *
|
| 4 | * multiprocessing.c
|
| 5 | *
|
| 6 | * Copyright (c) 2006-2008, R Oudkerk --- see COPYING.txt
|
| 7 | */
|
| 8 |
|
| 9 | #include "multiprocessing.h"
|
| 10 |
|
| 11 | PyObject *create_win32_namespace(void);
|
| 12 |
|
| 13 | PyObject *pickle_dumps, *pickle_loads, *pickle_protocol;
|
| 14 | PyObject *ProcessError, *BufferTooShort;
|
| 15 |
|
| 16 | /*
|
| 17 | * Function which raises exceptions based on error codes
|
| 18 | */
|
| 19 |
|
| 20 | PyObject *
|
| 21 | mp_SetError(PyObject *Type, int num)
|
| 22 | {
|
| 23 | switch (num) {
|
| 24 | #ifdef MS_WINDOWS
|
| 25 | 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;
|
| 35 | #else /* !MS_WINDOWS */
|
| 36 | case MP_STANDARD_ERROR:
|
| 37 | case MP_SOCKET_ERROR:
|
| 38 | if (Type == NULL)
|
| 39 | Type = PyExc_OSError;
|
| 40 | PyErr_SetFromErrno(Type);
|
| 41 | break;
|
| 42 | #endif /* !MS_WINDOWS */
|
| 43 | 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;
|
| 63 | }
|
| 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 |
|
| 74 | HANDLE sigint_event = NULL;
|
| 75 |
|
| 76 | static BOOL WINAPI
|
| 77 | ProcessingCtrlHandler(DWORD dwCtrlType)
|
| 78 | {
|
| 79 | SetEvent(sigint_event);
|
| 80 | return FALSE;
|
| 81 | }
|
| 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 |
|
| 95 | static PyObject *
|
| 96 | multiprocessing_sendfd(PyObject *self, PyObject *args)
|
| 97 | {
|
| 98 | 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;
|
| 104 |
|
| 105 | if (!PyArg_ParseTuple(args, "ii", &conn, &fd))
|
| 106 | return NULL;
|
| 107 |
|
| 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;
|
| 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;
|
| 120 |
|
| 121 | Py_BEGIN_ALLOW_THREADS
|
| 122 | res = sendmsg(conn, &msg, 0);
|
| 123 | Py_END_ALLOW_THREADS
|
| 124 |
|
| 125 | if (res < 0)
|
| 126 | return PyErr_SetFromErrno(PyExc_OSError);
|
| 127 | Py_RETURN_NONE;
|
| 128 | }
|
| 129 |
|
| 130 | static PyObject *
|
| 131 | multiprocessing_recvfd(PyObject *self, PyObject *args)
|
| 132 | {
|
| 133 | 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;
|
| 139 |
|
| 140 | if (!PyArg_ParseTuple(args, "i", &conn))
|
| 141 | return NULL;
|
| 142 |
|
| 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;
|
| 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;
|
| 154 |
|
| 155 | Py_BEGIN_ALLOW_THREADS
|
| 156 | res = recvmsg(conn, &msg, 0);
|
| 157 | Py_END_ALLOW_THREADS
|
| 158 |
|
| 159 | if (res < 0)
|
| 160 | return PyErr_SetFromErrno(PyExc_OSError);
|
| 161 |
|
| 162 | fd = *(int*)CMSG_DATA(cmsg);
|
| 163 | return Py_BuildValue("i", fd);
|
| 164 | }
|
| 165 |
|
| 166 | #endif /* HAVE_FD_TRANSFER */
|
| 167 |
|
| 168 | #endif /* !MS_WINDOWS */
|
| 169 |
|
| 170 |
|
| 171 | /*
|
| 172 | * All platforms
|
| 173 | */
|
| 174 |
|
| 175 | static PyObject*
|
| 176 | multiprocessing_address_of_buffer(PyObject *self, PyObject *obj)
|
| 177 | {
|
| 178 | void *buffer;
|
| 179 | Py_ssize_t buffer_len;
|
| 180 |
|
| 181 | if (PyObject_AsWriteBuffer(obj, &buffer, &buffer_len) < 0)
|
| 182 | return NULL;
|
| 183 |
|
| 184 | return Py_BuildValue("N" F_PY_SSIZE_T,
|
| 185 | PyLong_FromVoidPtr(buffer), buffer_len);
|
| 186 | }
|
| 187 |
|
| 188 |
|
| 189 | /*
|
| 190 | * Function table
|
| 191 | */
|
| 192 |
|
| 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"},
|
| 197 | #if HAVE_FD_TRANSFER
|
| 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"},
|
| 206 | #endif
|
| 207 | {NULL}
|
| 208 | };
|
| 209 |
|
| 210 |
|
| 211 | /*
|
| 212 | * Initialize
|
| 213 | */
|
| 214 |
|
| 215 | PyMODINIT_FUNC
|
| 216 | init_multiprocessing(void)
|
| 217 | {
|
Georg Brandl | 6d53e7e | 2008-06-13 06:56:50 +0000 | [diff] [blame] | 218 | PyObject *module, *temp, *value;
|
Benjamin Peterson | 190d56e | 2008-06-11 02:40:25 +0000 | [diff] [blame] | 219 |
|
| 220 | /* Initialize module */
|
| 221 | module = Py_InitModule("_multiprocessing", module_methods);
|
| 222 | if (!module)
|
| 223 | return;
|
| 224 |
|
| 225 | /* 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);
|
| 233 |
|
| 234 | /* Get copy of BufferTooShort */
|
| 235 | temp = PyImport_ImportModule("multiprocessing");
|
| 236 | if (!temp)
|
| 237 | return;
|
| 238 | BufferTooShort = PyObject_GetAttrString(temp, "BufferTooShort");
|
| 239 | Py_XDECREF(temp);
|
| 240 |
|
| 241 | /* Add connection type to module */
|
| 242 | if (PyType_Ready(&ConnectionType) < 0)
|
| 243 | return;
|
| 244 | Py_INCREF(&ConnectionType);
|
| 245 | PyModule_AddObject(module, "Connection", (PyObject*)&ConnectionType);
|
| 246 |
|
| 247 | #if defined(MS_WINDOWS) || HAVE_SEM_OPEN
|
| 248 | /* 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);
|
| 255 | #endif
|
| 256 |
|
| 257 | #ifdef MS_WINDOWS
|
| 258 | /* Add PipeConnection to module */
|
| 259 | if (PyType_Ready(&PipeConnectionType) < 0)
|
| 260 | return;
|
| 261 | Py_INCREF(&PipeConnectionType);
|
| 262 | PyModule_AddObject(module, "PipeConnection",
|
| 263 | (PyObject*)&PipeConnectionType);
|
| 264 |
|
| 265 | /* Initialize win32 class and add to multiprocessing */
|
| 266 | temp = create_win32_namespace();
|
| 267 | if (!temp)
|
| 268 | return;
|
| 269 | PyModule_AddObject(module, "win32", temp);
|
| 270 |
|
| 271 | /* 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 | }
|
| 281 | #endif
|
| 282 |
|
| 283 | /* Add configuration macros */
|
| 284 | temp = PyDict_New();
|
| 285 | if (!temp)
|
| 286 | return;
|
Georg Brandl | 6d53e7e | 2008-06-13 06:56:50 +0000 | [diff] [blame] | 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)
|
Benjamin Peterson | 190d56e | 2008-06-11 02:40:25 +0000 | [diff] [blame] | 293 |
|
| 294 | #ifdef HAVE_SEM_OPEN
|
| 295 | ADD_FLAG(HAVE_SEM_OPEN);
|
| 296 | #endif
|
| 297 | #ifdef HAVE_SEM_TIMEDWAIT
|
| 298 | ADD_FLAG(HAVE_SEM_TIMEDWAIT);
|
| 299 | #endif
|
| 300 | #ifdef HAVE_FD_TRANSFER
|
| 301 | ADD_FLAG(HAVE_FD_TRANSFER);
|
| 302 | #endif
|
| 303 | #ifdef HAVE_BROKEN_SEM_GETVALUE
|
| 304 | ADD_FLAG(HAVE_BROKEN_SEM_GETVALUE);
|
| 305 | #endif
|
| 306 | #ifdef HAVE_BROKEN_SEM_UNLINK
|
| 307 | ADD_FLAG(HAVE_BROKEN_SEM_UNLINK);
|
| 308 | #endif
|
Georg Brandl | 6d53e7e | 2008-06-13 06:56:50 +0000 | [diff] [blame] | 309 | if (PyModule_AddObject(module, "flags", temp) < 0)
|
| 310 | return;
|
Benjamin Peterson | 190d56e | 2008-06-11 02:40:25 +0000 | [diff] [blame] | 311 | }
|