process_shared 0.1.6 → 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,9 +0,0 @@
1
- require 'mkmf'
2
-
3
- #have_func("pthread_mutex_init", "pthread.h")
4
- #have_func("pthread_cond_init", "pthread.h")
5
- #have_func("pthread_mutex_trylock", "pthread.h")
6
-
7
- have_library("pthread", "pthread_mutex_init")
8
-
9
- create_makefile("pthread_sync_helper")
@@ -1,43 +0,0 @@
1
- #include <pthread.h>
2
- #include <sys/mman.h> /* PROT_*, MAP_* */
3
- #include <fcntl.h> /* O_* */
4
-
5
- /* Declarations. These are split this way to avoid compiler warnings. */
6
-
7
- extern size_t sizeof_pthread_mutex_t;
8
- extern size_t sizeof_pthread_mutexattr_t;
9
-
10
- extern int pthread_process_shared;
11
-
12
- extern int o_rdwr;
13
- extern int o_creat;
14
-
15
- extern int prot_read;
16
- extern int prot_write;
17
- extern int prot_exec;
18
- extern int prot_none;
19
-
20
- extern void * map_failed;
21
-
22
- extern int map_shared;
23
- extern int map_private;
24
-
25
- /* Definitions. These are split from declrations to avoid compiler warnings. */
26
-
27
- size_t sizeof_pthread_mutex_t = sizeof (pthread_mutex_t);
28
- size_t sizeof_pthread_mutexattr_t = sizeof (pthread_mutexattr_t);
29
-
30
- int pthread_process_shared = PTHREAD_PROCESS_SHARED;
31
-
32
- int o_rdwr = O_RDWR;
33
- int o_creat = O_CREAT;
34
-
35
- int prot_read = PROT_READ;
36
- int prot_write = PROT_WRITE;
37
- int prot_exec = PROT_EXEC;
38
- int prot_none = PROT_NONE;
39
-
40
- void * map_failed = MAP_FAILED;
41
-
42
- int map_shared = MAP_SHARED;
43
- int map_private = MAP_PRIVATE;
data/ext/semaphore.c DELETED
@@ -1,623 +0,0 @@
1
- /*
2
- * A type which wraps a semaphore
3
- *
4
- * semaphore.c
5
- *
6
- * Copyright (c) 2006-2008, R Oudkerk
7
- *
8
- * All rights reserved.
9
- *
10
- * Redistribution and use in source and binary forms, with or without
11
- * modification, are permitted provided that the following conditions
12
- * are met:
13
- *
14
- * 1. Redistributions of source code must retain the above copyright
15
- * notice, this list of conditions and the following disclaimer.
16
- *
17
- * 2. Redistributions in binary form must reproduce the above
18
- * copyright notice, this list of conditions and the following
19
- * disclaimer in the documentation and/or other materials provided
20
- * with the distribution.
21
- *
22
- * 3. Neither the name of author nor the names of any contributors
23
- * may be used to endorse or promote products derived from this
24
- * software without specific prior written permission.
25
- *
26
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS"
27
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
29
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
30
- * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
33
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
34
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
36
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37
- * POSSIBILITY OF SUCH DAMAGE.
38
- */
39
-
40
- /*
41
- * Modifications Copyright (c) 2011, Patrick Mahoney
42
- */
43
-
44
- #include "processing.h"
45
-
46
- enum {
47
- RECURSIVE_MUTEX,
48
- SEMAPHORE,
49
- BOUNDED_SEMAPHORE
50
- };
51
-
52
- typedef struct {
53
- PyObject_HEAD
54
- SEM_HANDLE handle;
55
- long last_tid;
56
- int count;
57
- int maxvalue;
58
- int kind;
59
- } SemLock;
60
-
61
- #define ISMINE(o) (o->count > 0 && PyThread_get_thread_ident() == o->last_tid)
62
-
63
-
64
- #ifdef MS_WINDOWS
65
-
66
- /*
67
- * Windows definitions
68
- */
69
-
70
- static SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
71
-
72
- #define SEM_FAILED NULL
73
-
74
- #define SEM_CLEAR_ERROR() SetLastError(0)
75
- #define SEM_GET_LAST_ERROR() GetLastError()
76
- #define SEM_CREATE(name, val, max) CreateSemaphore(&sa, val, max, NULL)
77
- #define SEM_CLOSE(sem) (CloseHandle(sem) ? 0 : -1)
78
- #define SEM_GETVALUE(sem, pval) _SemLock_GetSemaphoreValue(sem, pval)
79
- #define SEM_UNLINK(name) 0
80
-
81
- static int
82
- _SemLock_GetSemaphoreValue(HANDLE handle, long *value)
83
- {
84
- long previous;
85
-
86
- switch (WaitForSingleObject(handle, 0)) {
87
- case WAIT_OBJECT_0:
88
- if (!ReleaseSemaphore(handle, 1, &previous))
89
- return STANDARD_ERROR;
90
- *value = previous + 1;
91
- return 0;
92
- case WAIT_TIMEOUT:
93
- *value = 0;
94
- return 0;
95
- default:
96
- return STANDARD_ERROR;
97
- }
98
- }
99
-
100
- static PyObject *
101
- SemLock_acquire(SemLock *self, PyObject *args, PyObject *kwds)
102
- {
103
- int blocking = 1;
104
- double timeout;
105
- PyObject *timeout_obj = Py_None;
106
- DWORD res, dwTimeout;
107
-
108
- static char *kwlist[] = {"block", "timeout", NULL};
109
-
110
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iO", kwlist,
111
- &blocking, &timeout_obj))
112
- return NULL;
113
-
114
- if (self->kind == RECURSIVE_MUTEX && ISMINE(self)) {
115
- ++self->count;
116
- Py_RETURN_TRUE;
117
- }
118
-
119
- /* work out timeout */
120
- if (!blocking) {
121
- dwTimeout = 0;
122
- } else if (timeout_obj == Py_None) {
123
- dwTimeout = INFINITE;
124
- } else {
125
- timeout = PyFloat_AsDouble(timeout_obj);
126
- if (PyErr_Occurred())
127
- return NULL;
128
- timeout *= 1000.0; /* convert to millisecs */
129
- if (timeout < 0.0) {
130
- timeout = 0.0;
131
- } else if (timeout >= ((double)INFINITE - 0.5)) {
132
- PyErr_SetString(PyExc_OverflowError, "timeout is too large");
133
- return NULL;
134
- }
135
- dwTimeout = (DWORD)(timeout + 0.5);
136
- }
137
-
138
- /* do the wait */
139
- if (dwTimeout == 0) {
140
- res = WaitForSingleObject(self->handle, 0);
141
- } else if (main_thread == GetCurrentThreadId()) {
142
- res = WaitForSingleObject(self->handle, 0);
143
- if (res == WAIT_TIMEOUT) {
144
- HANDLE handles[2] = {self->handle, hInterruptEvent};
145
- ResetEvent(hInterruptEvent);
146
- Py_BEGIN_ALLOW_THREADS
147
- res = WaitForMultipleObjects(2, handles, FALSE, dwTimeout);
148
- Py_END_ALLOW_THREADS
149
- }
150
- } else {
151
- Py_BEGIN_ALLOW_THREADS
152
- res = WaitForSingleObject(self->handle, dwTimeout);
153
- Py_END_ALLOW_THREADS
154
- }
155
-
156
- /* handle result */
157
- switch (res) {
158
- case WAIT_TIMEOUT:
159
- Py_RETURN_FALSE;
160
- case WAIT_OBJECT_0:
161
- self->last_tid = GetCurrentThreadId();
162
- ++self->count;
163
- Py_RETURN_TRUE;
164
- case (WAIT_OBJECT_0 + 1): /* we got SIGINT; do like in timemodule.c */
165
- Sleep(1);
166
- errno = EINTR;
167
- PyErr_SetFromErrno(PyExc_OSError);
168
- return NULL;
169
- case WAIT_FAILED:
170
- return PyErr_SetFromWindowsErr(0);
171
- default:
172
- PyErr_SetString(PyExc_RuntimeError, "WaitForSingleObject() or "
173
- "WaitForMultipleObjects() gave unrecognized value");
174
- return NULL;
175
- }
176
- }
177
-
178
- static PyObject *
179
- SemLock_release(SemLock *self, PyObject *args)
180
- {
181
- if (self->kind == RECURSIVE_MUTEX) {
182
- if (!ISMINE(self)) {
183
- PyErr_SetString(PyExc_AssertionError, "attempt to release "
184
- "recursive lock not owned 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,
197
- "semaphore or lock 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
- #if HAVE_BROKEN_SEM_UNLINK
222
- # define sem_unlink(name) 0
223
- #endif
224
-
225
- #if !HAVE_SEM_TIMEDWAIT
226
- # define sem_timedwait(sem,deadline) sem_timedwait_save(sem,deadline,_save)
227
-
228
- int
229
- sem_timedwait_save(sem_t *sem, struct timespec *deadline, PyThreadState *_save)
230
- {
231
- int res;
232
- unsigned long delay, difference;
233
- struct timeval now, tvdeadline, tvdelay;
234
-
235
- errno = 0;
236
- tvdeadline.tv_sec = deadline->tv_sec;
237
- tvdeadline.tv_usec = deadline->tv_nsec / 1000;
238
-
239
- for (delay = 0 ; ; delay += 1000) {
240
- /* poll */
241
- if (sem_trywait(sem) == 0)
242
- return 0;
243
- else if (errno != EAGAIN)
244
- return STANDARD_ERROR;
245
-
246
- /* get current time */
247
- if (gettimeofday(&now, NULL) < 0)
248
- return STANDARD_ERROR;
249
-
250
- /* check for timeout */
251
- if (tvdeadline.tv_sec < now.tv_sec ||
252
- (tvdeadline.tv_sec == now.tv_sec &&
253
- tvdeadline.tv_usec <= now.tv_usec)) {
254
- errno = ETIMEDOUT;
255
- return STANDARD_ERROR;
256
- }
257
-
258
- /* calculate how much time is left */
259
- difference = (tvdeadline.tv_sec - now.tv_sec) * 1000000 +
260
- (tvdeadline.tv_usec - now.tv_usec);
261
-
262
- /* check delay not too long -- maximum is 20 msecs */
263
- if (delay > 20000)
264
- delay = 20000;
265
- if (delay > difference)
266
- delay = difference;
267
-
268
- /* sleep */
269
- tvdelay.tv_sec = delay / 1000000;
270
- tvdelay.tv_usec = delay % 1000000;
271
- if (select(0, NULL, NULL, NULL, &tvdelay) < 0)
272
- return STANDARD_ERROR;
273
-
274
- /* check for signals */
275
- Py_BLOCK_THREADS
276
- res = PyErr_CheckSignals();
277
- Py_UNBLOCK_THREADS
278
-
279
- if (res) {
280
- errno = EINTR;
281
- return EXCEPTION_HAS_BEEN_SET;
282
- }
283
- }
284
- }
285
-
286
- #endif /* !HAVE_SEM_TIMEDWAIT */
287
-
288
- static PyObject *
289
- SemLock_acquire(SemLock *self, PyObject *args, PyObject *kwds)
290
- {
291
- int blocking = 1, res;
292
- double timeout;
293
- PyObject *timeout_obj = Py_None;
294
- struct timespec deadline = {0};
295
- struct timeval now;
296
- long sec, nsec;
297
-
298
- static char *kwlist[] = {"block", "timeout", NULL};
299
-
300
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iO", kwlist,
301
- &blocking, &timeout_obj))
302
- return NULL;
303
-
304
- if (self->kind == RECURSIVE_MUTEX && ISMINE(self)) {
305
- ++self->count;
306
- Py_RETURN_TRUE;
307
- }
308
-
309
- if (timeout_obj != Py_None) {
310
- timeout = PyFloat_AsDouble(timeout_obj);
311
- if (PyErr_Occurred())
312
- return NULL;
313
- if (timeout < 0.0)
314
- timeout = 0.0;
315
-
316
- if (gettimeofday(&now, NULL) < 0) {
317
- PyErr_SetFromErrno(PyExc_OSError);
318
- return NULL;
319
- }
320
- sec = (long) timeout;
321
- nsec = (long) (1e9 * (timeout - sec) + 0.5);
322
- deadline.tv_sec = now.tv_sec + sec;
323
- deadline.tv_nsec = now.tv_usec * 1000 + nsec;
324
- deadline.tv_sec += (deadline.tv_nsec / 1000000000);
325
- deadline.tv_nsec %= 1000000000;
326
- }
327
-
328
- do {
329
- Py_BEGIN_ALLOW_THREADS
330
- if (blocking && timeout_obj == Py_None)
331
- res = sem_wait(self->handle);
332
- else if (!blocking)
333
- res = sem_trywait(self->handle);
334
- else
335
- res = sem_timedwait(self->handle, &deadline);
336
- Py_END_ALLOW_THREADS
337
- if (res == EXCEPTION_HAS_BEEN_SET)
338
- break;
339
- } while (res < 0 && errno == EINTR && !PyErr_CheckSignals());
340
-
341
- if (res < 0) {
342
- if (errno == EAGAIN || errno == ETIMEDOUT)
343
- Py_RETURN_FALSE;
344
- else if (errno == EINTR)
345
- return NULL;
346
- else
347
- return PyErr_SetFromErrno(PyExc_OSError);
348
- }
349
-
350
- ++self->count;
351
- self->last_tid = PyThread_get_thread_ident();
352
-
353
- Py_RETURN_TRUE;
354
- }
355
-
356
- static PyObject *
357
- SemLock_release(SemLock *self, PyObject *args)
358
- {
359
- switch (self->kind) {
360
- case RECURSIVE_MUTEX:
361
- if (!ISMINE(self)) {
362
- PyErr_SetString(PyExc_AssertionError, "attempt to release "
363
- "recursive lock not owned by thread");
364
- return NULL;
365
- }
366
- if (self->count > 1) {
367
- --self->count;
368
- Py_RETURN_NONE;
369
- }
370
- assert(self->count == 1);
371
- break;
372
- #if HAVE_BROKEN_SEM_GETVALUE
373
- case BOUNDED_SEMAPHORE:
374
- /* We will only check properly the Lock case (where maxvalue == 1) */
375
- if (self->maxvalue == 1) {
376
- /* make sure that already locked */
377
- if (sem_trywait(self->handle) < 0) {
378
- if (errno != EAGAIN)
379
- return PyErr_SetFromErrno(PyExc_OSError);
380
- /* it is already locked as expected */
381
- } else {
382
- /* it was not locked -- so undo wait and raise error */
383
- if (sem_post(self->handle) < 0)
384
- return PyErr_SetFromErrno(PyExc_OSError);
385
- PyErr_SetString(PyExc_ValueError,
386
- "semaphore or lock released too many times");
387
- return NULL;
388
- }
389
- }
390
- #else
391
- case BOUNDED_SEMAPHORE:
392
- {
393
- int sval;
394
-
395
- /* This check is not an absolute guarantee that the semaphore
396
- does not rise above maxvalue. */
397
- if (sem_getvalue(self->handle, &sval) < 0) {
398
- return PyErr_SetFromErrno(PyExc_OSError);
399
- } else if (sval >= self->maxvalue) {
400
- PyErr_SetString(PyExc_ValueError,
401
- "semaphore or lock released too many times");
402
- return NULL;
403
- }
404
- }
405
- #endif
406
- }
407
-
408
- if (sem_post(self->handle) < 0)
409
- return PyErr_SetFromErrno(PyExc_OSError);
410
-
411
- --self->count;
412
- Py_RETURN_NONE;
413
- }
414
-
415
- #endif /* !MS_WINDOWS */
416
-
417
- /*
418
- * All platforms
419
- */
420
-
421
- static PyObject *
422
- _SemLock_create(PyTypeObject *type, SEM_HANDLE handle, int kind, int maxvalue)
423
- {
424
- SemLock *self;
425
-
426
- self = (SemLock*)type->tp_alloc(type, 0);
427
- if (!self)
428
- return NULL;
429
- self->handle = handle;
430
- self->kind = kind;
431
- self->count = 0;
432
- self->last_tid = 0;
433
- self->maxvalue = maxvalue;
434
- return (PyObject*)self;
435
- }
436
-
437
- static PyObject *
438
- SemLock_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
439
- {
440
- char buffer[256];
441
- SEM_HANDLE handle = SEM_FAILED;
442
- int kind, maxvalue, value;
443
- PyObject *result;
444
- static char *kwlist[] = {"kind", "value", NULL};
445
- static int counter = 0;
446
-
447
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "ii", kwlist, &kind, &value))
448
- return NULL;
449
-
450
- if (kind < RECURSIVE_MUTEX || kind > BOUNDED_SEMAPHORE) {
451
- PyErr_SetString(PyExc_ValueError, "unrecongnized blocker type");
452
- return NULL;
453
- }
454
-
455
- PyOS_snprintf(buffer, sizeof(buffer), "/pr%d-%d", getpid(), counter++);
456
-
457
- if (kind == BOUNDED_SEMAPHORE)
458
- maxvalue = value;
459
- else if (kind == RECURSIVE_MUTEX)
460
- maxvalue = 1;
461
- else
462
- maxvalue = INT_MAX;
463
-
464
- SEM_CLEAR_ERROR();
465
- handle = SEM_CREATE(buffer, value, maxvalue);
466
- /* On Windows we should fail if GetLastError() == ERROR_ALREADY_EXISTS */
467
- if (handle == SEM_FAILED || SEM_GET_LAST_ERROR() != 0)
468
- goto failure;
469
-
470
- if (SEM_UNLINK(buffer) < 0)
471
- goto failure;
472
-
473
- result = _SemLock_create(type, handle, kind, maxvalue);
474
- if (!result)
475
- goto failure;
476
-
477
- return result;
478
-
479
- failure:
480
- if (handle != SEM_FAILED)
481
- SEM_CLOSE(handle);
482
- SetException(NULL, STANDARD_ERROR);
483
- return NULL;
484
- }
485
-
486
- static PyObject *
487
- SemLock_rebuild(PyTypeObject *type, PyObject *args)
488
- {
489
- SEM_HANDLE handle;
490
- int kind, maxvalue;
491
-
492
- if (!PyArg_ParseTuple(args, F_SEM_HANDLE "ii", &handle, &kind, &maxvalue))
493
- return NULL;
494
-
495
- return _SemLock_create(type, handle, kind, maxvalue);
496
- }
497
-
498
- static void
499
- SemLock_dealloc(SemLock* self)
500
- {
501
- if (self->handle != SEM_FAILED)
502
- SEM_CLOSE(self->handle);
503
- self->ob_type->tp_free((PyObject*)self);
504
- }
505
-
506
- static PyObject *
507
- SemLock_count(SemLock *self)
508
- {
509
- return PyInt_FromLong((long)self->count);
510
- }
511
-
512
- static PyObject *
513
- SemLock_ismine(SemLock *self)
514
- {
515
- /* only makes sense for a lock */
516
- return PyBool_FromLong(ISMINE(self));
517
- }
518
-
519
- static PyObject *
520
- SemLock_getvalue(SemLock *self)
521
- {
522
- #if HAVE_BROKEN_SEM_GETVALUE
523
- PyErr_SetNone(PyExc_NotImplementedError);
524
- return NULL;
525
- #else
526
- int sval;
527
- if (SEM_GETVALUE(self->handle, &sval) < 0)
528
- SetException(NULL, STANDARD_ERROR);
529
- return PyInt_FromLong((long)sval);
530
- #endif
531
- }
532
-
533
- static PyObject *
534
- SemLock_afterfork(SemLock *self)
535
- {
536
- self->count = 0;
537
- Py_RETURN_NONE;
538
- }
539
-
540
- /*
541
- * Semaphore methods
542
- */
543
-
544
- static PyMethodDef SemLock_methods[] = {
545
- {"acquire", (PyCFunction)SemLock_acquire, METH_KEYWORDS,
546
- "acquire the semaphore/lock"},
547
- {"release", (PyCFunction)SemLock_release, METH_NOARGS,
548
- "release the semaphore/lock"},
549
- {"__enter__", (PyCFunction)SemLock_acquire, METH_KEYWORDS,
550
- "enter the semaphore/lock"},
551
- {"__exit__", (PyCFunction)SemLock_release, METH_VARARGS,
552
- "exit the semaphore/lock"},
553
- {"_count", (PyCFunction)SemLock_count, METH_NOARGS,
554
- "number of `acquire()`s minus number of `release()`s for this process"},
555
- {"_isMine", (PyCFunction)SemLock_ismine, METH_NOARGS,
556
- "whether the lock is owned by this thread"},
557
- {"_getValue", (PyCFunction)SemLock_getvalue, METH_NOARGS,
558
- "get the value of the semaphore"},
559
- {"_rebuild", (PyCFunction)SemLock_rebuild, METH_VARARGS | METH_CLASS,
560
- ""},
561
- {"_afterFork", (PyCFunction)SemLock_afterfork, METH_NOARGS,
562
- "rezero the net acquisition count after fork()"},
563
- {NULL}
564
- };
565
-
566
- /*
567
- * Member table
568
- */
569
-
570
- static PyMemberDef SemLock_members[] = {
571
- {"handle", T_SEM_HANDLE, offsetof(SemLock, handle), READONLY, ""},
572
- {"kind", T_INT, offsetof(SemLock, kind), READONLY, ""},
573
- {"maxvalue", T_INT, offsetof(SemLock, maxvalue), READONLY, ""},
574
- {NULL}
575
- };
576
-
577
- /*
578
- * Semaphore type
579
- */
580
-
581
- PyTypeObject SemLockType = {
582
- PyObject_HEAD_INIT(NULL)
583
- 0, /* ob_size */
584
- "_processing.SemLock", /* tp_name */
585
- sizeof(SemLock), /* tp_basicsize */
586
- 0, /* tp_itemsize */
587
- (destructor)SemLock_dealloc,
588
- /* tp_dealloc */
589
- 0, /* tp_print */
590
- 0, /* tp_getattr */
591
- 0, /* tp_setattr */
592
- 0, /* tp_compare */
593
- 0, /* tp_repr */
594
- 0, /* tp_as_number */
595
- 0, /* tp_as_sequence */
596
- 0, /* tp_as_mapping */
597
- 0, /* tp_hash */
598
- 0, /* tp_call */
599
- 0, /* tp_str */
600
- 0, /* tp_getattro */
601
- 0, /* tp_setattro */
602
- 0, /* tp_as_buffer */
603
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
604
- /* tp_flags */
605
- "Semaphore/Mutex type", /* tp_doc */
606
- 0, /* tp_traverse */
607
- 0, /* tp_clear */
608
- 0, /* tp_richcompare */
609
- 0, /* tp_weaklistoffset */
610
- 0, /* tp_iter */
611
- 0, /* tp_iternext */
612
- SemLock_methods, /* tp_methods */
613
- SemLock_members, /* tp_members */
614
- 0, /* tp_getset */
615
- 0, /* tp_base */
616
- 0, /* tp_dict */
617
- 0, /* tp_descr_get */
618
- 0, /* tp_descr_set */
619
- 0, /* tp_dictoffset */
620
- 0, /* tp_init */
621
- 0, /* tp_alloc */
622
- (newfunc)SemLock_new, /* tp_new */
623
- };