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 14enum { RECURSIVE_MUTEX, SEMAPHORE }; 15 16typedef 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] 27class 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] 35module _multiprocessing 36class _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 60static 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(accept={int}) = True 83 timeout as timeout_obj: object = None 84 85Acquire the semaphore/lock. 86[clinic start generated code]*/ 87 88static PyObject * 89_multiprocessing_SemLock_acquire_impl(SemLockObject *self, int blocking, 90 PyObject *timeout_obj) 91/*[clinic end generated code: output=f9998f0b6b0b0872 input=86f05662cf753eb4]*/ 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 173Release the semaphore/lock. 174[clinic start generated code]*/ 175 176static 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 235static int 236sem_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(accept={int}) = True 299 timeout as timeout_obj: object = None 300 301Acquire the semaphore/lock. 302[clinic start generated code]*/ 303 304static PyObject * 305_multiprocessing_SemLock_acquire_impl(SemLockObject *self, int blocking, 306 PyObject *timeout_obj) 307/*[clinic end generated code: output=f9998f0b6b0b0872 input=86f05662cf753eb4]*/ 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 383Release the semaphore/lock. 384[clinic start generated code]*/ 385 386static 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 453static PyObject * 454newsemlockobject(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(accept={int}) 478 479[clinic start generated code]*/ 480 481static 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=b378c3ee27d3a0fa]*/ 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 540static 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 568static void 569semlock_dealloc(SemLockObject* self) 570{ 571 if (self->handle != SEM_FAILED) 572 SEM_CLOSE(self->handle); 573 PyMem_Free(self->name); 574 Py_TYPE(self)->tp_free((PyObject*)self); 575} 576 577/*[clinic input] 578_multiprocessing.SemLock._count 579 580Num of `acquire()`s minus num of `release()`s for this process. 581[clinic start generated code]*/ 582 583static PyObject * 584_multiprocessing_SemLock__count_impl(SemLockObject *self) 585/*[clinic end generated code: output=5ba8213900e517bb input=36fc59b1cd1025ab]*/ 586{ 587 return PyLong_FromLong((long)self->count); 588} 589 590/*[clinic input] 591_multiprocessing.SemLock._is_mine 592 593Whether the lock is owned by this thread. 594[clinic start generated code]*/ 595 596static PyObject * 597_multiprocessing_SemLock__is_mine_impl(SemLockObject *self) 598/*[clinic end generated code: output=92dc98863f4303be input=a96664cb2f0093ba]*/ 599{ 600 /* only makes sense for a lock */ 601 return PyBool_FromLong(ISMINE(self)); 602} 603 604/*[clinic input] 605_multiprocessing.SemLock._get_value 606 607Get the value of the semaphore. 608[clinic start generated code]*/ 609 610static PyObject * 611_multiprocessing_SemLock__get_value_impl(SemLockObject *self) 612/*[clinic end generated code: output=64bc1b89bda05e36 input=cb10f9a769836203]*/ 613{ 614#ifdef HAVE_BROKEN_SEM_GETVALUE 615 PyErr_SetNone(PyExc_NotImplementedError); 616 return NULL; 617#else 618 int sval; 619 if (SEM_GETVALUE(self->handle, &sval) < 0) 620 return _PyMp_SetError(NULL, MP_STANDARD_ERROR); 621 /* some posix implementations use negative numbers to indicate 622 the number of waiting threads */ 623 if (sval < 0) 624 sval = 0; 625 return PyLong_FromLong((long)sval); 626#endif 627} 628 629/*[clinic input] 630_multiprocessing.SemLock._is_zero 631 632Return whether semaphore has value zero. 633[clinic start generated code]*/ 634 635static PyObject * 636_multiprocessing_SemLock__is_zero_impl(SemLockObject *self) 637/*[clinic end generated code: output=815d4c878c806ed7 input=294a446418d31347]*/ 638{ 639#ifdef HAVE_BROKEN_SEM_GETVALUE 640 if (sem_trywait(self->handle) < 0) { 641 if (errno == EAGAIN) 642 Py_RETURN_TRUE; 643 return _PyMp_SetError(NULL, MP_STANDARD_ERROR); 644 } else { 645 if (sem_post(self->handle) < 0) 646 return _PyMp_SetError(NULL, MP_STANDARD_ERROR); 647 Py_RETURN_FALSE; 648 } 649#else 650 int sval; 651 if (SEM_GETVALUE(self->handle, &sval) < 0) 652 return _PyMp_SetError(NULL, MP_STANDARD_ERROR); 653 return PyBool_FromLong((long)sval == 0); 654#endif 655} 656 657/*[clinic input] 658_multiprocessing.SemLock._after_fork 659 660Rezero the net acquisition count after fork(). 661[clinic start generated code]*/ 662 663static PyObject * 664_multiprocessing_SemLock__after_fork_impl(SemLockObject *self) 665/*[clinic end generated code: output=718bb27914c6a6c1 input=190991008a76621e]*/ 666{ 667 self->count = 0; 668 Py_RETURN_NONE; 669} 670 671/*[clinic input] 672_multiprocessing.SemLock.__enter__ 673 674Enter the semaphore/lock. 675[clinic start generated code]*/ 676 677static PyObject * 678_multiprocessing_SemLock___enter___impl(SemLockObject *self) 679/*[clinic end generated code: output=beeb2f07c858511f input=c5e27d594284690b]*/ 680{ 681 return _multiprocessing_SemLock_acquire_impl(self, 1, Py_None); 682} 683 684/*[clinic input] 685_multiprocessing.SemLock.__exit__ 686 687 exc_type: object = None 688 exc_value: object = None 689 exc_tb: object = None 690 / 691 692Exit the semaphore/lock. 693[clinic start generated code]*/ 694 695static PyObject * 696_multiprocessing_SemLock___exit___impl(SemLockObject *self, 697 PyObject *exc_type, 698 PyObject *exc_value, PyObject *exc_tb) 699/*[clinic end generated code: output=3b37c1a9f8b91a03 input=7d644b64a89903f8]*/ 700{ 701 return _multiprocessing_SemLock_release_impl(self); 702} 703 704/* 705 * Semaphore methods 706 */ 707 708static PyMethodDef semlock_methods[] = { 709 _MULTIPROCESSING_SEMLOCK_ACQUIRE_METHODDEF 710 _MULTIPROCESSING_SEMLOCK_RELEASE_METHODDEF 711 _MULTIPROCESSING_SEMLOCK___ENTER___METHODDEF 712 _MULTIPROCESSING_SEMLOCK___EXIT___METHODDEF 713 _MULTIPROCESSING_SEMLOCK__COUNT_METHODDEF 714 _MULTIPROCESSING_SEMLOCK__IS_MINE_METHODDEF 715 _MULTIPROCESSING_SEMLOCK__GET_VALUE_METHODDEF 716 _MULTIPROCESSING_SEMLOCK__IS_ZERO_METHODDEF 717 _MULTIPROCESSING_SEMLOCK__REBUILD_METHODDEF 718 _MULTIPROCESSING_SEMLOCK__AFTER_FORK_METHODDEF 719 {NULL} 720}; 721 722/* 723 * Member table 724 */ 725 726static PyMemberDef semlock_members[] = { 727 {"handle", T_SEM_HANDLE, offsetof(SemLockObject, handle), READONLY, 728 ""}, 729 {"kind", T_INT, offsetof(SemLockObject, kind), READONLY, 730 ""}, 731 {"maxvalue", T_INT, offsetof(SemLockObject, maxvalue), READONLY, 732 ""}, 733 {"name", T_STRING, offsetof(SemLockObject, name), READONLY, 734 ""}, 735 {NULL} 736}; 737 738/* 739 * Semaphore type 740 */ 741 742PyTypeObject _PyMp_SemLockType = { 743 PyVarObject_HEAD_INIT(NULL, 0) 744 /* tp_name */ "_multiprocessing.SemLock", 745 /* tp_basicsize */ sizeof(SemLockObject), 746 /* tp_itemsize */ 0, 747 /* tp_dealloc */ (destructor)semlock_dealloc, 748 /* tp_vectorcall_offset */ 0, 749 /* tp_getattr */ 0, 750 /* tp_setattr */ 0, 751 /* tp_as_async */ 0, 752 /* tp_repr */ 0, 753 /* tp_as_number */ 0, 754 /* tp_as_sequence */ 0, 755 /* tp_as_mapping */ 0, 756 /* tp_hash */ 0, 757 /* tp_call */ 0, 758 /* tp_str */ 0, 759 /* tp_getattro */ 0, 760 /* tp_setattro */ 0, 761 /* tp_as_buffer */ 0, 762 /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, 763 /* tp_doc */ "Semaphore/Mutex type", 764 /* tp_traverse */ 0, 765 /* tp_clear */ 0, 766 /* tp_richcompare */ 0, 767 /* tp_weaklistoffset */ 0, 768 /* tp_iter */ 0, 769 /* tp_iternext */ 0, 770 /* tp_methods */ semlock_methods, 771 /* tp_members */ semlock_members, 772 /* tp_getset */ 0, 773 /* tp_base */ 0, 774 /* tp_dict */ 0, 775 /* tp_descr_get */ 0, 776 /* tp_descr_set */ 0, 777 /* tp_dictoffset */ 0, 778 /* tp_init */ 0, 779 /* tp_alloc */ 0, 780 /* tp_new */ _multiprocessing_SemLock, 781}; 782 783/* 784 * Function to unlink semaphore names 785 */ 786 787PyObject * 788_PyMp_sem_unlink(const char *name) 789{ 790 if (SEM_UNLINK(name) < 0) { 791 _PyMp_SetError(NULL, MP_STANDARD_ERROR); 792 return NULL; 793 } 794 795 Py_RETURN_NONE; 796} 797 798#endif // HAVE_MP_SEMAPHORE 799