semaphore.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. /* Linuxthreads - a simple clone()-based implementation of Posix */
  2. /* threads for Linux. */
  3. /* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */
  4. /* */
  5. /* This program is free software; you can redistribute it and/or */
  6. /* modify it under the terms of the GNU Library General Public License */
  7. /* as published by the Free Software Foundation; either version 2 */
  8. /* of the License, or (at your option) any later version. */
  9. /* */
  10. /* This program is distributed in the hope that it will be useful, */
  11. /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
  12. /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
  13. /* GNU Library General Public License for more details. */
  14. /* Semaphores a la POSIX 1003.1b */
  15. #include <features.h>
  16. #include <limits.h>
  17. #include <errno.h>
  18. #include "pthread.h"
  19. #include "semaphore.h"
  20. #include "internals.h"
  21. #include "spinlock.h"
  22. #include "restart.h"
  23. #include "queue.h"
  24. int sem_init(sem_t *sem, int pshared, unsigned int value)
  25. {
  26. if (value > SEM_VALUE_MAX) {
  27. errno = EINVAL;
  28. return -1;
  29. }
  30. if (pshared) {
  31. errno = ENOSYS;
  32. return -1;
  33. }
  34. __pthread_init_lock(&sem->__sem_lock);
  35. sem->__sem_value = value;
  36. sem->__sem_waiting = NULL;
  37. return 0;
  38. }
  39. /* Function called by pthread_cancel to remove the thread from
  40. waiting inside sem_wait. */
  41. static int new_sem_extricate_func(void *obj, pthread_descr th)
  42. {
  43. volatile pthread_descr self = thread_self();
  44. sem_t *sem = obj;
  45. int did_remove = 0;
  46. __pthread_lock(&sem->__sem_lock, self);
  47. did_remove = remove_from_queue(&sem->__sem_waiting, th);
  48. __pthread_unlock(&sem->__sem_lock);
  49. return did_remove;
  50. }
  51. int sem_wait(sem_t * sem)
  52. {
  53. volatile pthread_descr self = thread_self();
  54. pthread_extricate_if extr;
  55. int already_canceled = 0;
  56. /* Set up extrication interface */
  57. extr.pu_object = sem;
  58. extr.pu_extricate_func = new_sem_extricate_func;
  59. __pthread_lock(&sem->__sem_lock, self);
  60. if (sem->__sem_value > 0) {
  61. sem->__sem_value--;
  62. __pthread_unlock(&sem->__sem_lock);
  63. return 0;
  64. }
  65. /* Register extrication interface */
  66. THREAD_SETMEM(self, p_sem_avail, 0);
  67. __pthread_set_own_extricate_if(self, &extr);
  68. /* Enqueue only if not already cancelled. */
  69. if (!(THREAD_GETMEM(self, p_canceled)
  70. && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
  71. enqueue(&sem->__sem_waiting, self);
  72. else
  73. already_canceled = 1;
  74. __pthread_unlock(&sem->__sem_lock);
  75. if (already_canceled) {
  76. __pthread_set_own_extricate_if(self, 0);
  77. __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
  78. }
  79. /* Wait for sem_post or cancellation, or fall through if already canceled */
  80. while (1)
  81. {
  82. suspend(self);
  83. if (THREAD_GETMEM(self, p_sem_avail) == 0
  84. && (THREAD_GETMEM(self, p_woken_by_cancel) == 0
  85. || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE))
  86. {
  87. /* Resume does not belong to us. */
  88. continue;
  89. }
  90. break;
  91. }
  92. __pthread_set_own_extricate_if(self, 0);
  93. /* Terminate only if the wakeup came from cancellation. */
  94. /* Otherwise ignore cancellation because we got the semaphore. */
  95. if (THREAD_GETMEM(self, p_woken_by_cancel)
  96. && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
  97. THREAD_SETMEM(self, p_woken_by_cancel, 0);
  98. __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
  99. }
  100. /* We got the semaphore */
  101. return 0;
  102. }
  103. int sem_trywait(sem_t * sem)
  104. {
  105. int retval;
  106. __pthread_lock(&sem->__sem_lock, NULL);
  107. if (sem->__sem_value == 0) {
  108. errno = EAGAIN;
  109. retval = -1;
  110. } else {
  111. sem->__sem_value--;
  112. retval = 0;
  113. }
  114. __pthread_unlock(&sem->__sem_lock);
  115. return retval;
  116. }
  117. int sem_post(sem_t * sem)
  118. {
  119. pthread_descr self = thread_self();
  120. pthread_descr th;
  121. struct pthread_request request;
  122. if (THREAD_GETMEM(self, p_in_sighandler) == NULL) {
  123. __pthread_lock(&sem->__sem_lock, self);
  124. if (sem->__sem_waiting == NULL) {
  125. if (sem->__sem_value >= SEM_VALUE_MAX) {
  126. /* Overflow */
  127. errno = ERANGE;
  128. __pthread_unlock(&sem->__sem_lock);
  129. return -1;
  130. }
  131. sem->__sem_value++;
  132. __pthread_unlock(&sem->__sem_lock);
  133. } else {
  134. th = dequeue(&sem->__sem_waiting);
  135. __pthread_unlock(&sem->__sem_lock);
  136. th->p_sem_avail = 1;
  137. WRITE_MEMORY_BARRIER();
  138. restart(th);
  139. }
  140. } else {
  141. /* If we're in signal handler, delegate post operation to
  142. the thread manager. */
  143. if (__pthread_manager_request < 0) {
  144. if (__pthread_initialize_manager() < 0) {
  145. errno = EAGAIN;
  146. return -1;
  147. }
  148. }
  149. request.req_kind = REQ_POST;
  150. request.req_args.post = sem;
  151. TEMP_FAILURE_RETRY(write(__pthread_manager_request,
  152. (char *) &request, sizeof(request)));
  153. }
  154. return 0;
  155. }
  156. int sem_getvalue(sem_t * sem, int * sval)
  157. {
  158. *sval = sem->__sem_value;
  159. return 0;
  160. }
  161. int sem_destroy(sem_t * sem)
  162. {
  163. if (sem->__sem_waiting != NULL) {
  164. __set_errno (EBUSY);
  165. return -1;
  166. }
  167. return 0;
  168. }
  169. sem_t *sem_open(const char *name attribute_unused, int oflag attribute_unused, ...)
  170. {
  171. __set_errno (ENOSYS);
  172. return SEM_FAILED;
  173. }
  174. int sem_close(sem_t *sem attribute_unused)
  175. {
  176. __set_errno (ENOSYS);
  177. return -1;
  178. }
  179. int sem_unlink(const char *name attribute_unused)
  180. {
  181. __set_errno (ENOSYS);
  182. return -1;
  183. }
  184. int sem_timedwait(sem_t *sem, const struct timespec *abstime)
  185. {
  186. pthread_descr self = thread_self();
  187. pthread_extricate_if extr;
  188. int already_canceled = 0;
  189. __pthread_lock(&sem->__sem_lock, self);
  190. if (sem->__sem_value > 0) {
  191. --sem->__sem_value;
  192. __pthread_unlock(&sem->__sem_lock);
  193. return 0;
  194. }
  195. if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) {
  196. /* The standard requires that if the function would block and the
  197. time value is illegal, the function returns with an error. */
  198. __pthread_unlock(&sem->__sem_lock);
  199. __set_errno (EINVAL);
  200. return -1;
  201. }
  202. /* Set up extrication interface */
  203. extr.pu_object = sem;
  204. extr.pu_extricate_func = new_sem_extricate_func;
  205. /* Register extrication interface */
  206. THREAD_SETMEM(self, p_sem_avail, 0);
  207. __pthread_set_own_extricate_if(self, &extr);
  208. /* Enqueue only if not already cancelled. */
  209. if (!(THREAD_GETMEM(self, p_canceled)
  210. && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
  211. enqueue(&sem->__sem_waiting, self);
  212. else
  213. already_canceled = 1;
  214. __pthread_unlock(&sem->__sem_lock);
  215. if (already_canceled) {
  216. __pthread_set_own_extricate_if(self, 0);
  217. __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
  218. }
  219. while (1)
  220. {
  221. if (timedsuspend(self, abstime) == 0) {
  222. int was_on_queue;
  223. /* __pthread_lock will queue back any spurious restarts that
  224. may happen to it. */
  225. __pthread_lock(&sem->__sem_lock, self);
  226. was_on_queue = remove_from_queue(&sem->__sem_waiting, self);
  227. __pthread_unlock(&sem->__sem_lock);
  228. if (was_on_queue) {
  229. __pthread_set_own_extricate_if(self, 0);
  230. __set_errno (ETIMEDOUT);
  231. return -1;
  232. }
  233. /* Eat the outstanding restart() from the signaller */
  234. suspend(self);
  235. }
  236. if (THREAD_GETMEM(self, p_sem_avail) == 0
  237. && (THREAD_GETMEM(self, p_woken_by_cancel) == 0
  238. || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE))
  239. {
  240. /* Resume does not belong to us. */
  241. continue;
  242. }
  243. break;
  244. }
  245. __pthread_set_own_extricate_if(self, 0);
  246. /* Terminate only if the wakeup came from cancellation. */
  247. /* Otherwise ignore cancellation because we got the semaphore. */
  248. if (THREAD_GETMEM(self, p_woken_by_cancel)
  249. && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
  250. THREAD_SETMEM(self, p_woken_by_cancel, 0);
  251. __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
  252. }
  253. /* We got the semaphore */
  254. return 0;
  255. }