diff options
Diffstat (limited to 'Modules/_multiprocessing/semaphore.c')
-rw-r--r-- | Modules/_multiprocessing/semaphore.c | 227 |
1 files changed, 89 insertions, 138 deletions
diff --git a/Modules/_multiprocessing/semaphore.c b/Modules/_multiprocessing/semaphore.c index 4be2dea..fc42754 100644 --- a/Modules/_multiprocessing/semaphore.c +++ b/Modules/_multiprocessing/semaphore.c @@ -3,8 +3,7 @@ * * semaphore.c * - * Copyright (c) 2006-2008, R Oudkerk - * Licensed to PSF under a Contributor Agreement. + * Copyright (c) 2006-2008, R Oudkerk --- see COPYING.txt */ #include "multiprocessing.h" @@ -14,11 +13,10 @@ enum { RECURSIVE_MUTEX, SEMAPHORE }; typedef struct { PyObject_HEAD SEM_HANDLE handle; - unsigned long last_tid; + long last_tid; int count; int maxvalue; int kind; - char *name; } SemLockObject; #define ISMINE(o) (o->count > 0 && PyThread_get_thread_ident() == o->last_tid) @@ -44,7 +42,7 @@ _GetSemaphoreValue(HANDLE handle, long *value) { long previous; - switch (WaitForSingleObjectEx(handle, 0, FALSE)) { + switch (WaitForSingleObject(handle, 0)) { case WAIT_OBJECT_0: if (!ReleaseSemaphore(handle, 1, &previous)) return MP_STANDARD_ERROR; @@ -64,8 +62,7 @@ semlock_acquire(SemLockObject *self, PyObject *args, PyObject *kwds) int blocking = 1; double timeout; PyObject *timeout_obj = Py_None; - DWORD res, full_msecs, nhandles; - HANDLE handles[2], sigint_event; + DWORD res, full_msecs, msecs, start, ticks; static char *kwlist[] = {"block", "timeout", NULL}; @@ -99,49 +96,59 @@ semlock_acquire(SemLockObject *self, PyObject *args, PyObject *kwds) Py_RETURN_TRUE; } - /* check whether we can acquire without releasing the GIL and blocking */ - if (WaitForSingleObjectEx(self->handle, 0, FALSE) == WAIT_OBJECT_0) { + /* check whether we can acquire without blocking */ + if (WaitForSingleObject(self->handle, 0) == WAIT_OBJECT_0) { self->last_tid = GetCurrentThreadId(); ++self->count; Py_RETURN_TRUE; } - /* prepare list of handles */ - nhandles = 0; - handles[nhandles++] = self->handle; - if (_PyOS_IsMainThread()) { - sigint_event = _PyOS_SigintEvent(); - assert(sigint_event != NULL); - handles[nhandles++] = sigint_event; - } - else { - sigint_event = NULL; - } + msecs = full_msecs; + start = GetTickCount(); + + for ( ; ; ) { + HANDLE handles[2] = {self->handle, sigint_event}; - /* do the wait */ - Py_BEGIN_ALLOW_THREADS - if (sigint_event != NULL) + /* do the wait */ + Py_BEGIN_ALLOW_THREADS ResetEvent(sigint_event); - res = WaitForMultipleObjectsEx(nhandles, handles, FALSE, full_msecs, FALSE); - Py_END_ALLOW_THREADS + res = WaitForMultipleObjects(2, handles, FALSE, msecs); + Py_END_ALLOW_THREADS + + /* handle result */ + if (res != WAIT_OBJECT_0 + 1) + break; + + /* got SIGINT so give signal handler a chance to run */ + Sleep(1); + + /* if this is main thread let KeyboardInterrupt be raised */ + if (PyErr_CheckSignals()) + return NULL; + + /* recalculate timeout */ + if (msecs != INFINITE) { + ticks = GetTickCount(); + if ((DWORD)(ticks - start) >= full_msecs) + Py_RETURN_FALSE; + msecs = full_msecs - (ticks - start); + } + } /* handle result */ switch (res) { case WAIT_TIMEOUT: Py_RETURN_FALSE; - case WAIT_OBJECT_0 + 0: + case WAIT_OBJECT_0: self->last_tid = GetCurrentThreadId(); ++self->count; Py_RETURN_TRUE; - case WAIT_OBJECT_0 + 1: - errno = EINTR; - return PyErr_SetFromErrno(PyExc_OSError); case WAIT_FAILED: return PyErr_SetFromWindowsErr(0); default: PyErr_Format(PyExc_RuntimeError, "WaitForSingleObject() or " "WaitForMultipleObjects() gave unrecognized " - "value %u", res); + "value %d", res); return NULL; } } @@ -204,7 +211,7 @@ semlock_release(SemLockObject *self, PyObject *args) #ifndef HAVE_SEM_TIMEDWAIT # define sem_timedwait(sem,deadline) sem_timedwait_save(sem,deadline,_save) -static int +int sem_timedwait_save(sem_t *sem, struct timespec *deadline, PyThreadState *_save) { int res; @@ -267,7 +274,7 @@ sem_timedwait_save(sem_t *sem, struct timespec *deadline, PyThreadState *_save) static PyObject * semlock_acquire(SemLockObject *self, PyObject *args, PyObject *kwds) { - int blocking = 1, res, err = 0; + int blocking = 1, res; double timeout; PyObject *timeout_obj = Py_None; struct timespec deadline = {0}; @@ -304,32 +311,20 @@ semlock_acquire(SemLockObject *self, PyObject *args, PyObject *kwds) deadline.tv_nsec %= 1000000000; } - /* Check whether we can acquire without releasing the GIL and blocking */ do { - res = sem_trywait(self->handle); - err = errno; + Py_BEGIN_ALLOW_THREADS + if (blocking && timeout_obj == Py_None) + res = sem_wait(self->handle); + else if (!blocking) + res = sem_trywait(self->handle); + else + res = sem_timedwait(self->handle, &deadline); + Py_END_ALLOW_THREADS + if (res == MP_EXCEPTION_HAS_BEEN_SET) + break; } while (res < 0 && errno == EINTR && !PyErr_CheckSignals()); - errno = err; - - if (res < 0 && errno == EAGAIN && blocking) { - /* Couldn't acquire immediately, need to block */ - do { - Py_BEGIN_ALLOW_THREADS - if (timeout_obj == Py_None) { - res = sem_wait(self->handle); - } - else { - res = sem_timedwait(self->handle, &deadline); - } - Py_END_ALLOW_THREADS - err = errno; - if (res == MP_EXCEPTION_HAS_BEEN_SET) - break; - } while (res < 0 && errno == EINTR && !PyErr_CheckSignals()); - } if (res < 0) { - errno = err; if (errno == EAGAIN || errno == ETIMEDOUT) Py_RETURN_FALSE; else if (errno == EINTR) @@ -411,8 +406,7 @@ semlock_release(SemLockObject *self, PyObject *args) */ static PyObject * -newsemlockobject(PyTypeObject *type, SEM_HANDLE handle, int kind, int maxvalue, - char *name) +newsemlockobject(PyTypeObject *type, SEM_HANDLE handle, int kind, int maxvalue) { SemLockObject *self; @@ -424,22 +418,21 @@ newsemlockobject(PyTypeObject *type, SEM_HANDLE handle, int kind, int maxvalue, self->count = 0; self->last_tid = 0; self->maxvalue = maxvalue; - self->name = name; return (PyObject*)self; } static PyObject * semlock_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { + char buffer[256]; SEM_HANDLE handle = SEM_FAILED; - int kind, maxvalue, value, unlink; + int kind, maxvalue, value; PyObject *result; - char *name, *name_copy = NULL; - static char *kwlist[] = {"kind", "value", "maxvalue", "name", "unlink", - NULL}; + static char *kwlist[] = {"kind", "value", "maxvalue", NULL}; + int try = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "iiisi", kwlist, - &kind, &value, &maxvalue, &name, &unlink)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "iii", kwlist, + &kind, &value, &maxvalue)) return NULL; if (kind != RECURSIVE_MUTEX && kind != SEMAPHORE) { @@ -447,24 +440,26 @@ semlock_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return NULL; } - if (!unlink) { - name_copy = PyMem_Malloc(strlen(name) + 1); - if (name_copy == NULL) { - return PyErr_NoMemory(); - } - strcpy(name_copy, name); - } + /* Create a semaphore with a unique name. The bytes returned by + * _PyOS_URandom() are treated as unsigned long to ensure that the filename + * is valid (no special characters). */ + do { + unsigned long suffix; + _PyOS_URandom((char *)&suffix, sizeof(suffix)); + PyOS_snprintf(buffer, sizeof(buffer), "/mp%ld-%lu", (long)getpid(), + suffix); + SEM_CLEAR_ERROR(); + handle = SEM_CREATE(buffer, value, maxvalue); + } while ((handle == SEM_FAILED) && (errno == EEXIST) && (++try < 100)); - SEM_CLEAR_ERROR(); - handle = SEM_CREATE(name, value, maxvalue); /* On Windows we should fail if GetLastError()==ERROR_ALREADY_EXISTS */ if (handle == SEM_FAILED || SEM_GET_LAST_ERROR() != 0) goto failure; - if (unlink && SEM_UNLINK(name) < 0) + if (SEM_UNLINK(buffer) < 0) goto failure; - result = newsemlockobject(type, handle, kind, maxvalue, name_copy); + result = newsemlockobject(type, handle, kind, maxvalue); if (!result) goto failure; @@ -473,10 +468,7 @@ semlock_new(PyTypeObject *type, PyObject *args, PyObject *kwds) failure: if (handle != SEM_FAILED) SEM_CLOSE(handle); - PyMem_Free(name_copy); - if (!PyErr_Occurred()) { - _PyMp_SetError(NULL, MP_STANDARD_ERROR); - } + mp_SetError(NULL, MP_STANDARD_ERROR); return NULL; } @@ -485,30 +477,12 @@ semlock_rebuild(PyTypeObject *type, PyObject *args) { SEM_HANDLE handle; int kind, maxvalue; - char *name, *name_copy = NULL; - if (!PyArg_ParseTuple(args, F_SEM_HANDLE "iiz", - &handle, &kind, &maxvalue, &name)) + if (!PyArg_ParseTuple(args, F_SEM_HANDLE "ii", + &handle, &kind, &maxvalue)) return NULL; - if (name != NULL) { - name_copy = PyMem_Malloc(strlen(name) + 1); - if (name_copy == NULL) - return PyErr_NoMemory(); - strcpy(name_copy, name); - } - -#ifndef MS_WINDOWS - if (name != NULL) { - handle = sem_open(name, 0); - if (handle == SEM_FAILED) { - PyMem_Free(name_copy); - return PyErr_SetFromErrno(PyExc_OSError); - } - } -#endif - - return newsemlockobject(type, handle, kind, maxvalue, name_copy); + return newsemlockobject(type, handle, kind, maxvalue); } static void @@ -516,25 +490,24 @@ semlock_dealloc(SemLockObject* self) { if (self->handle != SEM_FAILED) SEM_CLOSE(self->handle); - PyMem_Free(self->name); PyObject_Del(self); } static PyObject * -semlock_count(SemLockObject *self, PyObject *Py_UNUSED(ignored)) +semlock_count(SemLockObject *self) { - return PyLong_FromLong((long)self->count); + return PyInt_FromLong((long)self->count); } static PyObject * -semlock_ismine(SemLockObject *self, PyObject *Py_UNUSED(ignored)) +semlock_ismine(SemLockObject *self) { /* only makes sense for a lock */ return PyBool_FromLong(ISMINE(self)); } static PyObject * -semlock_getvalue(SemLockObject *self, PyObject *Py_UNUSED(ignored)) +semlock_getvalue(SemLockObject *self) { #ifdef HAVE_BROKEN_SEM_GETVALUE PyErr_SetNone(PyExc_NotImplementedError); @@ -542,38 +515,38 @@ semlock_getvalue(SemLockObject *self, PyObject *Py_UNUSED(ignored)) #else int sval; if (SEM_GETVALUE(self->handle, &sval) < 0) - return _PyMp_SetError(NULL, MP_STANDARD_ERROR); + return mp_SetError(NULL, MP_STANDARD_ERROR); /* some posix implementations use negative numbers to indicate the number of waiting threads */ if (sval < 0) sval = 0; - return PyLong_FromLong((long)sval); + return PyInt_FromLong((long)sval); #endif } static PyObject * -semlock_iszero(SemLockObject *self, PyObject *Py_UNUSED(ignored)) +semlock_iszero(SemLockObject *self) { #ifdef HAVE_BROKEN_SEM_GETVALUE if (sem_trywait(self->handle) < 0) { if (errno == EAGAIN) Py_RETURN_TRUE; - return _PyMp_SetError(NULL, MP_STANDARD_ERROR); + return mp_SetError(NULL, MP_STANDARD_ERROR); } else { if (sem_post(self->handle) < 0) - return _PyMp_SetError(NULL, MP_STANDARD_ERROR); + return mp_SetError(NULL, MP_STANDARD_ERROR); Py_RETURN_FALSE; } #else int sval; if (SEM_GETVALUE(self->handle, &sval) < 0) - return _PyMp_SetError(NULL, MP_STANDARD_ERROR); + return mp_SetError(NULL, MP_STANDARD_ERROR); return PyBool_FromLong((long)sval == 0); #endif } static PyObject * -semlock_afterfork(SemLockObject *self, PyObject *Py_UNUSED(ignored)) +semlock_afterfork(SemLockObject *self) { self->count = 0; Py_RETURN_NONE; @@ -584,11 +557,11 @@ semlock_afterfork(SemLockObject *self, PyObject *Py_UNUSED(ignored)) */ static PyMethodDef semlock_methods[] = { - {"acquire", (PyCFunction)(void(*)(void))semlock_acquire, METH_VARARGS | METH_KEYWORDS, + {"acquire", (PyCFunction)semlock_acquire, METH_VARARGS | METH_KEYWORDS, "acquire the semaphore/lock"}, {"release", (PyCFunction)semlock_release, METH_NOARGS, "release the semaphore/lock"}, - {"__enter__", (PyCFunction)(void(*)(void))semlock_acquire, METH_VARARGS | METH_KEYWORDS, + {"__enter__", (PyCFunction)semlock_acquire, METH_VARARGS | METH_KEYWORDS, "enter the semaphore/lock"}, {"__exit__", (PyCFunction)semlock_release, METH_VARARGS, "exit the semaphore/lock"}, @@ -618,8 +591,6 @@ static PyMemberDef semlock_members[] = { ""}, {"maxvalue", T_INT, offsetof(SemLockObject, maxvalue), READONLY, ""}, - {"name", T_STRING, offsetof(SemLockObject, name), READONLY, - ""}, {NULL} }; @@ -627,16 +598,16 @@ static PyMemberDef semlock_members[] = { * Semaphore type */ -PyTypeObject _PyMp_SemLockType = { +PyTypeObject SemLockType = { PyVarObject_HEAD_INIT(NULL, 0) /* tp_name */ "_multiprocessing.SemLock", /* tp_basicsize */ sizeof(SemLockObject), /* tp_itemsize */ 0, /* tp_dealloc */ (destructor)semlock_dealloc, - /* tp_vectorcall_offset */ 0, + /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, - /* tp_as_async */ 0, + /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, @@ -667,23 +638,3 @@ PyTypeObject _PyMp_SemLockType = { /* tp_alloc */ 0, /* tp_new */ semlock_new, }; - -/* - * Function to unlink semaphore names - */ - -PyObject * -_PyMp_sem_unlink(PyObject *ignore, PyObject *args) -{ - char *name; - - if (!PyArg_ParseTuple(args, "s", &name)) - return NULL; - - if (SEM_UNLINK(name) < 0) { - _PyMp_SetError(NULL, MP_STANDARD_ERROR); - return NULL; - } - - Py_RETURN_NONE; -} |