1 | /*
|
---|
2 | * A type which wraps a semaphore
|
---|
3 | *
|
---|
4 | * semaphore.c
|
---|
5 | *
|
---|
6 | * Copyright (c) 2006-2008, R Oudkerk --- see COPYING.txt
|
---|
7 | */
|
---|
8 |
|
---|
9 | #include "multiprocessing.h"
|
---|
10 |
|
---|
11 | enum { RECURSIVE_MUTEX, SEMAPHORE };
|
---|
12 |
|
---|
13 | typedef struct {
|
---|
14 | PyObject_HEAD
|
---|
15 | SEM_HANDLE handle;
|
---|
16 | long last_tid;
|
---|
17 | int count;
|
---|
18 | int maxvalue;
|
---|
19 | int kind;
|
---|
20 | } SemLockObject;
|
---|
21 |
|
---|
22 | #define ISMINE(o) (o->count > 0 && PyThread_get_thread_ident() == o->last_tid)
|
---|
23 |
|
---|
24 |
|
---|
25 | #ifdef MS_WINDOWS
|
---|
26 |
|
---|
27 | /*
|
---|
28 | * Windows definitions
|
---|
29 | */
|
---|
30 |
|
---|
31 | #define SEM_FAILED NULL
|
---|
32 |
|
---|
33 | #define SEM_CLEAR_ERROR() SetLastError(0)
|
---|
34 | #define SEM_GET_LAST_ERROR() GetLastError()
|
---|
35 | #define SEM_CREATE(name, val, max) CreateSemaphore(NULL, val, max, NULL)
|
---|
36 | #define SEM_CLOSE(sem) (CloseHandle(sem) ? 0 : -1)
|
---|
37 | #define SEM_GETVALUE(sem, pval) _GetSemaphoreValue(sem, pval)
|
---|
38 | #define SEM_UNLINK(name) 0
|
---|
39 |
|
---|
40 | static int
|
---|
41 | _GetSemaphoreValue(HANDLE handle, long *value)
|
---|
42 | {
|
---|
43 | long previous;
|
---|
44 |
|
---|
45 | switch (WaitForSingleObject(handle, 0)) {
|
---|
46 | case WAIT_OBJECT_0:
|
---|
47 | if (!ReleaseSemaphore(handle, 1, &previous))
|
---|
48 | return MP_STANDARD_ERROR;
|
---|
49 | *value = previous + 1;
|
---|
50 | return 0;
|
---|
51 | case WAIT_TIMEOUT:
|
---|
52 | *value = 0;
|
---|
53 | return 0;
|
---|
54 | default:
|
---|
55 | return MP_STANDARD_ERROR;
|
---|
56 | }
|
---|
57 | }
|
---|
58 |
|
---|
59 | static PyObject *
|
---|
60 | semlock_acquire(SemLockObject *self, PyObject *args, PyObject *kwds)
|
---|
61 | {
|
---|
62 | int blocking = 1;
|
---|
63 | double timeout;
|
---|
64 | PyObject *timeout_obj = Py_None;
|
---|
65 | DWORD res, full_msecs, msecs, start, ticks;
|
---|
66 |
|
---|
67 | static char *kwlist[] = {"block", "timeout", NULL};
|
---|
68 |
|
---|
69 | if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iO", kwlist,
|
---|
70 | &blocking, &timeout_obj))
|
---|
71 | return NULL;
|
---|
72 |
|
---|
73 | /* calculate timeout */
|
---|
74 | if (!blocking) {
|
---|
75 | full_msecs = 0;
|
---|
76 | } else if (timeout_obj == Py_None) {
|
---|
77 | full_msecs = INFINITE;
|
---|
78 | } else {
|
---|
79 | timeout = PyFloat_AsDouble(timeout_obj);
|
---|
80 | if (PyErr_Occurred())
|
---|
81 | return NULL;
|
---|
82 | timeout *= 1000.0; /* convert to millisecs */
|
---|
83 | if (timeout < 0.0) {
|
---|
84 | timeout = 0.0;
|
---|
85 | } else if (timeout >= 0.5 * INFINITE) { /* 25 days */
|
---|
86 | PyErr_SetString(PyExc_OverflowError,
|
---|
87 | "timeout is too large");
|
---|
88 | return NULL;
|
---|
89 | }
|
---|
90 | full_msecs = (DWORD)(timeout + 0.5);
|
---|
91 | }
|
---|
92 |
|
---|
93 | /* check whether we already own the lock */
|
---|
94 | if (self->kind == RECURSIVE_MUTEX && ISMINE(self)) {
|
---|
95 | ++self->count;
|
---|
96 | Py_RETURN_TRUE;
|
---|
97 | }
|
---|
98 |
|
---|
99 | /* check whether we can acquire without blocking */
|
---|
100 | if (WaitForSingleObject(self->handle, 0) == WAIT_OBJECT_0) {
|
---|
101 | self->last_tid = GetCurrentThreadId();
|
---|
102 | ++self->count;
|
---|
103 | Py_RETURN_TRUE;
|
---|
104 | }
|
---|
105 |
|
---|
106 | msecs = full_msecs;
|
---|
107 | start = GetTickCount();
|
---|
108 |
|
---|
109 | for ( ; ; ) {
|
---|
110 | HANDLE handles[2] = {self->handle, sigint_event};
|
---|
111 |
|
---|
112 | /* do the wait */
|
---|
113 | Py_BEGIN_ALLOW_THREADS
|
---|
114 | ResetEvent(sigint_event);
|
---|
115 | res = WaitForMultipleObjects(2, handles, FALSE, msecs);
|
---|
116 | Py_END_ALLOW_THREADS
|
---|
117 |
|
---|
118 | /* handle result */
|
---|
119 | if (res != WAIT_OBJECT_0 + 1)
|
---|
120 | break;
|
---|
121 |
|
---|
122 | /* got SIGINT so give signal handler a chance to run */
|
---|
123 | Sleep(1);
|
---|
124 |
|
---|
125 | /* if this is main thread let KeyboardInterrupt be raised */
|
---|
126 | if (PyErr_CheckSignals())
|
---|
127 | return NULL;
|
---|
128 |
|
---|
129 | /* recalculate timeout */
|
---|
130 | if (msecs != INFINITE) {
|
---|
131 | ticks = GetTickCount();
|
---|
132 | if ((DWORD)(ticks - start) >= full_msecs)
|
---|
133 | Py_RETURN_FALSE;
|
---|
134 | msecs = full_msecs - (ticks - start);
|
---|
135 | }
|
---|
136 | }
|
---|
137 |
|
---|
138 | /* handle result */
|
---|
139 | switch (res) {
|
---|
140 | case WAIT_TIMEOUT:
|
---|
141 | Py_RETURN_FALSE;
|
---|
142 | case WAIT_OBJECT_0:
|
---|
143 | self->last_tid = GetCurrentThreadId();
|
---|
144 | ++self->count;
|
---|
145 | Py_RETURN_TRUE;
|
---|
146 | case WAIT_FAILED:
|
---|
147 | return PyErr_SetFromWindowsErr(0);
|
---|
148 | default:
|
---|
149 | PyErr_Format(PyExc_RuntimeError, "WaitForSingleObject() or "
|
---|
150 | "WaitForMultipleObjects() gave unrecognized "
|
---|
151 | "value %d", res);
|
---|
152 | return NULL;
|
---|
153 | }
|
---|
154 | }
|
---|
155 |
|
---|
156 | static PyObject *
|
---|
157 | semlock_release(SemLockObject *self, PyObject *args)
|
---|
158 | {
|
---|
159 | if (self->kind == RECURSIVE_MUTEX) {
|
---|
160 | if (!ISMINE(self)) {
|
---|
161 | PyErr_SetString(PyExc_AssertionError, "attempt to "
|
---|
162 | "release recursive lock not owned "
|
---|
163 | "by thread");
|
---|
164 | return NULL;
|
---|
165 | }
|
---|
166 | if (self->count > 1) {
|
---|
167 | --self->count;
|
---|
168 | Py_RETURN_NONE;
|
---|
169 | }
|
---|
170 | assert(self->count == 1);
|
---|
171 | }
|
---|
172 |
|
---|
173 | if (!ReleaseSemaphore(self->handle, 1, NULL)) {
|
---|
174 | if (GetLastError() == ERROR_TOO_MANY_POSTS) {
|
---|
175 | PyErr_SetString(PyExc_ValueError, "semaphore or lock "
|
---|
176 | "released too many times");
|
---|
177 | return NULL;
|
---|
178 | } else {
|
---|
179 | return PyErr_SetFromWindowsErr(0);
|
---|
180 | }
|
---|
181 | }
|
---|
182 |
|
---|
183 | --self->count;
|
---|
184 | Py_RETURN_NONE;
|
---|
185 | }
|
---|
186 |
|
---|
187 | #else /* !MS_WINDOWS */
|
---|
188 |
|
---|
189 | /*
|
---|
190 | * Unix definitions
|
---|
191 | */
|
---|
192 |
|
---|
193 | #define SEM_CLEAR_ERROR()
|
---|
194 | #define SEM_GET_LAST_ERROR() 0
|
---|
195 | #define SEM_CREATE(name, val, max) sem_open(name, O_CREAT | O_EXCL, 0600, val)
|
---|
196 | #define SEM_CLOSE(sem) sem_close(sem)
|
---|
197 | #define SEM_GETVALUE(sem, pval) sem_getvalue(sem, pval)
|
---|
198 | #define SEM_UNLINK(name) sem_unlink(name)
|
---|
199 |
|
---|
200 | /* OS X 10.4 defines SEM_FAILED as -1 instead of (sem_t *)-1; this gives
|
---|
201 | compiler warnings, and (potentially) undefined behaviour. */
|
---|
202 | #ifdef __APPLE__
|
---|
203 | # undef SEM_FAILED
|
---|
204 | # define SEM_FAILED ((sem_t *)-1)
|
---|
205 | #endif
|
---|
206 |
|
---|
207 | #ifndef HAVE_SEM_UNLINK
|
---|
208 | # define sem_unlink(name) 0
|
---|
209 | #endif
|
---|
210 |
|
---|
211 | #ifndef HAVE_SEM_TIMEDWAIT
|
---|
212 | # define sem_timedwait(sem,deadline) sem_timedwait_save(sem,deadline,_save)
|
---|
213 |
|
---|
214 | int
|
---|
215 | sem_timedwait_save(sem_t *sem, struct timespec *deadline, PyThreadState *_save)
|
---|
216 | {
|
---|
217 | int res;
|
---|
218 | unsigned long delay, difference;
|
---|
219 | struct timeval now, tvdeadline, tvdelay;
|
---|
220 |
|
---|
221 | errno = 0;
|
---|
222 | tvdeadline.tv_sec = deadline->tv_sec;
|
---|
223 | tvdeadline.tv_usec = deadline->tv_nsec / 1000;
|
---|
224 |
|
---|
225 | for (delay = 0 ; ; delay += 1000) {
|
---|
226 | /* poll */
|
---|
227 | if (sem_trywait(sem) == 0)
|
---|
228 | return 0;
|
---|
229 | else if (errno != EAGAIN)
|
---|
230 | return MP_STANDARD_ERROR;
|
---|
231 |
|
---|
232 | /* get current time */
|
---|
233 | if (gettimeofday(&now, NULL) < 0)
|
---|
234 | return MP_STANDARD_ERROR;
|
---|
235 |
|
---|
236 | /* check for timeout */
|
---|
237 | if (tvdeadline.tv_sec < now.tv_sec ||
|
---|
238 | (tvdeadline.tv_sec == now.tv_sec &&
|
---|
239 | tvdeadline.tv_usec <= now.tv_usec)) {
|
---|
240 | errno = ETIMEDOUT;
|
---|
241 | return MP_STANDARD_ERROR;
|
---|
242 | }
|
---|
243 |
|
---|
244 | /* calculate how much time is left */
|
---|
245 | difference = (tvdeadline.tv_sec - now.tv_sec) * 1000000 +
|
---|
246 | (tvdeadline.tv_usec - now.tv_usec);
|
---|
247 |
|
---|
248 | /* check delay not too long -- maximum is 20 msecs */
|
---|
249 | if (delay > 20000)
|
---|
250 | delay = 20000;
|
---|
251 | if (delay > difference)
|
---|
252 | delay = difference;
|
---|
253 |
|
---|
254 | /* sleep */
|
---|
255 | tvdelay.tv_sec = delay / 1000000;
|
---|
256 | tvdelay.tv_usec = delay % 1000000;
|
---|
257 | if (select(0, NULL, NULL, NULL, &tvdelay) < 0)
|
---|
258 | return MP_STANDARD_ERROR;
|
---|
259 |
|
---|
260 | /* check for signals */
|
---|
261 | Py_BLOCK_THREADS
|
---|
262 | res = PyErr_CheckSignals();
|
---|
263 | Py_UNBLOCK_THREADS
|
---|
264 |
|
---|
265 | if (res) {
|
---|
266 | errno = EINTR;
|
---|
267 | return MP_EXCEPTION_HAS_BEEN_SET;
|
---|
268 | }
|
---|
269 | }
|
---|
270 | }
|
---|
271 |
|
---|
272 | #endif /* !HAVE_SEM_TIMEDWAIT */
|
---|
273 |
|
---|
274 | static PyObject *
|
---|
275 | semlock_acquire(SemLockObject *self, PyObject *args, PyObject *kwds)
|
---|
276 | {
|
---|
277 | int blocking = 1, res;
|
---|
278 | double timeout;
|
---|
279 | PyObject *timeout_obj = Py_None;
|
---|
280 | struct timespec deadline = {0};
|
---|
281 | struct timeval now;
|
---|
282 | long sec, nsec;
|
---|
283 |
|
---|
284 | static char *kwlist[] = {"block", "timeout", NULL};
|
---|
285 |
|
---|
286 | if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iO", kwlist,
|
---|
287 | &blocking, &timeout_obj))
|
---|
288 | return NULL;
|
---|
289 |
|
---|
290 | if (self->kind == RECURSIVE_MUTEX && ISMINE(self)) {
|
---|
291 | ++self->count;
|
---|
292 | Py_RETURN_TRUE;
|
---|
293 | }
|
---|
294 |
|
---|
295 | if (timeout_obj != Py_None) {
|
---|
296 | timeout = PyFloat_AsDouble(timeout_obj);
|
---|
297 | if (PyErr_Occurred())
|
---|
298 | return NULL;
|
---|
299 | if (timeout < 0.0)
|
---|
300 | timeout = 0.0;
|
---|
301 |
|
---|
302 | if (gettimeofday(&now, NULL) < 0) {
|
---|
303 | PyErr_SetFromErrno(PyExc_OSError);
|
---|
304 | return NULL;
|
---|
305 | }
|
---|
306 | sec = (long) timeout;
|
---|
307 | nsec = (long) (1e9 * (timeout - sec) + 0.5);
|
---|
308 | deadline.tv_sec = now.tv_sec + sec;
|
---|
309 | deadline.tv_nsec = now.tv_usec * 1000 + nsec;
|
---|
310 | deadline.tv_sec += (deadline.tv_nsec / 1000000000);
|
---|
311 | deadline.tv_nsec %= 1000000000;
|
---|
312 | }
|
---|
313 |
|
---|
314 | do {
|
---|
315 | Py_BEGIN_ALLOW_THREADS
|
---|
316 | if (blocking && timeout_obj == Py_None)
|
---|
317 | res = sem_wait(self->handle);
|
---|
318 | else if (!blocking)
|
---|
319 | res = sem_trywait(self->handle);
|
---|
320 | else
|
---|
321 | res = sem_timedwait(self->handle, &deadline);
|
---|
322 | Py_END_ALLOW_THREADS
|
---|
323 | if (res == MP_EXCEPTION_HAS_BEEN_SET)
|
---|
324 | break;
|
---|
325 | } while (res < 0 && errno == EINTR && !PyErr_CheckSignals());
|
---|
326 |
|
---|
327 | if (res < 0) {
|
---|
328 | if (errno == EAGAIN || errno == ETIMEDOUT)
|
---|
329 | Py_RETURN_FALSE;
|
---|
330 | else if (errno == EINTR)
|
---|
331 | return NULL;
|
---|
332 | else
|
---|
333 | return PyErr_SetFromErrno(PyExc_OSError);
|
---|
334 | }
|
---|
335 |
|
---|
336 | ++self->count;
|
---|
337 | self->last_tid = PyThread_get_thread_ident();
|
---|
338 |
|
---|
339 | Py_RETURN_TRUE;
|
---|
340 | }
|
---|
341 |
|
---|
342 | static PyObject *
|
---|
343 | semlock_release(SemLockObject *self, PyObject *args)
|
---|
344 | {
|
---|
345 | if (self->kind == RECURSIVE_MUTEX) {
|
---|
346 | if (!ISMINE(self)) {
|
---|
347 | PyErr_SetString(PyExc_AssertionError, "attempt to "
|
---|
348 | "release recursive lock not owned "
|
---|
349 | "by thread");
|
---|
350 | return NULL;
|
---|
351 | }
|
---|
352 | if (self->count > 1) {
|
---|
353 | --self->count;
|
---|
354 | Py_RETURN_NONE;
|
---|
355 | }
|
---|
356 | assert(self->count == 1);
|
---|
357 | } else {
|
---|
358 | #ifdef HAVE_BROKEN_SEM_GETVALUE
|
---|
359 | /* We will only check properly the maxvalue == 1 case */
|
---|
360 | if (self->maxvalue == 1) {
|
---|
361 | /* make sure that already locked */
|
---|
362 | if (sem_trywait(self->handle) < 0) {
|
---|
363 | if (errno != EAGAIN) {
|
---|
364 | PyErr_SetFromErrno(PyExc_OSError);
|
---|
365 | return NULL;
|
---|
366 | }
|
---|
367 | /* it is already locked as expected */
|
---|
368 | } else {
|
---|
369 | /* it was not locked so undo wait and raise */
|
---|
370 | if (sem_post(self->handle) < 0) {
|
---|
371 | PyErr_SetFromErrno(PyExc_OSError);
|
---|
372 | return NULL;
|
---|
373 | }
|
---|
374 | PyErr_SetString(PyExc_ValueError, "semaphore "
|
---|
375 | "or lock released too many "
|
---|
376 | "times");
|
---|
377 | return NULL;
|
---|
378 | }
|
---|
379 | }
|
---|
380 | #else
|
---|
381 | int sval;
|
---|
382 |
|
---|
383 | /* This check is not an absolute guarantee that the semaphore
|
---|
384 | does not rise above maxvalue. */
|
---|
385 | if (sem_getvalue(self->handle, &sval) < 0) {
|
---|
386 | return PyErr_SetFromErrno(PyExc_OSError);
|
---|
387 | } else if (sval >= self->maxvalue) {
|
---|
388 | PyErr_SetString(PyExc_ValueError, "semaphore or lock "
|
---|
389 | "released too many times");
|
---|
390 | return NULL;
|
---|
391 | }
|
---|
392 | #endif
|
---|
393 | }
|
---|
394 |
|
---|
395 | if (sem_post(self->handle) < 0)
|
---|
396 | return PyErr_SetFromErrno(PyExc_OSError);
|
---|
397 |
|
---|
398 | --self->count;
|
---|
399 | Py_RETURN_NONE;
|
---|
400 | }
|
---|
401 |
|
---|
402 | #endif /* !MS_WINDOWS */
|
---|
403 |
|
---|
404 | /*
|
---|
405 | * All platforms
|
---|
406 | */
|
---|
407 |
|
---|
408 | static PyObject *
|
---|
409 | newsemlockobject(PyTypeObject *type, SEM_HANDLE handle, int kind, int maxvalue)
|
---|
410 | {
|
---|
411 | SemLockObject *self;
|
---|
412 |
|
---|
413 | self = PyObject_New(SemLockObject, type);
|
---|
414 | if (!self)
|
---|
415 | return NULL;
|
---|
416 | self->handle = handle;
|
---|
417 | self->kind = kind;
|
---|
418 | self->count = 0;
|
---|
419 | self->last_tid = 0;
|
---|
420 | self->maxvalue = maxvalue;
|
---|
421 | return (PyObject*)self;
|
---|
422 | }
|
---|
423 |
|
---|
424 | static PyObject *
|
---|
425 | semlock_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
---|
426 | {
|
---|
427 | char buffer[256];
|
---|
428 | SEM_HANDLE handle = SEM_FAILED;
|
---|
429 | int kind, maxvalue, value;
|
---|
430 | PyObject *result;
|
---|
431 | static char *kwlist[] = {"kind", "value", "maxvalue", NULL};
|
---|
432 | static int counter = 0;
|
---|
433 |
|
---|
434 | if (!PyArg_ParseTupleAndKeywords(args, kwds, "iii", kwlist,
|
---|
435 | &kind, &value, &maxvalue))
|
---|
436 | return NULL;
|
---|
437 |
|
---|
438 | if (kind != RECURSIVE_MUTEX && kind != SEMAPHORE) {
|
---|
439 | PyErr_SetString(PyExc_ValueError, "unrecognized kind");
|
---|
440 | return NULL;
|
---|
441 | }
|
---|
442 |
|
---|
443 | PyOS_snprintf(buffer, sizeof(buffer), "/mp%ld-%d", (long)getpid(), counter++);
|
---|
444 |
|
---|
445 | SEM_CLEAR_ERROR();
|
---|
446 | handle = SEM_CREATE(buffer, value, maxvalue);
|
---|
447 | /* On Windows we should fail if GetLastError()==ERROR_ALREADY_EXISTS */
|
---|
448 | if (handle == SEM_FAILED || SEM_GET_LAST_ERROR() != 0)
|
---|
449 | goto failure;
|
---|
450 |
|
---|
451 | if (SEM_UNLINK(buffer) < 0)
|
---|
452 | goto failure;
|
---|
453 |
|
---|
454 | result = newsemlockobject(type, handle, kind, maxvalue);
|
---|
455 | if (!result)
|
---|
456 | goto failure;
|
---|
457 |
|
---|
458 | return result;
|
---|
459 |
|
---|
460 | failure:
|
---|
461 | if (handle != SEM_FAILED)
|
---|
462 | SEM_CLOSE(handle);
|
---|
463 | mp_SetError(NULL, MP_STANDARD_ERROR);
|
---|
464 | return NULL;
|
---|
465 | }
|
---|
466 |
|
---|
467 | static PyObject *
|
---|
468 | semlock_rebuild(PyTypeObject *type, PyObject *args)
|
---|
469 | {
|
---|
470 | SEM_HANDLE handle;
|
---|
471 | int kind, maxvalue;
|
---|
472 |
|
---|
473 | if (!PyArg_ParseTuple(args, F_SEM_HANDLE "ii",
|
---|
474 | &handle, &kind, &maxvalue))
|
---|
475 | return NULL;
|
---|
476 |
|
---|
477 | return newsemlockobject(type, handle, kind, maxvalue);
|
---|
478 | }
|
---|
479 |
|
---|
480 | static void
|
---|
481 | semlock_dealloc(SemLockObject* self)
|
---|
482 | {
|
---|
483 | if (self->handle != SEM_FAILED)
|
---|
484 | SEM_CLOSE(self->handle);
|
---|
485 | PyObject_Del(self);
|
---|
486 | }
|
---|
487 |
|
---|
488 | static PyObject *
|
---|
489 | semlock_count(SemLockObject *self)
|
---|
490 | {
|
---|
491 | return PyInt_FromLong((long)self->count);
|
---|
492 | }
|
---|
493 |
|
---|
494 | static PyObject *
|
---|
495 | semlock_ismine(SemLockObject *self)
|
---|
496 | {
|
---|
497 | /* only makes sense for a lock */
|
---|
498 | return PyBool_FromLong(ISMINE(self));
|
---|
499 | }
|
---|
500 |
|
---|
501 | static PyObject *
|
---|
502 | semlock_getvalue(SemLockObject *self)
|
---|
503 | {
|
---|
504 | #ifdef HAVE_BROKEN_SEM_GETVALUE
|
---|
505 | PyErr_SetNone(PyExc_NotImplementedError);
|
---|
506 | return NULL;
|
---|
507 | #else
|
---|
508 | int sval;
|
---|
509 | if (SEM_GETVALUE(self->handle, &sval) < 0)
|
---|
510 | return mp_SetError(NULL, MP_STANDARD_ERROR);
|
---|
511 | /* some posix implementations use negative numbers to indicate
|
---|
512 | the number of waiting threads */
|
---|
513 | if (sval < 0)
|
---|
514 | sval = 0;
|
---|
515 | return PyInt_FromLong((long)sval);
|
---|
516 | #endif
|
---|
517 | }
|
---|
518 |
|
---|
519 | static PyObject *
|
---|
520 | semlock_iszero(SemLockObject *self)
|
---|
521 | {
|
---|
522 | #ifdef HAVE_BROKEN_SEM_GETVALUE
|
---|
523 | if (sem_trywait(self->handle) < 0) {
|
---|
524 | if (errno == EAGAIN)
|
---|
525 | Py_RETURN_TRUE;
|
---|
526 | return mp_SetError(NULL, MP_STANDARD_ERROR);
|
---|
527 | } else {
|
---|
528 | if (sem_post(self->handle) < 0)
|
---|
529 | return mp_SetError(NULL, MP_STANDARD_ERROR);
|
---|
530 | Py_RETURN_FALSE;
|
---|
531 | }
|
---|
532 | #else
|
---|
533 | int sval;
|
---|
534 | if (SEM_GETVALUE(self->handle, &sval) < 0)
|
---|
535 | return mp_SetError(NULL, MP_STANDARD_ERROR);
|
---|
536 | return PyBool_FromLong((long)sval == 0);
|
---|
537 | #endif
|
---|
538 | }
|
---|
539 |
|
---|
540 | static PyObject *
|
---|
541 | semlock_afterfork(SemLockObject *self)
|
---|
542 | {
|
---|
543 | self->count = 0;
|
---|
544 | Py_RETURN_NONE;
|
---|
545 | }
|
---|
546 |
|
---|
547 | /*
|
---|
548 | * Semaphore methods
|
---|
549 | */
|
---|
550 |
|
---|
551 | static PyMethodDef semlock_methods[] = {
|
---|
552 | {"acquire", (PyCFunction)semlock_acquire, METH_VARARGS | METH_KEYWORDS,
|
---|
553 | "acquire the semaphore/lock"},
|
---|
554 | {"release", (PyCFunction)semlock_release, METH_NOARGS,
|
---|
555 | "release the semaphore/lock"},
|
---|
556 | {"__enter__", (PyCFunction)semlock_acquire, METH_VARARGS | METH_KEYWORDS,
|
---|
557 | "enter the semaphore/lock"},
|
---|
558 | {"__exit__", (PyCFunction)semlock_release, METH_VARARGS,
|
---|
559 | "exit the semaphore/lock"},
|
---|
560 | {"_count", (PyCFunction)semlock_count, METH_NOARGS,
|
---|
561 | "num of `acquire()`s minus num of `release()`s for this process"},
|
---|
562 | {"_is_mine", (PyCFunction)semlock_ismine, METH_NOARGS,
|
---|
563 | "whether the lock is owned by this thread"},
|
---|
564 | {"_get_value", (PyCFunction)semlock_getvalue, METH_NOARGS,
|
---|
565 | "get the value of the semaphore"},
|
---|
566 | {"_is_zero", (PyCFunction)semlock_iszero, METH_NOARGS,
|
---|
567 | "returns whether semaphore has value zero"},
|
---|
568 | {"_rebuild", (PyCFunction)semlock_rebuild, METH_VARARGS | METH_CLASS,
|
---|
569 | ""},
|
---|
570 | {"_after_fork", (PyCFunction)semlock_afterfork, METH_NOARGS,
|
---|
571 | "rezero the net acquisition count after fork()"},
|
---|
572 | {NULL}
|
---|
573 | };
|
---|
574 |
|
---|
575 | /*
|
---|
576 | * Member table
|
---|
577 | */
|
---|
578 |
|
---|
579 | static PyMemberDef semlock_members[] = {
|
---|
580 | {"handle", T_SEM_HANDLE, offsetof(SemLockObject, handle), READONLY,
|
---|
581 | ""},
|
---|
582 | {"kind", T_INT, offsetof(SemLockObject, kind), READONLY,
|
---|
583 | ""},
|
---|
584 | {"maxvalue", T_INT, offsetof(SemLockObject, maxvalue), READONLY,
|
---|
585 | ""},
|
---|
586 | {NULL}
|
---|
587 | };
|
---|
588 |
|
---|
589 | /*
|
---|
590 | * Semaphore type
|
---|
591 | */
|
---|
592 |
|
---|
593 | PyTypeObject SemLockType = {
|
---|
594 | PyVarObject_HEAD_INIT(NULL, 0)
|
---|
595 | /* tp_name */ "_multiprocessing.SemLock",
|
---|
596 | /* tp_basicsize */ sizeof(SemLockObject),
|
---|
597 | /* tp_itemsize */ 0,
|
---|
598 | /* tp_dealloc */ (destructor)semlock_dealloc,
|
---|
599 | /* tp_print */ 0,
|
---|
600 | /* tp_getattr */ 0,
|
---|
601 | /* tp_setattr */ 0,
|
---|
602 | /* tp_compare */ 0,
|
---|
603 | /* tp_repr */ 0,
|
---|
604 | /* tp_as_number */ 0,
|
---|
605 | /* tp_as_sequence */ 0,
|
---|
606 | /* tp_as_mapping */ 0,
|
---|
607 | /* tp_hash */ 0,
|
---|
608 | /* tp_call */ 0,
|
---|
609 | /* tp_str */ 0,
|
---|
610 | /* tp_getattro */ 0,
|
---|
611 | /* tp_setattro */ 0,
|
---|
612 | /* tp_as_buffer */ 0,
|
---|
613 | /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
---|
614 | /* tp_doc */ "Semaphore/Mutex type",
|
---|
615 | /* tp_traverse */ 0,
|
---|
616 | /* tp_clear */ 0,
|
---|
617 | /* tp_richcompare */ 0,
|
---|
618 | /* tp_weaklistoffset */ 0,
|
---|
619 | /* tp_iter */ 0,
|
---|
620 | /* tp_iternext */ 0,
|
---|
621 | /* tp_methods */ semlock_methods,
|
---|
622 | /* tp_members */ semlock_members,
|
---|
623 | /* tp_getset */ 0,
|
---|
624 | /* tp_base */ 0,
|
---|
625 | /* tp_dict */ 0,
|
---|
626 | /* tp_descr_get */ 0,
|
---|
627 | /* tp_descr_set */ 0,
|
---|
628 | /* tp_dictoffset */ 0,
|
---|
629 | /* tp_init */ 0,
|
---|
630 | /* tp_alloc */ 0,
|
---|
631 | /* tp_new */ semlock_new,
|
---|
632 | };
|
---|