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