1 /* 2 * Extension module used by multiprocessing package 3 * 4 * multiprocessing.c 5 * 6 * Copyright (c) 2006-2008, R Oudkerk 7 * Licensed to PSF under a Contributor Agreement. 8 */ 9 10 #include "multiprocessing.h" 11 12 13 /* 14 * Function which raises exceptions based on error codes 15 */ 16 17 PyObject * 18 _PyMp_SetError(PyObject *Type, int num) 19 { 20 switch (num) { 21 #ifdef MS_WINDOWS 22 case MP_STANDARD_ERROR: 23 if (Type == NULL) 24 Type = PyExc_OSError; 25 PyErr_SetExcFromWindowsErr(Type, 0); 26 break; 27 case MP_SOCKET_ERROR: 28 if (Type == NULL) 29 Type = PyExc_OSError; 30 PyErr_SetExcFromWindowsErr(Type, WSAGetLastError()); 31 break; 32 #else /* !MS_WINDOWS */ 33 case MP_STANDARD_ERROR: 34 case MP_SOCKET_ERROR: 35 if (Type == NULL) 36 Type = PyExc_OSError; 37 PyErr_SetFromErrno(Type); 38 break; 39 #endif /* !MS_WINDOWS */ 40 case MP_MEMORY_ERROR: 41 PyErr_NoMemory(); 42 break; 43 case MP_EXCEPTION_HAS_BEEN_SET: 44 break; 45 default: 46 PyErr_Format(PyExc_RuntimeError, 47 "unknown error number %d", num); 48 } 49 return NULL; 50 } 51 52 #ifdef MS_WINDOWS 53 static PyObject * 54 multiprocessing_closesocket(PyObject *self, PyObject *args) 55 { 56 HANDLE handle; 57 int ret; 58 59 if (!PyArg_ParseTuple(args, F_HANDLE ":closesocket" , &handle)) 60 return NULL; 61 62 Py_BEGIN_ALLOW_THREADS 63 ret = closesocket((SOCKET) handle); 64 Py_END_ALLOW_THREADS 65 66 if (ret) 67 return PyErr_SetExcFromWindowsErr(PyExc_OSError, WSAGetLastError()); 68 Py_RETURN_NONE; 69 } 70 71 static PyObject * 72 multiprocessing_recv(PyObject *self, PyObject *args) 73 { 74 HANDLE handle; 75 int size, nread; 76 PyObject *buf; 77 78 if (!PyArg_ParseTuple(args, F_HANDLE "i:recv" , &handle, &size)) 79 return NULL; 80 81 buf = PyBytes_FromStringAndSize(NULL, size); 82 if (!buf) 83 return NULL; 84 85 Py_BEGIN_ALLOW_THREADS 86 nread = recv((SOCKET) handle, PyBytes_AS_STRING(buf), size, 0); 87 Py_END_ALLOW_THREADS 88 89 if (nread < 0) { 90 Py_DECREF(buf); 91 return PyErr_SetExcFromWindowsErr(PyExc_OSError, WSAGetLastError()); 92 } 93 _PyBytes_Resize(&buf, nread); 94 return buf; 95 } 96 97 static PyObject * 98 multiprocessing_send(PyObject *self, PyObject *args) 99 { 100 HANDLE handle; 101 Py_buffer buf; 102 int ret, length; 103 104 if (!PyArg_ParseTuple(args, F_HANDLE "y*:send" , &handle, &buf)) 105 return NULL; 106 107 length = (int)Py_MIN(buf.len, INT_MAX); 108 109 Py_BEGIN_ALLOW_THREADS 110 ret = send((SOCKET) handle, buf.buf, length, 0); 111 Py_END_ALLOW_THREADS 112 113 PyBuffer_Release(&buf); 114 if (ret < 0) 115 return PyErr_SetExcFromWindowsErr(PyExc_OSError, WSAGetLastError()); 116 return PyLong_FromLong(ret); 117 } 118 119 #endif 120 121 /* 122 * Function table 123 */ 124 125 static PyMethodDef module_methods[] = { 126 #ifdef MS_WINDOWS 127 {"closesocket", multiprocessing_closesocket, METH_VARARGS, ""}, 128 {"recv", multiprocessing_recv, METH_VARARGS, ""}, 129 {"send", multiprocessing_send, METH_VARARGS, ""}, 130 #endif 131 #if !defined(POSIX_SEMAPHORES_NOT_ENABLED) && !defined(__ANDROID__) 132 {"sem_unlink", _PyMp_sem_unlink, METH_VARARGS, ""}, 133 #endif 134 {NULL} 135 }; 136 137 138 /* 139 * Initialize 140 */ 141 142 static struct PyModuleDef multiprocessing_module = { 143 PyModuleDef_HEAD_INIT, 144 "_multiprocessing", 145 NULL, 146 -1, 147 module_methods, 148 NULL, 149 NULL, 150 NULL, 151 NULL 152 }; 153 154 155 PyMODINIT_FUNC 156 PyInit__multiprocessing(void) 157 { 158 PyObject *module, *temp, *value = NULL; 159 160 /* Initialize module */ 161 module = PyModule_Create(&multiprocessing_module); 162 if (!module) 163 return NULL; 164 165 #if defined(MS_WINDOWS) || \ 166 (defined(HAVE_SEM_OPEN) && !defined(POSIX_SEMAPHORES_NOT_ENABLED)) 167 /* Add _PyMp_SemLock type to module */ 168 if (PyType_Ready(&_PyMp_SemLockType) < 0) 169 return NULL; 170 Py_INCREF(&_PyMp_SemLockType); 171 { 172 PyObject *py_sem_value_max; 173 /* Some systems define SEM_VALUE_MAX as an unsigned value that 174 * causes it to be negative when used as an int (NetBSD). 175 * 176 * Issue #28152: Use (0) instead of 0 to fix a warning on dead code 177 * when using clang -Wunreachable-code. */ 178 if ((int)(SEM_VALUE_MAX) < (0)) 179 py_sem_value_max = PyLong_FromLong(INT_MAX); 180 else 181 py_sem_value_max = PyLong_FromLong(SEM_VALUE_MAX); 182 if (py_sem_value_max == NULL) 183 return NULL; 184 PyDict_SetItemString(_PyMp_SemLockType.tp_dict, "SEM_VALUE_MAX", 185 py_sem_value_max); 186 } 187 PyModule_AddObject(module, "SemLock", (PyObject*)&_PyMp_SemLockType); 188 #endif 189 190 /* Add configuration macros */ 191 temp = PyDict_New(); 192 if (!temp) 193 return NULL; 194 195 #define ADD_FLAG(name) \ 196 value = Py_BuildValue("i", name); \ 197 if (value == NULL) { Py_DECREF(temp); return NULL; } \ 198 if (PyDict_SetItemString(temp, #name, value) < 0) { \ 199 Py_DECREF(temp); Py_DECREF(value); return NULL; } \ 200 Py_DECREF(value) 201 202 #if defined(HAVE_SEM_OPEN) && !defined(POSIX_SEMAPHORES_NOT_ENABLED) 203 ADD_FLAG(HAVE_SEM_OPEN); 204 #endif 205 #ifdef HAVE_SEM_TIMEDWAIT 206 ADD_FLAG(HAVE_SEM_TIMEDWAIT); 207 #endif 208 #ifdef HAVE_BROKEN_SEM_GETVALUE 209 ADD_FLAG(HAVE_BROKEN_SEM_GETVALUE); 210 #endif 211 #ifdef HAVE_BROKEN_SEM_UNLINK 212 ADD_FLAG(HAVE_BROKEN_SEM_UNLINK); 213 #endif 214 215 if (PyModule_AddObject(module, "flags", temp) < 0) 216 return NULL; 217 218 return module; 219 } 220