blob: dcf3b42bc108e446ad479cd3f865e530a61f4b72 [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
Martin v. Löwisb26a9b12013-01-25 14:25:48 +010046 switch (WaitForSingleObjectEx(handle, 0, FALSE)) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000047 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 */
Martin v. Löwisb26a9b12013-01-25 14:25:48 +0100102 if (WaitForSingleObjectEx(self->handle, 0, FALSE) == WAIT_OBJECT_0) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000103 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);
Martin v. Löwisc8c65632013-01-25 14:29:13 +0100121 res = WaitForMultipleObjectsEx(nhandles, handles, FALSE, full_msecs, FALSE);
Antoine Pitrou6dd381e2011-11-21 21:26:56 +0100122 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
Richard Oudkerk98662312013-01-01 17:29:44 +0000189/* OS X 10.4 defines SEM_FAILED as -1 instead of (sem_t *)-1; this gives
190 compiler warnings, and (potentially) undefined behaviour. */
191#ifdef __APPLE__
192# undef SEM_FAILED
193# define SEM_FAILED ((sem_t *)-1)
194#endif
195
Benjamin Peterson965ce872009-04-05 21:24:58 +0000196#ifndef HAVE_SEM_UNLINK
Benjamin Petersone711caf2008-06-11 16:44:04 +0000197# define sem_unlink(name) 0
198#endif
199
Benjamin Peterson965ce872009-04-05 21:24:58 +0000200#ifndef HAVE_SEM_TIMEDWAIT
Benjamin Petersone711caf2008-06-11 16:44:04 +0000201# define sem_timedwait(sem,deadline) sem_timedwait_save(sem,deadline,_save)
202
Richard Oudkerk8fb9f4c2012-10-07 18:08:47 +0100203static int
Benjamin Petersone711caf2008-06-11 16:44:04 +0000204sem_timedwait_save(sem_t *sem, struct timespec *deadline, PyThreadState *_save)
205{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000206 int res;
207 unsigned long delay, difference;
208 struct timeval now, tvdeadline, tvdelay;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000209
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000210 errno = 0;
211 tvdeadline.tv_sec = deadline->tv_sec;
212 tvdeadline.tv_usec = deadline->tv_nsec / 1000;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000213
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000214 for (delay = 0 ; ; delay += 1000) {
215 /* poll */
216 if (sem_trywait(sem) == 0)
217 return 0;
218 else if (errno != EAGAIN)
219 return MP_STANDARD_ERROR;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000220
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000221 /* get current time */
222 if (gettimeofday(&now, NULL) < 0)
223 return MP_STANDARD_ERROR;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000224
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000225 /* check for timeout */
226 if (tvdeadline.tv_sec < now.tv_sec ||
227 (tvdeadline.tv_sec == now.tv_sec &&
228 tvdeadline.tv_usec <= now.tv_usec)) {
229 errno = ETIMEDOUT;
230 return MP_STANDARD_ERROR;
231 }
Benjamin Petersone711caf2008-06-11 16:44:04 +0000232
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000233 /* calculate how much time is left */
234 difference = (tvdeadline.tv_sec - now.tv_sec) * 1000000 +
235 (tvdeadline.tv_usec - now.tv_usec);
Benjamin Petersone711caf2008-06-11 16:44:04 +0000236
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000237 /* check delay not too long -- maximum is 20 msecs */
238 if (delay > 20000)
239 delay = 20000;
240 if (delay > difference)
241 delay = difference;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000242
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000243 /* sleep */
244 tvdelay.tv_sec = delay / 1000000;
245 tvdelay.tv_usec = delay % 1000000;
246 if (select(0, NULL, NULL, NULL, &tvdelay) < 0)
247 return MP_STANDARD_ERROR;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000248
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000249 /* check for signals */
250 Py_BLOCK_THREADS
251 res = PyErr_CheckSignals();
252 Py_UNBLOCK_THREADS
Benjamin Petersone711caf2008-06-11 16:44:04 +0000253
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000254 if (res) {
255 errno = EINTR;
256 return MP_EXCEPTION_HAS_BEEN_SET;
257 }
258 }
Benjamin Petersone711caf2008-06-11 16:44:04 +0000259}
260
261#endif /* !HAVE_SEM_TIMEDWAIT */
262
263static PyObject *
264semlock_acquire(SemLockObject *self, PyObject *args, PyObject *kwds)
265{
Antoine Pitrouc345ce12011-12-16 12:28:32 +0100266 int blocking = 1, res, err = 0;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000267 double timeout;
268 PyObject *timeout_obj = Py_None;
269 struct timespec deadline = {0};
270 struct timeval now;
271 long sec, nsec;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000272
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000273 static char *kwlist[] = {"block", "timeout", NULL};
Benjamin Petersone711caf2008-06-11 16:44:04 +0000274
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000275 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iO", kwlist,
276 &blocking, &timeout_obj))
277 return NULL;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000278
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000279 if (self->kind == RECURSIVE_MUTEX && ISMINE(self)) {
280 ++self->count;
281 Py_RETURN_TRUE;
282 }
Benjamin Petersone711caf2008-06-11 16:44:04 +0000283
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000284 if (timeout_obj != Py_None) {
285 timeout = PyFloat_AsDouble(timeout_obj);
286 if (PyErr_Occurred())
287 return NULL;
288 if (timeout < 0.0)
289 timeout = 0.0;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000290
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000291 if (gettimeofday(&now, NULL) < 0) {
292 PyErr_SetFromErrno(PyExc_OSError);
293 return NULL;
294 }
295 sec = (long) timeout;
296 nsec = (long) (1e9 * (timeout - sec) + 0.5);
297 deadline.tv_sec = now.tv_sec + sec;
298 deadline.tv_nsec = now.tv_usec * 1000 + nsec;
299 deadline.tv_sec += (deadline.tv_nsec / 1000000000);
300 deadline.tv_nsec %= 1000000000;
301 }
Benjamin Petersone711caf2008-06-11 16:44:04 +0000302
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000303 do {
304 Py_BEGIN_ALLOW_THREADS
305 if (blocking && timeout_obj == Py_None)
306 res = sem_wait(self->handle);
307 else if (!blocking)
308 res = sem_trywait(self->handle);
309 else
310 res = sem_timedwait(self->handle, &deadline);
311 Py_END_ALLOW_THREADS
Antoine Pitrouc345ce12011-12-16 12:28:32 +0100312 err = errno;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000313 if (res == MP_EXCEPTION_HAS_BEEN_SET)
314 break;
315 } while (res < 0 && errno == EINTR && !PyErr_CheckSignals());
Benjamin Petersone711caf2008-06-11 16:44:04 +0000316
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000317 if (res < 0) {
Antoine Pitrouc345ce12011-12-16 12:28:32 +0100318 errno = err;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000319 if (errno == EAGAIN || errno == ETIMEDOUT)
320 Py_RETURN_FALSE;
321 else if (errno == EINTR)
322 return NULL;
323 else
324 return PyErr_SetFromErrno(PyExc_OSError);
325 }
Benjamin Petersone711caf2008-06-11 16:44:04 +0000326
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000327 ++self->count;
328 self->last_tid = PyThread_get_thread_ident();
Benjamin Petersone711caf2008-06-11 16:44:04 +0000329
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000330 Py_RETURN_TRUE;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000331}
332
333static PyObject *
334semlock_release(SemLockObject *self, PyObject *args)
335{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000336 if (self->kind == RECURSIVE_MUTEX) {
337 if (!ISMINE(self)) {
338 PyErr_SetString(PyExc_AssertionError, "attempt to "
339 "release recursive lock not owned "
340 "by thread");
341 return NULL;
342 }
343 if (self->count > 1) {
344 --self->count;
345 Py_RETURN_NONE;
346 }
347 assert(self->count == 1);
348 } else {
Benjamin Peterson965ce872009-04-05 21:24:58 +0000349#ifdef HAVE_BROKEN_SEM_GETVALUE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000350 /* We will only check properly the maxvalue == 1 case */
351 if (self->maxvalue == 1) {
352 /* make sure that already locked */
353 if (sem_trywait(self->handle) < 0) {
354 if (errno != EAGAIN) {
355 PyErr_SetFromErrno(PyExc_OSError);
356 return NULL;
357 }
358 /* it is already locked as expected */
359 } else {
360 /* it was not locked so undo wait and raise */
361 if (sem_post(self->handle) < 0) {
362 PyErr_SetFromErrno(PyExc_OSError);
363 return NULL;
364 }
365 PyErr_SetString(PyExc_ValueError, "semaphore "
366 "or lock released too many "
367 "times");
368 return NULL;
369 }
370 }
Benjamin Petersone711caf2008-06-11 16:44:04 +0000371#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000372 int sval;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000373
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000374 /* This check is not an absolute guarantee that the semaphore
375 does not rise above maxvalue. */
376 if (sem_getvalue(self->handle, &sval) < 0) {
377 return PyErr_SetFromErrno(PyExc_OSError);
378 } else if (sval >= self->maxvalue) {
379 PyErr_SetString(PyExc_ValueError, "semaphore or lock "
380 "released too many times");
381 return NULL;
382 }
Benjamin Petersone711caf2008-06-11 16:44:04 +0000383#endif
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000384 }
Benjamin Petersone711caf2008-06-11 16:44:04 +0000385
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000386 if (sem_post(self->handle) < 0)
387 return PyErr_SetFromErrno(PyExc_OSError);
Benjamin Petersone711caf2008-06-11 16:44:04 +0000388
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000389 --self->count;
390 Py_RETURN_NONE;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000391}
392
393#endif /* !MS_WINDOWS */
394
395/*
396 * All platforms
397 */
398
399static PyObject *
400newsemlockobject(PyTypeObject *type, SEM_HANDLE handle, int kind, int maxvalue)
401{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000402 SemLockObject *self;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000403
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000404 self = PyObject_New(SemLockObject, type);
405 if (!self)
406 return NULL;
407 self->handle = handle;
408 self->kind = kind;
409 self->count = 0;
410 self->last_tid = 0;
411 self->maxvalue = maxvalue;
412 return (PyObject*)self;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000413}
414
415static PyObject *
416semlock_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
417{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000418 char buffer[256];
419 SEM_HANDLE handle = SEM_FAILED;
420 int kind, maxvalue, value;
421 PyObject *result;
422 static char *kwlist[] = {"kind", "value", "maxvalue", NULL};
423 static int counter = 0;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000424
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000425 if (!PyArg_ParseTupleAndKeywords(args, kwds, "iii", kwlist,
426 &kind, &value, &maxvalue))
427 return NULL;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000428
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000429 if (kind != RECURSIVE_MUTEX && kind != SEMAPHORE) {
430 PyErr_SetString(PyExc_ValueError, "unrecognized kind");
431 return NULL;
432 }
Benjamin Petersone711caf2008-06-11 16:44:04 +0000433
Georg Brandlc7f4af42010-10-18 05:06:18 +0000434 PyOS_snprintf(buffer, sizeof(buffer), "/mp%ld-%d", (long)getpid(), counter++);
Benjamin Petersone711caf2008-06-11 16:44:04 +0000435
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000436 SEM_CLEAR_ERROR();
437 handle = SEM_CREATE(buffer, value, maxvalue);
438 /* On Windows we should fail if GetLastError()==ERROR_ALREADY_EXISTS */
439 if (handle == SEM_FAILED || SEM_GET_LAST_ERROR() != 0)
440 goto failure;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000441
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000442 if (SEM_UNLINK(buffer) < 0)
443 goto failure;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000444
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000445 result = newsemlockobject(type, handle, kind, maxvalue);
446 if (!result)
447 goto failure;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000448
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000449 return result;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000450
451 failure:
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000452 if (handle != SEM_FAILED)
453 SEM_CLOSE(handle);
Richard Oudkerk8fb9f4c2012-10-07 18:08:47 +0100454 _PyMp_SetError(NULL, MP_STANDARD_ERROR);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000455 return NULL;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000456}
457
458static PyObject *
459semlock_rebuild(PyTypeObject *type, PyObject *args)
460{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000461 SEM_HANDLE handle;
462 int kind, maxvalue;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000463
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000464 if (!PyArg_ParseTuple(args, F_SEM_HANDLE "ii",
465 &handle, &kind, &maxvalue))
466 return NULL;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000467
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000468 return newsemlockobject(type, handle, kind, maxvalue);
Benjamin Petersone711caf2008-06-11 16:44:04 +0000469}
470
471static void
472semlock_dealloc(SemLockObject* self)
473{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000474 if (self->handle != SEM_FAILED)
475 SEM_CLOSE(self->handle);
476 PyObject_Del(self);
Benjamin Petersone711caf2008-06-11 16:44:04 +0000477}
478
479static PyObject *
480semlock_count(SemLockObject *self)
481{
Antoine Pitrou2341f9b2011-05-09 20:55:03 +0200482 return PyLong_FromLong((long)self->count);
Benjamin Petersone711caf2008-06-11 16:44:04 +0000483}
484
485static PyObject *
486semlock_ismine(SemLockObject *self)
487{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000488 /* only makes sense for a lock */
489 return PyBool_FromLong(ISMINE(self));
Benjamin Petersone711caf2008-06-11 16:44:04 +0000490}
491
492static PyObject *
493semlock_getvalue(SemLockObject *self)
494{
Benjamin Peterson965ce872009-04-05 21:24:58 +0000495#ifdef HAVE_BROKEN_SEM_GETVALUE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000496 PyErr_SetNone(PyExc_NotImplementedError);
497 return NULL;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000498#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000499 int sval;
500 if (SEM_GETVALUE(self->handle, &sval) < 0)
Richard Oudkerk8fb9f4c2012-10-07 18:08:47 +0100501 return _PyMp_SetError(NULL, MP_STANDARD_ERROR);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000502 /* some posix implementations use negative numbers to indicate
503 the number of waiting threads */
504 if (sval < 0)
505 sval = 0;
Antoine Pitrou2341f9b2011-05-09 20:55:03 +0200506 return PyLong_FromLong((long)sval);
Benjamin Petersone711caf2008-06-11 16:44:04 +0000507#endif
508}
509
510static PyObject *
511semlock_iszero(SemLockObject *self)
512{
Benjamin Peterson965ce872009-04-05 21:24:58 +0000513#ifdef HAVE_BROKEN_SEM_GETVALUE
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000514 if (sem_trywait(self->handle) < 0) {
515 if (errno == EAGAIN)
516 Py_RETURN_TRUE;
Richard Oudkerk8fb9f4c2012-10-07 18:08:47 +0100517 return _PyMp_SetError(NULL, MP_STANDARD_ERROR);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000518 } else {
519 if (sem_post(self->handle) < 0)
Richard Oudkerk8fb9f4c2012-10-07 18:08:47 +0100520 return _PyMp_SetError(NULL, MP_STANDARD_ERROR);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000521 Py_RETURN_FALSE;
522 }
Benjamin Petersone711caf2008-06-11 16:44:04 +0000523#else
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000524 int sval;
525 if (SEM_GETVALUE(self->handle, &sval) < 0)
Richard Oudkerk8fb9f4c2012-10-07 18:08:47 +0100526 return _PyMp_SetError(NULL, MP_STANDARD_ERROR);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000527 return PyBool_FromLong((long)sval == 0);
Benjamin Petersone711caf2008-06-11 16:44:04 +0000528#endif
529}
530
531static PyObject *
532semlock_afterfork(SemLockObject *self)
533{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000534 self->count = 0;
535 Py_RETURN_NONE;
Benjamin Petersone711caf2008-06-11 16:44:04 +0000536}
537
538/*
539 * Semaphore methods
540 */
541
542static PyMethodDef semlock_methods[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000543 {"acquire", (PyCFunction)semlock_acquire, METH_VARARGS | METH_KEYWORDS,
544 "acquire the semaphore/lock"},
545 {"release", (PyCFunction)semlock_release, METH_NOARGS,
546 "release the semaphore/lock"},
Jesse Nollerf8d00852009-03-31 03:25:07 +0000547 {"__enter__", (PyCFunction)semlock_acquire, METH_VARARGS | METH_KEYWORDS,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000548 "enter the semaphore/lock"},
549 {"__exit__", (PyCFunction)semlock_release, METH_VARARGS,
550 "exit the semaphore/lock"},
551 {"_count", (PyCFunction)semlock_count, METH_NOARGS,
552 "num of `acquire()`s minus num of `release()`s for this process"},
553 {"_is_mine", (PyCFunction)semlock_ismine, METH_NOARGS,
554 "whether the lock is owned by this thread"},
555 {"_get_value", (PyCFunction)semlock_getvalue, METH_NOARGS,
556 "get the value of the semaphore"},
557 {"_is_zero", (PyCFunction)semlock_iszero, METH_NOARGS,
558 "returns whether semaphore has value zero"},
559 {"_rebuild", (PyCFunction)semlock_rebuild, METH_VARARGS | METH_CLASS,
560 ""},
561 {"_after_fork", (PyCFunction)semlock_afterfork, METH_NOARGS,
562 "rezero the net acquisition count after fork()"},
563 {NULL}
Benjamin Petersone711caf2008-06-11 16:44:04 +0000564};
565
566/*
567 * Member table
568 */
569
570static PyMemberDef semlock_members[] = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000571 {"handle", T_SEM_HANDLE, offsetof(SemLockObject, handle), READONLY,
572 ""},
573 {"kind", T_INT, offsetof(SemLockObject, kind), READONLY,
574 ""},
575 {"maxvalue", T_INT, offsetof(SemLockObject, maxvalue), READONLY,
576 ""},
577 {NULL}
Benjamin Petersone711caf2008-06-11 16:44:04 +0000578};
579
580/*
581 * Semaphore type
582 */
583
Richard Oudkerk8fb9f4c2012-10-07 18:08:47 +0100584PyTypeObject _PyMp_SemLockType = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000585 PyVarObject_HEAD_INIT(NULL, 0)
586 /* tp_name */ "_multiprocessing.SemLock",
587 /* tp_basicsize */ sizeof(SemLockObject),
588 /* tp_itemsize */ 0,
589 /* tp_dealloc */ (destructor)semlock_dealloc,
590 /* tp_print */ 0,
591 /* tp_getattr */ 0,
592 /* tp_setattr */ 0,
593 /* tp_reserved */ 0,
594 /* tp_repr */ 0,
595 /* tp_as_number */ 0,
596 /* tp_as_sequence */ 0,
597 /* tp_as_mapping */ 0,
598 /* tp_hash */ 0,
599 /* tp_call */ 0,
600 /* tp_str */ 0,
601 /* tp_getattro */ 0,
602 /* tp_setattro */ 0,
603 /* tp_as_buffer */ 0,
604 /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
605 /* tp_doc */ "Semaphore/Mutex type",
606 /* tp_traverse */ 0,
607 /* tp_clear */ 0,
608 /* tp_richcompare */ 0,
609 /* tp_weaklistoffset */ 0,
610 /* tp_iter */ 0,
611 /* tp_iternext */ 0,
612 /* tp_methods */ semlock_methods,
613 /* tp_members */ semlock_members,
614 /* tp_getset */ 0,
615 /* tp_base */ 0,
616 /* tp_dict */ 0,
617 /* tp_descr_get */ 0,
618 /* tp_descr_set */ 0,
619 /* tp_dictoffset */ 0,
620 /* tp_init */ 0,
621 /* tp_alloc */ 0,
622 /* tp_new */ semlock_new,
Benjamin Petersone711caf2008-06-11 16:44:04 +0000623};