Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
allendowney
GitHub Repository: allendowney/cpython
Path: blob/main/Modules/_multiprocessing/semaphore.c
12 views
1
/*
2
* A type which wraps a semaphore
3
*
4
* semaphore.c
5
*
6
* Copyright (c) 2006-2008, R Oudkerk
7
* Licensed to PSF under a Contributor Agreement.
8
*/
9
10
#include "multiprocessing.h"
11
12
#ifdef HAVE_MP_SEMAPHORE
13
14
enum { RECURSIVE_MUTEX, SEMAPHORE };
15
16
typedef struct {
17
PyObject_HEAD
18
SEM_HANDLE handle;
19
unsigned long last_tid;
20
int count;
21
int maxvalue;
22
int kind;
23
char *name;
24
} SemLockObject;
25
26
/*[python input]
27
class SEM_HANDLE_converter(CConverter):
28
type = "SEM_HANDLE"
29
format_unit = '"F_SEM_HANDLE"'
30
31
[python start generated code]*/
32
/*[python end generated code: output=da39a3ee5e6b4b0d input=3e0ad43e482d8716]*/
33
34
/*[clinic input]
35
module _multiprocessing
36
class _multiprocessing.SemLock "SemLockObject *" "&_PyMp_SemLockType"
37
[clinic start generated code]*/
38
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=935fb41b7d032599]*/
39
40
#include "clinic/semaphore.c.h"
41
42
#define ISMINE(o) (o->count > 0 && PyThread_get_thread_ident() == o->last_tid)
43
44
45
#ifdef MS_WINDOWS
46
47
/*
48
* Windows definitions
49
*/
50
51
#define SEM_FAILED NULL
52
53
#define SEM_CLEAR_ERROR() SetLastError(0)
54
#define SEM_GET_LAST_ERROR() GetLastError()
55
#define SEM_CREATE(name, val, max) CreateSemaphore(NULL, val, max, NULL)
56
#define SEM_CLOSE(sem) (CloseHandle(sem) ? 0 : -1)
57
#define SEM_GETVALUE(sem, pval) _GetSemaphoreValue(sem, pval)
58
#define SEM_UNLINK(name) 0
59
60
static int
61
_GetSemaphoreValue(HANDLE handle, long *value)
62
{
63
long previous;
64
65
switch (WaitForSingleObjectEx(handle, 0, FALSE)) {
66
case WAIT_OBJECT_0:
67
if (!ReleaseSemaphore(handle, 1, &previous))
68
return MP_STANDARD_ERROR;
69
*value = previous + 1;
70
return 0;
71
case WAIT_TIMEOUT:
72
*value = 0;
73
return 0;
74
default:
75
return MP_STANDARD_ERROR;
76
}
77
}
78
79
/*[clinic input]
80
_multiprocessing.SemLock.acquire
81
82
block as blocking: bool = True
83
timeout as timeout_obj: object = None
84
85
Acquire the semaphore/lock.
86
[clinic start generated code]*/
87
88
static PyObject *
89
_multiprocessing_SemLock_acquire_impl(SemLockObject *self, int blocking,
90
PyObject *timeout_obj)
91
/*[clinic end generated code: output=f9998f0b6b0b0872 input=e5b45f5cbb775166]*/
92
{
93
double timeout;
94
DWORD res, full_msecs, nhandles;
95
HANDLE handles[2], sigint_event;
96
97
/* calculate timeout */
98
if (!blocking) {
99
full_msecs = 0;
100
} else if (timeout_obj == Py_None) {
101
full_msecs = INFINITE;
102
} else {
103
timeout = PyFloat_AsDouble(timeout_obj);
104
if (PyErr_Occurred())
105
return NULL;
106
timeout *= 1000.0; /* convert to millisecs */
107
if (timeout < 0.0) {
108
timeout = 0.0;
109
} else if (timeout >= 0.5 * INFINITE) { /* 25 days */
110
PyErr_SetString(PyExc_OverflowError,
111
"timeout is too large");
112
return NULL;
113
}
114
full_msecs = (DWORD)(timeout + 0.5);
115
}
116
117
/* check whether we already own the lock */
118
if (self->kind == RECURSIVE_MUTEX && ISMINE(self)) {
119
++self->count;
120
Py_RETURN_TRUE;
121
}
122
123
/* check whether we can acquire without releasing the GIL and blocking */
124
if (WaitForSingleObjectEx(self->handle, 0, FALSE) == WAIT_OBJECT_0) {
125
self->last_tid = GetCurrentThreadId();
126
++self->count;
127
Py_RETURN_TRUE;
128
}
129
130
/* prepare list of handles */
131
nhandles = 0;
132
handles[nhandles++] = self->handle;
133
if (_PyOS_IsMainThread()) {
134
sigint_event = _PyOS_SigintEvent();
135
assert(sigint_event != NULL);
136
handles[nhandles++] = sigint_event;
137
}
138
else {
139
sigint_event = NULL;
140
}
141
142
/* do the wait */
143
Py_BEGIN_ALLOW_THREADS
144
if (sigint_event != NULL)
145
ResetEvent(sigint_event);
146
res = WaitForMultipleObjectsEx(nhandles, handles, FALSE, full_msecs, FALSE);
147
Py_END_ALLOW_THREADS
148
149
/* handle result */
150
switch (res) {
151
case WAIT_TIMEOUT:
152
Py_RETURN_FALSE;
153
case WAIT_OBJECT_0 + 0:
154
self->last_tid = GetCurrentThreadId();
155
++self->count;
156
Py_RETURN_TRUE;
157
case WAIT_OBJECT_0 + 1:
158
errno = EINTR;
159
return PyErr_SetFromErrno(PyExc_OSError);
160
case WAIT_FAILED:
161
return PyErr_SetFromWindowsErr(0);
162
default:
163
PyErr_Format(PyExc_RuntimeError, "WaitForSingleObject() or "
164
"WaitForMultipleObjects() gave unrecognized "
165
"value %u", res);
166
return NULL;
167
}
168
}
169
170
/*[clinic input]
171
_multiprocessing.SemLock.release
172
173
Release the semaphore/lock.
174
[clinic start generated code]*/
175
176
static PyObject *
177
_multiprocessing_SemLock_release_impl(SemLockObject *self)
178
/*[clinic end generated code: output=b22f53ba96b0d1db input=ba7e63a961885d3d]*/
179
{
180
if (self->kind == RECURSIVE_MUTEX) {
181
if (!ISMINE(self)) {
182
PyErr_SetString(PyExc_AssertionError, "attempt to "
183
"release recursive lock not owned "
184
"by thread");
185
return NULL;
186
}
187
if (self->count > 1) {
188
--self->count;
189
Py_RETURN_NONE;
190
}
191
assert(self->count == 1);
192
}
193
194
if (!ReleaseSemaphore(self->handle, 1, NULL)) {
195
if (GetLastError() == ERROR_TOO_MANY_POSTS) {
196
PyErr_SetString(PyExc_ValueError, "semaphore or lock "
197
"released too many times");
198
return NULL;
199
} else {
200
return PyErr_SetFromWindowsErr(0);
201
}
202
}
203
204
--self->count;
205
Py_RETURN_NONE;
206
}
207
208
#else /* !MS_WINDOWS */
209
210
/*
211
* Unix definitions
212
*/
213
214
#define SEM_CLEAR_ERROR()
215
#define SEM_GET_LAST_ERROR() 0
216
#define SEM_CREATE(name, val, max) sem_open(name, O_CREAT | O_EXCL, 0600, val)
217
#define SEM_CLOSE(sem) sem_close(sem)
218
#define SEM_GETVALUE(sem, pval) sem_getvalue(sem, pval)
219
#define SEM_UNLINK(name) sem_unlink(name)
220
221
/* OS X 10.4 defines SEM_FAILED as -1 instead of (sem_t *)-1; this gives
222
compiler warnings, and (potentially) undefined behaviour. */
223
#ifdef __APPLE__
224
# undef SEM_FAILED
225
# define SEM_FAILED ((sem_t *)-1)
226
#endif
227
228
#ifndef HAVE_SEM_UNLINK
229
# define sem_unlink(name) 0
230
#endif
231
232
#ifndef HAVE_SEM_TIMEDWAIT
233
# define sem_timedwait(sem,deadline) sem_timedwait_save(sem,deadline,_save)
234
235
static int
236
sem_timedwait_save(sem_t *sem, struct timespec *deadline, PyThreadState *_save)
237
{
238
int res;
239
unsigned long delay, difference;
240
struct timeval now, tvdeadline, tvdelay;
241
242
errno = 0;
243
tvdeadline.tv_sec = deadline->tv_sec;
244
tvdeadline.tv_usec = deadline->tv_nsec / 1000;
245
246
for (delay = 0 ; ; delay += 1000) {
247
/* poll */
248
if (sem_trywait(sem) == 0)
249
return 0;
250
else if (errno != EAGAIN)
251
return MP_STANDARD_ERROR;
252
253
/* get current time */
254
if (gettimeofday(&now, NULL) < 0)
255
return MP_STANDARD_ERROR;
256
257
/* check for timeout */
258
if (tvdeadline.tv_sec < now.tv_sec ||
259
(tvdeadline.tv_sec == now.tv_sec &&
260
tvdeadline.tv_usec <= now.tv_usec)) {
261
errno = ETIMEDOUT;
262
return MP_STANDARD_ERROR;
263
}
264
265
/* calculate how much time is left */
266
difference = (tvdeadline.tv_sec - now.tv_sec) * 1000000 +
267
(tvdeadline.tv_usec - now.tv_usec);
268
269
/* check delay not too long -- maximum is 20 msecs */
270
if (delay > 20000)
271
delay = 20000;
272
if (delay > difference)
273
delay = difference;
274
275
/* sleep */
276
tvdelay.tv_sec = delay / 1000000;
277
tvdelay.tv_usec = delay % 1000000;
278
if (select(0, NULL, NULL, NULL, &tvdelay) < 0)
279
return MP_STANDARD_ERROR;
280
281
/* check for signals */
282
Py_BLOCK_THREADS
283
res = PyErr_CheckSignals();
284
Py_UNBLOCK_THREADS
285
286
if (res) {
287
errno = EINTR;
288
return MP_EXCEPTION_HAS_BEEN_SET;
289
}
290
}
291
}
292
293
#endif /* !HAVE_SEM_TIMEDWAIT */
294
295
/*[clinic input]
296
_multiprocessing.SemLock.acquire
297
298
block as blocking: bool = True
299
timeout as timeout_obj: object = None
300
301
Acquire the semaphore/lock.
302
[clinic start generated code]*/
303
304
static PyObject *
305
_multiprocessing_SemLock_acquire_impl(SemLockObject *self, int blocking,
306
PyObject *timeout_obj)
307
/*[clinic end generated code: output=f9998f0b6b0b0872 input=e5b45f5cbb775166]*/
308
{
309
int res, err = 0;
310
struct timespec deadline = {0};
311
312
if (self->kind == RECURSIVE_MUTEX && ISMINE(self)) {
313
++self->count;
314
Py_RETURN_TRUE;
315
}
316
317
int use_deadline = (timeout_obj != Py_None);
318
if (use_deadline) {
319
double timeout = PyFloat_AsDouble(timeout_obj);
320
if (PyErr_Occurred()) {
321
return NULL;
322
}
323
if (timeout < 0.0) {
324
timeout = 0.0;
325
}
326
327
struct timeval now;
328
if (gettimeofday(&now, NULL) < 0) {
329
PyErr_SetFromErrno(PyExc_OSError);
330
return NULL;
331
}
332
long sec = (long) timeout;
333
long nsec = (long) (1e9 * (timeout - sec) + 0.5);
334
deadline.tv_sec = now.tv_sec + sec;
335
deadline.tv_nsec = now.tv_usec * 1000 + nsec;
336
deadline.tv_sec += (deadline.tv_nsec / 1000000000);
337
deadline.tv_nsec %= 1000000000;
338
}
339
340
/* Check whether we can acquire without releasing the GIL and blocking */
341
do {
342
res = sem_trywait(self->handle);
343
err = errno;
344
} while (res < 0 && errno == EINTR && !PyErr_CheckSignals());
345
errno = err;
346
347
if (res < 0 && errno == EAGAIN && blocking) {
348
/* Couldn't acquire immediately, need to block */
349
do {
350
Py_BEGIN_ALLOW_THREADS
351
if (!use_deadline) {
352
res = sem_wait(self->handle);
353
}
354
else {
355
res = sem_timedwait(self->handle, &deadline);
356
}
357
Py_END_ALLOW_THREADS
358
err = errno;
359
if (res == MP_EXCEPTION_HAS_BEEN_SET)
360
break;
361
} while (res < 0 && errno == EINTR && !PyErr_CheckSignals());
362
}
363
364
if (res < 0) {
365
errno = err;
366
if (errno == EAGAIN || errno == ETIMEDOUT)
367
Py_RETURN_FALSE;
368
else if (errno == EINTR)
369
return NULL;
370
else
371
return PyErr_SetFromErrno(PyExc_OSError);
372
}
373
374
++self->count;
375
self->last_tid = PyThread_get_thread_ident();
376
377
Py_RETURN_TRUE;
378
}
379
380
/*[clinic input]
381
_multiprocessing.SemLock.release
382
383
Release the semaphore/lock.
384
[clinic start generated code]*/
385
386
static PyObject *
387
_multiprocessing_SemLock_release_impl(SemLockObject *self)
388
/*[clinic end generated code: output=b22f53ba96b0d1db input=ba7e63a961885d3d]*/
389
{
390
if (self->kind == RECURSIVE_MUTEX) {
391
if (!ISMINE(self)) {
392
PyErr_SetString(PyExc_AssertionError, "attempt to "
393
"release recursive lock not owned "
394
"by thread");
395
return NULL;
396
}
397
if (self->count > 1) {
398
--self->count;
399
Py_RETURN_NONE;
400
}
401
assert(self->count == 1);
402
} else {
403
#ifdef HAVE_BROKEN_SEM_GETVALUE
404
/* We will only check properly the maxvalue == 1 case */
405
if (self->maxvalue == 1) {
406
/* make sure that already locked */
407
if (sem_trywait(self->handle) < 0) {
408
if (errno != EAGAIN) {
409
PyErr_SetFromErrno(PyExc_OSError);
410
return NULL;
411
}
412
/* it is already locked as expected */
413
} else {
414
/* it was not locked so undo wait and raise */
415
if (sem_post(self->handle) < 0) {
416
PyErr_SetFromErrno(PyExc_OSError);
417
return NULL;
418
}
419
PyErr_SetString(PyExc_ValueError, "semaphore "
420
"or lock released too many "
421
"times");
422
return NULL;
423
}
424
}
425
#else
426
int sval;
427
428
/* This check is not an absolute guarantee that the semaphore
429
does not rise above maxvalue. */
430
if (sem_getvalue(self->handle, &sval) < 0) {
431
return PyErr_SetFromErrno(PyExc_OSError);
432
} else if (sval >= self->maxvalue) {
433
PyErr_SetString(PyExc_ValueError, "semaphore or lock "
434
"released too many times");
435
return NULL;
436
}
437
#endif
438
}
439
440
if (sem_post(self->handle) < 0)
441
return PyErr_SetFromErrno(PyExc_OSError);
442
443
--self->count;
444
Py_RETURN_NONE;
445
}
446
447
#endif /* !MS_WINDOWS */
448
449
/*
450
* All platforms
451
*/
452
453
static PyObject *
454
newsemlockobject(PyTypeObject *type, SEM_HANDLE handle, int kind, int maxvalue,
455
char *name)
456
{
457
SemLockObject *self = (SemLockObject *)type->tp_alloc(type, 0);
458
if (!self)
459
return NULL;
460
self->handle = handle;
461
self->kind = kind;
462
self->count = 0;
463
self->last_tid = 0;
464
self->maxvalue = maxvalue;
465
self->name = name;
466
return (PyObject*)self;
467
}
468
469
/*[clinic input]
470
@classmethod
471
_multiprocessing.SemLock.__new__
472
473
kind: int
474
value: int
475
maxvalue: int
476
name: str
477
unlink: bool
478
479
[clinic start generated code]*/
480
481
static PyObject *
482
_multiprocessing_SemLock_impl(PyTypeObject *type, int kind, int value,
483
int maxvalue, const char *name, int unlink)
484
/*[clinic end generated code: output=30727e38f5f7577a input=fdaeb69814471c5b]*/
485
{
486
SEM_HANDLE handle = SEM_FAILED;
487
PyObject *result;
488
char *name_copy = NULL;
489
490
if (kind != RECURSIVE_MUTEX && kind != SEMAPHORE) {
491
PyErr_SetString(PyExc_ValueError, "unrecognized kind");
492
return NULL;
493
}
494
495
if (!unlink) {
496
name_copy = PyMem_Malloc(strlen(name) + 1);
497
if (name_copy == NULL) {
498
return PyErr_NoMemory();
499
}
500
strcpy(name_copy, name);
501
}
502
503
SEM_CLEAR_ERROR();
504
handle = SEM_CREATE(name, value, maxvalue);
505
/* On Windows we should fail if GetLastError()==ERROR_ALREADY_EXISTS */
506
if (handle == SEM_FAILED || SEM_GET_LAST_ERROR() != 0)
507
goto failure;
508
509
if (unlink && SEM_UNLINK(name) < 0)
510
goto failure;
511
512
result = newsemlockobject(type, handle, kind, maxvalue, name_copy);
513
if (!result)
514
goto failure;
515
516
return result;
517
518
failure:
519
if (handle != SEM_FAILED)
520
SEM_CLOSE(handle);
521
PyMem_Free(name_copy);
522
if (!PyErr_Occurred()) {
523
_PyMp_SetError(NULL, MP_STANDARD_ERROR);
524
}
525
return NULL;
526
}
527
528
/*[clinic input]
529
@classmethod
530
_multiprocessing.SemLock._rebuild
531
532
handle: SEM_HANDLE
533
kind: int
534
maxvalue: int
535
name: str(accept={str, NoneType})
536
/
537
538
[clinic start generated code]*/
539
540
static PyObject *
541
_multiprocessing_SemLock__rebuild_impl(PyTypeObject *type, SEM_HANDLE handle,
542
int kind, int maxvalue,
543
const char *name)
544
/*[clinic end generated code: output=2aaee14f063f3bd9 input=f7040492ac6d9962]*/
545
{
546
char *name_copy = NULL;
547
548
if (name != NULL) {
549
name_copy = PyMem_Malloc(strlen(name) + 1);
550
if (name_copy == NULL)
551
return PyErr_NoMemory();
552
strcpy(name_copy, name);
553
}
554
555
#ifndef MS_WINDOWS
556
if (name != NULL) {
557
handle = sem_open(name, 0);
558
if (handle == SEM_FAILED) {
559
PyMem_Free(name_copy);
560
return PyErr_SetFromErrno(PyExc_OSError);
561
}
562
}
563
#endif
564
565
return newsemlockobject(type, handle, kind, maxvalue, name_copy);
566
}
567
568
static void
569
semlock_dealloc(SemLockObject* self)
570
{
571
PyTypeObject *tp = Py_TYPE(self);
572
PyObject_GC_UnTrack(self);
573
if (self->handle != SEM_FAILED)
574
SEM_CLOSE(self->handle);
575
PyMem_Free(self->name);
576
tp->tp_free(self);
577
Py_DECREF(tp);
578
}
579
580
/*[clinic input]
581
_multiprocessing.SemLock._count
582
583
Num of `acquire()`s minus num of `release()`s for this process.
584
[clinic start generated code]*/
585
586
static PyObject *
587
_multiprocessing_SemLock__count_impl(SemLockObject *self)
588
/*[clinic end generated code: output=5ba8213900e517bb input=36fc59b1cd1025ab]*/
589
{
590
return PyLong_FromLong((long)self->count);
591
}
592
593
/*[clinic input]
594
_multiprocessing.SemLock._is_mine
595
596
Whether the lock is owned by this thread.
597
[clinic start generated code]*/
598
599
static PyObject *
600
_multiprocessing_SemLock__is_mine_impl(SemLockObject *self)
601
/*[clinic end generated code: output=92dc98863f4303be input=a96664cb2f0093ba]*/
602
{
603
/* only makes sense for a lock */
604
return PyBool_FromLong(ISMINE(self));
605
}
606
607
/*[clinic input]
608
_multiprocessing.SemLock._get_value
609
610
Get the value of the semaphore.
611
[clinic start generated code]*/
612
613
static PyObject *
614
_multiprocessing_SemLock__get_value_impl(SemLockObject *self)
615
/*[clinic end generated code: output=64bc1b89bda05e36 input=cb10f9a769836203]*/
616
{
617
#ifdef HAVE_BROKEN_SEM_GETVALUE
618
PyErr_SetNone(PyExc_NotImplementedError);
619
return NULL;
620
#else
621
int sval;
622
if (SEM_GETVALUE(self->handle, &sval) < 0)
623
return _PyMp_SetError(NULL, MP_STANDARD_ERROR);
624
/* some posix implementations use negative numbers to indicate
625
the number of waiting threads */
626
if (sval < 0)
627
sval = 0;
628
return PyLong_FromLong((long)sval);
629
#endif
630
}
631
632
/*[clinic input]
633
_multiprocessing.SemLock._is_zero
634
635
Return whether semaphore has value zero.
636
[clinic start generated code]*/
637
638
static PyObject *
639
_multiprocessing_SemLock__is_zero_impl(SemLockObject *self)
640
/*[clinic end generated code: output=815d4c878c806ed7 input=294a446418d31347]*/
641
{
642
#ifdef HAVE_BROKEN_SEM_GETVALUE
643
if (sem_trywait(self->handle) < 0) {
644
if (errno == EAGAIN)
645
Py_RETURN_TRUE;
646
return _PyMp_SetError(NULL, MP_STANDARD_ERROR);
647
} else {
648
if (sem_post(self->handle) < 0)
649
return _PyMp_SetError(NULL, MP_STANDARD_ERROR);
650
Py_RETURN_FALSE;
651
}
652
#else
653
int sval;
654
if (SEM_GETVALUE(self->handle, &sval) < 0)
655
return _PyMp_SetError(NULL, MP_STANDARD_ERROR);
656
return PyBool_FromLong((long)sval == 0);
657
#endif
658
}
659
660
/*[clinic input]
661
_multiprocessing.SemLock._after_fork
662
663
Rezero the net acquisition count after fork().
664
[clinic start generated code]*/
665
666
static PyObject *
667
_multiprocessing_SemLock__after_fork_impl(SemLockObject *self)
668
/*[clinic end generated code: output=718bb27914c6a6c1 input=190991008a76621e]*/
669
{
670
self->count = 0;
671
Py_RETURN_NONE;
672
}
673
674
/*[clinic input]
675
_multiprocessing.SemLock.__enter__
676
677
Enter the semaphore/lock.
678
[clinic start generated code]*/
679
680
static PyObject *
681
_multiprocessing_SemLock___enter___impl(SemLockObject *self)
682
/*[clinic end generated code: output=beeb2f07c858511f input=c5e27d594284690b]*/
683
{
684
return _multiprocessing_SemLock_acquire_impl(self, 1, Py_None);
685
}
686
687
/*[clinic input]
688
_multiprocessing.SemLock.__exit__
689
690
exc_type: object = None
691
exc_value: object = None
692
exc_tb: object = None
693
/
694
695
Exit the semaphore/lock.
696
[clinic start generated code]*/
697
698
static PyObject *
699
_multiprocessing_SemLock___exit___impl(SemLockObject *self,
700
PyObject *exc_type,
701
PyObject *exc_value, PyObject *exc_tb)
702
/*[clinic end generated code: output=3b37c1a9f8b91a03 input=7d644b64a89903f8]*/
703
{
704
return _multiprocessing_SemLock_release_impl(self);
705
}
706
707
static int
708
semlock_traverse(SemLockObject *s, visitproc visit, void *arg)
709
{
710
Py_VISIT(Py_TYPE(s));
711
return 0;
712
}
713
714
/*
715
* Semaphore methods
716
*/
717
718
static PyMethodDef semlock_methods[] = {
719
_MULTIPROCESSING_SEMLOCK_ACQUIRE_METHODDEF
720
_MULTIPROCESSING_SEMLOCK_RELEASE_METHODDEF
721
_MULTIPROCESSING_SEMLOCK___ENTER___METHODDEF
722
_MULTIPROCESSING_SEMLOCK___EXIT___METHODDEF
723
_MULTIPROCESSING_SEMLOCK__COUNT_METHODDEF
724
_MULTIPROCESSING_SEMLOCK__IS_MINE_METHODDEF
725
_MULTIPROCESSING_SEMLOCK__GET_VALUE_METHODDEF
726
_MULTIPROCESSING_SEMLOCK__IS_ZERO_METHODDEF
727
_MULTIPROCESSING_SEMLOCK__REBUILD_METHODDEF
728
_MULTIPROCESSING_SEMLOCK__AFTER_FORK_METHODDEF
729
{NULL}
730
};
731
732
/*
733
* Member table
734
*/
735
736
static PyMemberDef semlock_members[] = {
737
{"handle", T_SEM_HANDLE, offsetof(SemLockObject, handle), READONLY,
738
""},
739
{"kind", T_INT, offsetof(SemLockObject, kind), READONLY,
740
""},
741
{"maxvalue", T_INT, offsetof(SemLockObject, maxvalue), READONLY,
742
""},
743
{"name", T_STRING, offsetof(SemLockObject, name), READONLY,
744
""},
745
{NULL}
746
};
747
748
/*
749
* Semaphore type
750
*/
751
752
static PyType_Slot _PyMp_SemLockType_slots[] = {
753
{Py_tp_dealloc, semlock_dealloc},
754
{Py_tp_getattro, PyObject_GenericGetAttr},
755
{Py_tp_setattro, PyObject_GenericSetAttr},
756
{Py_tp_methods, semlock_methods},
757
{Py_tp_members, semlock_members},
758
{Py_tp_alloc, PyType_GenericAlloc},
759
{Py_tp_new, _multiprocessing_SemLock},
760
{Py_tp_traverse, semlock_traverse},
761
{Py_tp_free, PyObject_GC_Del},
762
{Py_tp_doc, (void *)PyDoc_STR("Semaphore/Mutex type")},
763
{0, 0},
764
};
765
766
PyType_Spec _PyMp_SemLockType_spec = {
767
.name = "_multiprocessing.SemLock",
768
.basicsize = sizeof(SemLockObject),
769
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
770
Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE),
771
.slots = _PyMp_SemLockType_slots,
772
};
773
774
/*
775
* Function to unlink semaphore names
776
*/
777
778
PyObject *
779
_PyMp_sem_unlink(const char *name)
780
{
781
if (SEM_UNLINK(name) < 0) {
782
_PyMp_SetError(NULL, MP_STANDARD_ERROR);
783
return NULL;
784
}
785
786
Py_RETURN_NONE;
787
}
788
789
#endif // HAVE_MP_SEMAPHORE
790
791