ยปCore Development>Code coverage>Modules/_multiprocessing/semaphore.c

Python code coverage for Modules/_multiprocessing/semaphore.c

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