blob: 806e638340f7af0dcba9671f7184da62828b459b [file] [log] [blame]
/*
* Extension module used by multiprocessing package
*
* multiprocessing.c
*
* Copyright (c) 2006-2008, R Oudkerk
* Licensed to PSF under a Contributor Agreement.
*/
#include "multiprocessing.h"
/*
* Function which raises exceptions based on error codes
*/
PyObject *
_PyMp_SetError(PyObject *Type, int num)
{
switch (num) {
#ifdef MS_WINDOWS
case MP_STANDARD_ERROR:
if (Type == NULL)
Type = PyExc_OSError;
PyErr_SetExcFromWindowsErr(Type, 0);
break;
case MP_SOCKET_ERROR:
if (Type == NULL)
Type = PyExc_OSError;
PyErr_SetExcFromWindowsErr(Type, WSAGetLastError());
break;
#else /* !MS_WINDOWS */
case MP_STANDARD_ERROR:
case MP_SOCKET_ERROR:
if (Type == NULL)
Type = PyExc_OSError;
PyErr_SetFromErrno(Type);
break;
#endif /* !MS_WINDOWS */
case MP_MEMORY_ERROR:
PyErr_NoMemory();
break;
case MP_EXCEPTION_HAS_BEEN_SET:
break;
default:
PyErr_Format(PyExc_RuntimeError,
"unknown error number %d", num);
}
return NULL;
}
#ifdef MS_WINDOWS
static PyObject *
multiprocessing_closesocket(PyObject *self, PyObject *args)
{
HANDLE handle;
int ret;
if (!PyArg_ParseTuple(args, F_HANDLE ":closesocket" , &handle))
return NULL;
Py_BEGIN_ALLOW_THREADS
ret = closesocket((SOCKET) handle);
Py_END_ALLOW_THREADS
if (ret)
return PyErr_SetExcFromWindowsErr(PyExc_OSError, WSAGetLastError());
Py_RETURN_NONE;
}
static PyObject *
multiprocessing_recv(PyObject *self, PyObject *args)
{
HANDLE handle;
int size, nread;
PyObject *buf;
if (!PyArg_ParseTuple(args, F_HANDLE "i:recv" , &handle, &size))
return NULL;
buf = PyBytes_FromStringAndSize(NULL, size);
if (!buf)
return NULL;
Py_BEGIN_ALLOW_THREADS
nread = recv((SOCKET) handle, PyBytes_AS_STRING(buf), size, 0);
Py_END_ALLOW_THREADS
if (nread < 0) {
Py_DECREF(buf);
return PyErr_SetExcFromWindowsErr(PyExc_OSError, WSAGetLastError());
}
_PyBytes_Resize(&buf, nread);
return buf;
}
static PyObject *
multiprocessing_send(PyObject *self, PyObject *args)
{
HANDLE handle;
Py_buffer buf;
int ret, length;
if (!PyArg_ParseTuple(args, F_HANDLE "y*:send" , &handle, &buf))
return NULL;
length = (int)Py_MIN(buf.len, INT_MAX);
Py_BEGIN_ALLOW_THREADS
ret = send((SOCKET) handle, buf.buf, length, 0);
Py_END_ALLOW_THREADS
PyBuffer_Release(&buf);
if (ret < 0)
return PyErr_SetExcFromWindowsErr(PyExc_OSError, WSAGetLastError());
return PyLong_FromLong(ret);
}
#endif
/*
* Function table
*/
static PyMethodDef module_methods[] = {
#ifdef MS_WINDOWS
{"closesocket", multiprocessing_closesocket, METH_VARARGS, ""},
{"recv", multiprocessing_recv, METH_VARARGS, ""},
{"send", multiprocessing_send, METH_VARARGS, ""},
#endif
#if !defined(POSIX_SEMAPHORES_NOT_ENABLED) && !defined(__ANDROID__)
{"sem_unlink", _PyMp_sem_unlink, METH_VARARGS, ""},
#endif
{NULL}
};
/*
* Initialize
*/
static struct PyModuleDef multiprocessing_module = {
PyModuleDef_HEAD_INIT,
"_multiprocessing",
NULL,
-1,
module_methods,
NULL,
NULL,
NULL,
NULL
};
PyMODINIT_FUNC
PyInit__multiprocessing(void)
{
PyObject *module, *temp, *value = NULL;
/* Initialize module */
module = PyModule_Create(&multiprocessing_module);
if (!module)
return NULL;
#if defined(MS_WINDOWS) || \
(defined(HAVE_SEM_OPEN) && !defined(POSIX_SEMAPHORES_NOT_ENABLED))
/* Add _PyMp_SemLock type to module */
if (PyType_Ready(&_PyMp_SemLockType) < 0)
return NULL;
Py_INCREF(&_PyMp_SemLockType);
{
PyObject *py_sem_value_max;
/* Some systems define SEM_VALUE_MAX as an unsigned value that
* causes it to be negative when used as an int (NetBSD).
*
* Issue #28152: Use (0) instead of 0 to fix a warning on dead code
* when using clang -Wunreachable-code. */
if ((int)(SEM_VALUE_MAX) < (0))
py_sem_value_max = PyLong_FromLong(INT_MAX);
else
py_sem_value_max = PyLong_FromLong(SEM_VALUE_MAX);
if (py_sem_value_max == NULL)
return NULL;
PyDict_SetItemString(_PyMp_SemLockType.tp_dict, "SEM_VALUE_MAX",
py_sem_value_max);
}
PyModule_AddObject(module, "SemLock", (PyObject*)&_PyMp_SemLockType);
#endif
/* Add configuration macros */
temp = PyDict_New();
if (!temp)
return NULL;
#define ADD_FLAG(name) \
value = Py_BuildValue("i", name); \
if (value == NULL) { Py_DECREF(temp); return NULL; } \
if (PyDict_SetItemString(temp, #name, value) < 0) { \
Py_DECREF(temp); Py_DECREF(value); return NULL; } \
Py_DECREF(value)
#if defined(HAVE_SEM_OPEN) && !defined(POSIX_SEMAPHORES_NOT_ENABLED)
ADD_FLAG(HAVE_SEM_OPEN);
#endif
#ifdef HAVE_SEM_TIMEDWAIT
ADD_FLAG(HAVE_SEM_TIMEDWAIT);
#endif
#ifdef HAVE_BROKEN_SEM_GETVALUE
ADD_FLAG(HAVE_BROKEN_SEM_GETVALUE);
#endif
#ifdef HAVE_BROKEN_SEM_UNLINK
ADD_FLAG(HAVE_BROKEN_SEM_UNLINK);
#endif
if (PyModule_AddObject(module, "flags", temp) < 0)
return NULL;
return module;
}