blob: 8ea92f2b588ee1545b8132f20fb8c2731cfe4fa7 [file] [log] [blame]
Benjamin Petersone711caf2008-06-11 16:44:04 +00001/*
2 * A type which wraps a semaphore
3 *
4 * semaphore.c
5 *
Richard Oudkerk3e268aa2012-04-30 12:13:55 +01006 * Copyright (c) 2006-2008, R Oudkerk
7 * Licensed to PSF under a Contributor Agreement.
Benjamin Petersone711caf2008-06-11 16:44:04 +00008 */
9
10#include "multiprocessing.h"
11
12enum { RECURSIVE_MUTEX, SEMAPHORE };
13
14typedef struct {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000015 PyObject_HEAD
16 SEM_HANDLE handle;
17 long last_tid;
18 int count;
19 int maxvalue;
20 int kind;
Benjamin Petersone711caf2008-06-11 16:44:04 +000021} SemLockObject;
22
23#define ISMINE(o) (o->count > 0 && PyThread_get_thread_ident() == o->last_tid)
24
25
26#ifdef MS_WINDOWS
27
28/*
29 * Windows definitions
30 */
31
32#define SEM_FAILED NULL
33
34#define SEM_CLEAR_ERROR() SetLastError(0)
35#define SEM_GET_LAST_ERROR() GetLastError()
36#define SEM_CREATE(name, val, max) CreateSemaphore(NULL, val, max, NULL)
37#define SEM_CLOSE(sem) (CloseHandle(sem) ? 0 : -1)
38#define SEM_GETVALUE(sem, pval) _GetSemaphoreValue(sem, pval)
39#define SEM_UNLINK(name) 0
40
41static int
42_GetSemaphoreValue(HANDLE handle, long *value)
43{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000044 long previous;
Benjamin Petersone711caf2008-06-11 16:44:04 +000045
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000046 switch (WaitForSingleObject(handle, 0)) {
47 case WAIT_OBJECT_0:
48 if (!ReleaseSemaphore(handle, 1, &previous))
49 return MP_STANDARD_ERROR;
50 *value = previous + 1;
51 return 0;
52 case WAIT_TIMEOUT:
53 *value = 0;
54 return 0;
55 default:
56 return MP_STANDARD_ERROR;
57 }
Benjamin Petersone711caf2008-06-11 16:44:04 +000058}
59
60static PyObject *
61semlock_acquire(SemLockObject *self, PyObject *args, PyObject *kwds)
62{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000063 int blocking = 1;
64 double timeout;
65 PyObject *timeout_obj = Py_None;
Antoine Pitrou6dd381e2011-11-21 21:26:56 +010066 DWORD res, full_msecs, nhandles;
67 HANDLE handles[2], sigint_event;
Benjamin Petersone711caf2008-06-11 16:44:04 +000068
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000069 static char *kwlist[] = {"block", "timeout", NULL};
Benjamin Petersone711caf2008-06-11 16:44:04 +000070
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000071 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iO", kwlist,
72 &blocking, &timeout_obj))
73 return NULL;
Benjamin Petersone711caf2008-06-11 16:44:04 +000074
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000075 /* calculate timeout */
76 if (!blocking) {
77 full_msecs = 0;
78 } else if (timeout_obj == Py_None) {
79 full_msecs = INFINITE;
80 } else {
81 timeout = PyFloat_AsDouble(timeout_obj);
82 if (PyErr_Occurred())
83 return NULL;
84 timeout *= 1000.0; /* convert to millisecs */
85 if (timeout < 0.0) {
86 timeout = 0.0;
87 } else if (timeout >= 0.5 * INFINITE) { /* 25 days */
88 PyErr_SetString(PyExc_OverflowError,
89 "timeout is too large");
90 return NULL;
91 }
92 full_msecs = (DWORD)(timeout + 0.5);
93 }
Benjamin Petersone711caf2008-06-11 16:44:04 +000094
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000095 /* check whether we already own the lock */
96 if (self->kind == RECURSIVE_MUTEX && ISMINE(self)) {
97 ++self->count;
98 Py_RETURN_TRUE;
99 }
Benjamin Petersone711caf2008-06-11 16:44:04 +0000100
Antoine Pitrou6dd381e2011-11-21 21:26:56 +0100101 /* check whether we can acquire without releasing the GIL and blocking */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000102 if (WaitForSingleObject(self->handle, 0) == WAIT_OBJECT_0) {
103 self->last_tid = GetCurrentThreadId();
104 ++self->count;
105 Py_RETURN_TRUE;
106 }
107
Antoine Pitrou6dd381e2011-11-21 21:26:56 +0100108 /* prepare list of handles */
109 nhandles = 0;
110 handles[nhandles++] = self->handle;
111 if (_PyOS_IsMainThread()) {
112 sigint_event = _PyOS_SigintEvent();
113 assert(sigint_event != NULL);
114 handles[nhandles++] = sigint_event;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000115 }
116
Antoine Pitrou6dd381e2011-11-21 21:26:56 +0100117 /* do the wait */
118 Py_BEGIN_ALLOW_THREADS
119 if (sigint_event != NULL)
120 ResetEvent(sigint_event);
121 res = WaitForMultipleObjects(nhandles, handles, FALSE, full_msecs);
122 Py_END_ALLOW_THREADS
123
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000124 /* handle result */
125 switch (res) {
126 case WAIT_TIMEOUT:
127 Py_RETURN_FALSE;
Antoine Pitrou6dd381e2011-11-21 21:26:56 +0100128 case WAIT_OBJECT_0 + 0:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000129 self->last_tid = GetCurrentThreadId();
130 ++self->count;
131 Py_RETURN_TRUE;
Antoine Pitrou6dd381e2011-11-21 21:26:56 +0100132 case WAIT_OBJECT_0 + 1:
133 errno = EINTR;
134 return PyErr_SetFromErrno(PyExc_IOError);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000135 case WAIT_FAILED:
136 return PyErr_SetFromWindowsErr(0);
137 default:
138 PyErr_Format(PyExc_RuntimeError, "WaitForSingleObject() or "
139 "WaitForMultipleObjects() gave unrecognized "
140 "value %d", res);
141 return NULL;
142 }
Benjamin Petersone711caf2008-06-11 16:44:04 +0000143}
144
145static PyObject *
146semlock_release(SemLockObject *self, PyObject *args)
147{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000148 if (self->kind == RECURSIVE_MUTEX) {
149 if (!ISMINE(self)) {
150 PyErr_SetString(PyExc_AssertionError, "attempt to "
151 "release recursive lock not owned "
152 "by thread");
153 return NULL;
154 }
155 if (self->count > 1) {
156 --self->count;
157 Py_RETURN_NONE;
158 }
159 assert(self->count == 1);
160 }
Benjamin Petersone711caf2008-06-11 16:44:04 +0000161
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000162 if (!ReleaseSemaphore(self->handle, 1, NULL)) {
163 if (GetLastError() == ERROR_TOO_MANY_POSTS) {
164 PyErr_SetString(PyExc_ValueError, "semaphore or lock "
165 "released too many times");
166 return NULL;
167 } else {
168 return PyErr_SetFromWindowsErr(0);
169 }
170 }
Benjamin Petersone711caf2008-06-11 16:44:04 +0000171
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000172 --self->count;
173 Py_RETURN_NONE;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000174}
175
176#else /* !MS_WINDOWS */
177
178/*
179 * Unix definitions
180 */
181
182#define SEM_CLEAR_ERROR()
183#define SEM_GET_LAST_ERROR() 0
184#define SEM_CREATE(name, val, max) sem_open(name, O_CREAT | O_EXCL, 0600, val)
185#define SEM_CLOSE(sem) sem_close(sem)
186#define SEM_GETVALUE(sem, pval) sem_getvalue(sem, pval)
187#define SEM_UNLINK(name) sem_unlink(name)
188
Benjamin Peterson965ce872009-04-05 21:24:58 +0000189#ifndef HAVE_SEM_UNLINK
Benjamin Petersone711caf2008-06-11 16:44:04 +0000190# define sem_unlink(name) 0
191#endif
192
Benjamin Peterson965ce872009-04-05 21:24:58 +0000193#ifndef HAVE_SEM_TIMEDWAIT
Benjamin Petersone711caf2008-06-11 16:44:04 +0000194# define sem_timedwait(sem,deadline) sem_timedwait_save(sem,deadline,_save)
195
196int
197sem_timedwait_save(sem_t *sem, struct timespec *deadline, PyThreadState *_save)
198{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000199 int res;
200 unsigned long delay, difference;
201 struct timeval now, tvdeadline, tvdelay;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000202
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000203 errno = 0;
204 tvdeadline.tv_sec = deadline->tv_sec;
205 tvdeadline.tv_usec = deadline->tv_nsec / 1000;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000206
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000207 for (delay = 0 ; ; delay += 1000) {
208 /* poll */
209 if (sem_trywait(sem) == 0)
210 return 0;
211 else if (errno != EAGAIN)
212 return MP_STANDARD_ERROR;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000213
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000214 /* get current time */
215 if (gettimeofday(&now, NULL) < 0)
216 return MP_STANDARD_ERROR;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000217
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000218 /* check for timeout */
219 if (tvdeadline.tv_sec < now.tv_sec ||
220 (tvdeadline.tv_sec == now.tv_sec &&
221 tvdeadline.tv_usec <= now.tv_usec)) {
222 errno = ETIMEDOUT;
223 return MP_STANDARD_ERROR;
224 }
Benjamin Petersone711caf2008-06-11 16:44:04 +0000225
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000226 /* calculate how much time is left */
227 difference = (tvdeadline.tv_sec - now.tv_sec) * 1000000 +
228 (tvdeadline.tv_usec - now.tv_usec);
Benjamin Petersone711caf2008-06-11 16:44:04 +0000229
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000230 /* check delay not too long -- maximum is 20 msecs */
231 if (delay > 20000)
232 delay = 20000;
233 if (delay > difference)
234 delay = difference;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000235
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000236 /* sleep */
237 tvdelay.tv_sec = delay / 1000000;
238 tvdelay.tv_usec = delay % 1000000;
239 if (select(0, NULL, NULL, NULL, &tvdelay) < 0)
240 return MP_STANDARD_ERROR;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000241
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000242 /* check for signals */
243 Py_BLOCK_THREADS
244 res = PyErr_CheckSignals();
245 Py_UNBLOCK_THREADS
Benjamin Petersone711caf2008-06-11 16:44:04 +0000246
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000247 if (res) {
248 errno = EINTR;
249 return MP_EXCEPTION_HAS_BEEN_SET;
250 }
251 }
Benjamin Petersone711caf2008-06-11 16:44:04 +0000252}
253
254#endif /* !HAVE_SEM_TIMEDWAIT */
255
256static PyObject *
257semlock_acquire(SemLockObject *self, PyObject *args, PyObject *kwds)
258{
Antoine Pitrouc345ce12011-12-16 12:28:32 +0100259 int blocking = 1, res, err = 0;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000260 double timeout;
261 PyObject *timeout_obj = Py_None;
262 struct timespec deadline = {0};
263 struct timeval now;
264 long sec, nsec;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000265
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000266 static char *kwlist[] = {"block", "timeout", NULL};
Benjamin Petersone711caf2008-06-11 16:44:04 +0000267
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000268 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iO", kwlist,
269 &blocking, &timeout_obj))
270 return NULL;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000271
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000272 if (self->kind == RECURSIVE_MUTEX && ISMINE(self)) {
273 ++self->count;
274 Py_RETURN_TRUE;
275 }
Benjamin Petersone711caf2008-06-11 16:44:04 +0000276
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000277 if (timeout_obj != Py_None) {
278 timeout = PyFloat_AsDouble(timeout_obj);
279 if (PyErr_Occurred())
280 return NULL;
281 if (timeout < 0.0)
282 timeout = 0.0;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000283
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000284 if (gettimeofday(&now, NULL) < 0) {
285 PyErr_SetFromErrno(PyExc_OSError);
286 return NULL;
287 }
288 sec = (long) timeout;
289 nsec = (long) (1e9 * (timeout - sec) + 0.5);
290 deadline.tv_sec = now.tv_sec + sec;
291 deadline.tv_nsec = now.tv_usec * 1000 + nsec;
292 deadline.tv_sec += (deadline.tv_nsec / 1000000000);
293 deadline.tv_nsec %= 1000000000;
294 }
Benjamin Petersone711caf2008-06-11 16:44:04 +0000295
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000296 do {
297 Py_BEGIN_ALLOW_THREADS
298 if (blocking && timeout_obj == Py_None)
299 res = sem_wait(self->handle);
300 else if (!blocking)
301 res = sem_trywait(self->handle);
302 else
303 res = sem_timedwait(self->handle, &deadline);
304 Py_END_ALLOW_THREADS
Antoine Pitrouc345ce12011-12-16 12:28:32 +0100305 err = errno;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000306 if (res == MP_EXCEPTION_HAS_BEEN_SET)
307 break;
308 } while (res < 0 && errno == EINTR && !PyErr_CheckSignals());
Benjamin Petersone711caf2008-06-11 16:44:04 +0000309
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000310 if (res < 0) {
Antoine Pitrouc345ce12011-12-16 12:28:32 +0100311 errno = err;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000312 if (errno == EAGAIN || errno == ETIMEDOUT)
313 Py_RETURN_FALSE;
314 else if (errno == EINTR)
315 return NULL;
316 else
317 return PyErr_SetFromErrno(PyExc_OSError);
318 }
Benjamin Petersone711caf2008-06-11 16:44:04 +0000319
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000320 ++self->count;
321 self->last_tid = PyThread_get_thread_ident();
Benjamin Petersone711caf2008-06-11 16:44:04 +0000322
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000323 Py_RETURN_TRUE;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000324}
325
326static PyObject *
327semlock_release(SemLockObject *self, PyObject *args)
328{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000329 if (self->kind == RECURSIVE_MUTEX) {
330 if (!ISMINE(self)) {
331 PyErr_SetString(PyExc_AssertionError, "attempt to "
332 "release recursive lock not owned "
333 "by thread");
334 return NULL;
335 }
336 if (self->count > 1) {
337 --self->count;
338 Py_RETURN_NONE;
339 }
340 assert(self->count == 1);
341 } else {
Benjamin Peterson965ce872009-04-05 21:24:58 +0000342#ifdef HAVE_BROKEN_SEM_GETVALUE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000343 /* We will only check properly the maxvalue == 1 case */
344 if (self->maxvalue == 1) {
345 /* make sure that already locked */
346 if (sem_trywait(self->handle) < 0) {
347 if (errno != EAGAIN) {
348 PyErr_SetFromErrno(PyExc_OSError);
349 return NULL;
350 }
351 /* it is already locked as expected */
352 } else {
353 /* it was not locked so undo wait and raise */
354 if (sem_post(self->handle) < 0) {
355 PyErr_SetFromErrno(PyExc_OSError);
356 return NULL;
357 }
358 PyErr_SetString(PyExc_ValueError, "semaphore "
359 "or lock released too many "
360 "times");
361 return NULL;
362 }
363 }
Benjamin Petersone711caf2008-06-11 16:44:04 +0000364#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000365 int sval;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000366
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000367 /* This check is not an absolute guarantee that the semaphore
368 does not rise above maxvalue. */
369 if (sem_getvalue(self->handle, &sval) < 0) {
370 return PyErr_SetFromErrno(PyExc_OSError);
371 } else if (sval >= self->maxvalue) {
372 PyErr_SetString(PyExc_ValueError, "semaphore or lock "
373 "released too many times");
374 return NULL;
375 }
Benjamin Petersone711caf2008-06-11 16:44:04 +0000376#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000377 }
Benjamin Petersone711caf2008-06-11 16:44:04 +0000378
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000379 if (sem_post(self->handle) < 0)
380 return PyErr_SetFromErrno(PyExc_OSError);
Benjamin Petersone711caf2008-06-11 16:44:04 +0000381
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000382 --self->count;
383 Py_RETURN_NONE;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000384}
385
386#endif /* !MS_WINDOWS */
387
388/*
389 * All platforms
390 */
391
392static PyObject *
393newsemlockobject(PyTypeObject *type, SEM_HANDLE handle, int kind, int maxvalue)
394{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000395 SemLockObject *self;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000396
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000397 self = PyObject_New(SemLockObject, type);
398 if (!self)
399 return NULL;
400 self->handle = handle;
401 self->kind = kind;
402 self->count = 0;
403 self->last_tid = 0;
404 self->maxvalue = maxvalue;
405 return (PyObject*)self;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000406}
407
408static PyObject *
409semlock_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
410{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000411 char buffer[256];
412 SEM_HANDLE handle = SEM_FAILED;
413 int kind, maxvalue, value;
414 PyObject *result;
415 static char *kwlist[] = {"kind", "value", "maxvalue", NULL};
416 static int counter = 0;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000417
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000418 if (!PyArg_ParseTupleAndKeywords(args, kwds, "iii", kwlist,
419 &kind, &value, &maxvalue))
420 return NULL;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000421
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000422 if (kind != RECURSIVE_MUTEX && kind != SEMAPHORE) {
423 PyErr_SetString(PyExc_ValueError, "unrecognized kind");
424 return NULL;
425 }
Benjamin Petersone711caf2008-06-11 16:44:04 +0000426
Georg Brandlc7f4af42010-10-18 05:06:18 +0000427 PyOS_snprintf(buffer, sizeof(buffer), "/mp%ld-%d", (long)getpid(), counter++);
Benjamin Petersone711caf2008-06-11 16:44:04 +0000428
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000429 SEM_CLEAR_ERROR();
430 handle = SEM_CREATE(buffer, value, maxvalue);
431 /* On Windows we should fail if GetLastError()==ERROR_ALREADY_EXISTS */
432 if (handle == SEM_FAILED || SEM_GET_LAST_ERROR() != 0)
433 goto failure;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000434
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000435 if (SEM_UNLINK(buffer) < 0)
436 goto failure;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000437
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000438 result = newsemlockobject(type, handle, kind, maxvalue);
439 if (!result)
440 goto failure;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000441
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000442 return result;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000443
444 failure:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000445 if (handle != SEM_FAILED)
446 SEM_CLOSE(handle);
447 mp_SetError(NULL, MP_STANDARD_ERROR);
448 return NULL;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000449}
450
451static PyObject *
452semlock_rebuild(PyTypeObject *type, PyObject *args)
453{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000454 SEM_HANDLE handle;
455 int kind, maxvalue;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000456
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000457 if (!PyArg_ParseTuple(args, F_SEM_HANDLE "ii",
458 &handle, &kind, &maxvalue))
459 return NULL;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000460
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000461 return newsemlockobject(type, handle, kind, maxvalue);
Benjamin Petersone711caf2008-06-11 16:44:04 +0000462}
463
464static void
465semlock_dealloc(SemLockObject* self)
466{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000467 if (self->handle != SEM_FAILED)
468 SEM_CLOSE(self->handle);
469 PyObject_Del(self);
Benjamin Petersone711caf2008-06-11 16:44:04 +0000470}
471
472static PyObject *
473semlock_count(SemLockObject *self)
474{
Antoine Pitrou2341f9b2011-05-09 20:55:03 +0200475 return PyLong_FromLong((long)self->count);
Benjamin Petersone711caf2008-06-11 16:44:04 +0000476}
477
478static PyObject *
479semlock_ismine(SemLockObject *self)
480{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000481 /* only makes sense for a lock */
482 return PyBool_FromLong(ISMINE(self));
Benjamin Petersone711caf2008-06-11 16:44:04 +0000483}
484
485static PyObject *
486semlock_getvalue(SemLockObject *self)
487{
Benjamin Peterson965ce872009-04-05 21:24:58 +0000488#ifdef HAVE_BROKEN_SEM_GETVALUE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000489 PyErr_SetNone(PyExc_NotImplementedError);
490 return NULL;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000491#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000492 int sval;
493 if (SEM_GETVALUE(self->handle, &sval) < 0)
494 return mp_SetError(NULL, MP_STANDARD_ERROR);
495 /* some posix implementations use negative numbers to indicate
496 the number of waiting threads */
497 if (sval < 0)
498 sval = 0;
Antoine Pitrou2341f9b2011-05-09 20:55:03 +0200499 return PyLong_FromLong((long)sval);
Benjamin Petersone711caf2008-06-11 16:44:04 +0000500#endif
501}
502
503static PyObject *
504semlock_iszero(SemLockObject *self)
505{
Benjamin Peterson965ce872009-04-05 21:24:58 +0000506#ifdef HAVE_BROKEN_SEM_GETVALUE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000507 if (sem_trywait(self->handle) < 0) {
508 if (errno == EAGAIN)
509 Py_RETURN_TRUE;
510 return mp_SetError(NULL, MP_STANDARD_ERROR);
511 } else {
512 if (sem_post(self->handle) < 0)
513 return mp_SetError(NULL, MP_STANDARD_ERROR);
514 Py_RETURN_FALSE;
515 }
Benjamin Petersone711caf2008-06-11 16:44:04 +0000516#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000517 int sval;
518 if (SEM_GETVALUE(self->handle, &sval) < 0)
519 return mp_SetError(NULL, MP_STANDARD_ERROR);
520 return PyBool_FromLong((long)sval == 0);
Benjamin Petersone711caf2008-06-11 16:44:04 +0000521#endif
522}
523
524static PyObject *
525semlock_afterfork(SemLockObject *self)
526{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000527 self->count = 0;
528 Py_RETURN_NONE;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000529}
530
531/*
532 * Semaphore methods
533 */
534
535static PyMethodDef semlock_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000536 {"acquire", (PyCFunction)semlock_acquire, METH_VARARGS | METH_KEYWORDS,
537 "acquire the semaphore/lock"},
538 {"release", (PyCFunction)semlock_release, METH_NOARGS,
539 "release the semaphore/lock"},
Jesse Nollerf8d00852009-03-31 03:25:07 +0000540 {"__enter__", (PyCFunction)semlock_acquire, METH_VARARGS | METH_KEYWORDS,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000541 "enter the semaphore/lock"},
542 {"__exit__", (PyCFunction)semlock_release, METH_VARARGS,
543 "exit the semaphore/lock"},
544 {"_count", (PyCFunction)semlock_count, METH_NOARGS,
545 "num of `acquire()`s minus num of `release()`s for this process"},
546 {"_is_mine", (PyCFunction)semlock_ismine, METH_NOARGS,
547 "whether the lock is owned by this thread"},
548 {"_get_value", (PyCFunction)semlock_getvalue, METH_NOARGS,
549 "get the value of the semaphore"},
550 {"_is_zero", (PyCFunction)semlock_iszero, METH_NOARGS,
551 "returns whether semaphore has value zero"},
552 {"_rebuild", (PyCFunction)semlock_rebuild, METH_VARARGS | METH_CLASS,
553 ""},
554 {"_after_fork", (PyCFunction)semlock_afterfork, METH_NOARGS,
555 "rezero the net acquisition count after fork()"},
556 {NULL}
Benjamin Petersone711caf2008-06-11 16:44:04 +0000557};
558
559/*
560 * Member table
561 */
562
563static PyMemberDef semlock_members[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000564 {"handle", T_SEM_HANDLE, offsetof(SemLockObject, handle), READONLY,
565 ""},
566 {"kind", T_INT, offsetof(SemLockObject, kind), READONLY,
567 ""},
568 {"maxvalue", T_INT, offsetof(SemLockObject, maxvalue), READONLY,
569 ""},
570 {NULL}
Benjamin Petersone711caf2008-06-11 16:44:04 +0000571};
572
573/*
574 * Semaphore type
575 */
576
577PyTypeObject SemLockType = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000578 PyVarObject_HEAD_INIT(NULL, 0)
579 /* tp_name */ "_multiprocessing.SemLock",
580 /* tp_basicsize */ sizeof(SemLockObject),
581 /* tp_itemsize */ 0,
582 /* tp_dealloc */ (destructor)semlock_dealloc,
583 /* tp_print */ 0,
584 /* tp_getattr */ 0,
585 /* tp_setattr */ 0,
586 /* tp_reserved */ 0,
587 /* tp_repr */ 0,
588 /* tp_as_number */ 0,
589 /* tp_as_sequence */ 0,
590 /* tp_as_mapping */ 0,
591 /* tp_hash */ 0,
592 /* tp_call */ 0,
593 /* tp_str */ 0,
594 /* tp_getattro */ 0,
595 /* tp_setattro */ 0,
596 /* tp_as_buffer */ 0,
597 /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
598 /* tp_doc */ "Semaphore/Mutex type",
599 /* tp_traverse */ 0,
600 /* tp_clear */ 0,
601 /* tp_richcompare */ 0,
602 /* tp_weaklistoffset */ 0,
603 /* tp_iter */ 0,
604 /* tp_iternext */ 0,
605 /* tp_methods */ semlock_methods,
606 /* tp_members */ semlock_members,
607 /* tp_getset */ 0,
608 /* tp_base */ 0,
609 /* tp_dict */ 0,
610 /* tp_descr_get */ 0,
611 /* tp_descr_set */ 0,
612 /* tp_dictoffset */ 0,
613 /* tp_init */ 0,
614 /* tp_alloc */ 0,
615 /* tp_new */ semlock_new,
Benjamin Petersone711caf2008-06-11 16:44:04 +0000616};