summaryrefslogtreecommitdiffstats
path: root/Modules/_multiprocessing/semaphore.c
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/_multiprocessing/semaphore.c')
-rw-r--r--Modules/_multiprocessing/semaphore.c227
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;
-}