sem_wait.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. /*
  2. * -------------------------------------------------------------
  3. *
  4. * Module: sem_wait.c
  5. *
  6. * Purpose:
  7. * Semaphores aren't actually part of the PThreads standard.
  8. * They are defined by the POSIX Standard:
  9. *
  10. * POSIX 1003.1b-1993 (POSIX.1b)
  11. *
  12. * -------------------------------------------------------------
  13. *
  14. * --------------------------------------------------------------------------
  15. *
  16. * Pthreads-win32 - POSIX Threads Library for Win32
  17. * Copyright(C) 1998 John E. Bossom
  18. * Copyright(C) 1999,2005 Pthreads-win32 contributors
  19. *
  20. * Contact Email: [email protected]
  21. *
  22. * The current list of contributors is contained
  23. * in the file CONTRIBUTORS included with the source
  24. * code distribution. The list can also be seen at the
  25. * following World Wide Web location:
  26. * http://sources.redhat.com/pthreads-win32/contributors.html
  27. *
  28. * This library is free software; you can redistribute it and/or
  29. * modify it under the terms of the GNU Lesser General Public
  30. * License as published by the Free Software Foundation; either
  31. * version 2 of the License, or (at your option) any later version.
  32. *
  33. * This library is distributed in the hope that it will be useful,
  34. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  35. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  36. * Lesser General Public License for more details.
  37. *
  38. * You should have received a copy of the GNU Lesser General Public
  39. * License along with this library in the file COPYING.LIB;
  40. * if not, write to the Free Software Foundation, Inc.,
  41. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
  42. */
  43. #include "pthread.h"
  44. #include "semaphore.h"
  45. #include "implement.h"
  46. static void PTW32_CDECL
  47. ptw32_sem_wait_cleanup(void * sem)
  48. {
  49. sem_t s = (sem_t) sem;
  50. if (pthread_mutex_lock (&s->lock) == 0)
  51. {
  52. /*
  53. * If sema is destroyed do nothing, otherwise:-
  54. * If the sema is posted between us being cancelled and us locking
  55. * the sema again above then we need to consume that post but cancel
  56. * anyway. If we don't get the semaphore we indicate that we're no
  57. * longer waiting.
  58. */
  59. if (*((sem_t *)sem) != NULL && !(WaitForSingleObject(s->sem, 0) == WAIT_OBJECT_0))
  60. {
  61. ++s->value;
  62. #if defined(NEED_SEM)
  63. if (s->value > 0)
  64. {
  65. s->leftToUnblock = 0;
  66. }
  67. #else
  68. /*
  69. * Don't release the W32 sema, it doesn't need adjustment
  70. * because it doesn't record the number of waiters.
  71. */
  72. #endif /* NEED_SEM */
  73. }
  74. (void) pthread_mutex_unlock (&s->lock);
  75. }
  76. }
  77. int
  78. sem_wait (sem_t * sem)
  79. /*
  80. * ------------------------------------------------------
  81. * DOCPUBLIC
  82. * This function waits on a semaphore.
  83. *
  84. * PARAMETERS
  85. * sem
  86. * pointer to an instance of sem_t
  87. *
  88. * DESCRIPTION
  89. * This function waits on a semaphore. If the
  90. * semaphore value is greater than zero, it decreases
  91. * its value by one. If the semaphore value is zero, then
  92. * the calling thread (or process) is blocked until it can
  93. * successfully decrease the value or until interrupted by
  94. * a signal.
  95. *
  96. * RESULTS
  97. * 0 successfully decreased semaphore,
  98. * -1 failed, error in errno
  99. * ERRNO
  100. * EINVAL 'sem' is not a valid semaphore,
  101. * ENOSYS semaphores are not supported,
  102. * EINTR the function was interrupted by a signal,
  103. * EDEADLK a deadlock condition was detected.
  104. *
  105. * ------------------------------------------------------
  106. */
  107. {
  108. int result = 0;
  109. sem_t s = *sem;
  110. pthread_testcancel();
  111. if (s == NULL)
  112. {
  113. result = EINVAL;
  114. }
  115. else
  116. {
  117. if ((result = pthread_mutex_lock (&s->lock)) == 0)
  118. {
  119. int v;
  120. /* See sem_destroy.c
  121. */
  122. if (*sem == NULL)
  123. {
  124. (void) pthread_mutex_unlock (&s->lock);
  125. errno = EINVAL;
  126. return -1;
  127. }
  128. v = --s->value;
  129. (void) pthread_mutex_unlock (&s->lock);
  130. if (v < 0)
  131. {
  132. #if defined(_MSC_VER) && _MSC_VER < 1400
  133. #pragma inline_depth(0)
  134. #endif
  135. /* Must wait */
  136. pthread_cleanup_push(ptw32_sem_wait_cleanup, (void *) s);
  137. result = pthreadCancelableWait (s->sem);
  138. /* Cleanup if we're canceled or on any other error */
  139. pthread_cleanup_pop(result);
  140. #if defined(_MSC_VER) && _MSC_VER < 1400
  141. #pragma inline_depth()
  142. #endif
  143. }
  144. #if defined(NEED_SEM)
  145. if (!result && pthread_mutex_lock (&s->lock) == 0)
  146. {
  147. if (*sem == NULL)
  148. {
  149. (void) pthread_mutex_unlock (&s->lock);
  150. errno = EINVAL;
  151. return -1;
  152. }
  153. if (s->leftToUnblock > 0)
  154. {
  155. --s->leftToUnblock;
  156. SetEvent(s->sem);
  157. }
  158. (void) pthread_mutex_unlock (&s->lock);
  159. }
  160. #endif /* NEED_SEM */
  161. }
  162. }
  163. if (result != 0)
  164. {
  165. errno = result;
  166. return -1;
  167. }
  168. return 0;
  169. } /* sem_wait */