semaphore.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  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 __new_sem_init(sem_t *sem, int pshared, unsigned int value);
  25. int __new_sem_init(sem_t *sem, int pshared, unsigned int value)
  26. {
  27. if (value > SEM_VALUE_MAX) {
  28. errno = EINVAL;
  29. return -1;
  30. }
  31. if (pshared) {
  32. errno = ENOSYS;
  33. return -1;
  34. }
  35. __pthread_init_lock(&sem->__sem_lock);
  36. sem->__sem_value = value;
  37. sem->__sem_waiting = NULL;
  38. return 0;
  39. }
  40. /* Function called by pthread_cancel to remove the thread from
  41. waiting inside __new_sem_wait. */
  42. static int new_sem_extricate_func(void *obj, pthread_descr th)
  43. {
  44. volatile pthread_descr self = thread_self();
  45. sem_t *sem = obj;
  46. int did_remove = 0;
  47. __pthread_lock(&sem->__sem_lock, self);
  48. did_remove = remove_from_queue(&sem->__sem_waiting, th);
  49. __pthread_unlock(&sem->__sem_lock);
  50. return did_remove;
  51. }
  52. int __new_sem_wait(sem_t * sem);
  53. int __new_sem_wait(sem_t * sem)
  54. {
  55. volatile pthread_descr self = thread_self();
  56. pthread_extricate_if extr;
  57. int already_canceled = 0;
  58. int spurious_wakeup_count;
  59. /* Set up extrication interface */
  60. extr.pu_object = sem;
  61. extr.pu_extricate_func = new_sem_extricate_func;
  62. __pthread_lock(&sem->__sem_lock, self);
  63. if (sem->__sem_value > 0) {
  64. sem->__sem_value--;
  65. __pthread_unlock(&sem->__sem_lock);
  66. return 0;
  67. }
  68. /* Register extrication interface */
  69. THREAD_SETMEM(self, p_sem_avail, 0);
  70. __pthread_set_own_extricate_if(self, &extr);
  71. /* Enqueue only if not already cancelled. */
  72. if (!(THREAD_GETMEM(self, p_canceled)
  73. && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
  74. enqueue(&sem->__sem_waiting, self);
  75. else
  76. already_canceled = 1;
  77. __pthread_unlock(&sem->__sem_lock);
  78. if (already_canceled) {
  79. __pthread_set_own_extricate_if(self, 0);
  80. __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
  81. }
  82. /* Wait for sem_post or cancellation, or fall through if already canceled */
  83. spurious_wakeup_count = 0;
  84. while (1)
  85. {
  86. suspend(self);
  87. if (THREAD_GETMEM(self, p_sem_avail) == 0
  88. && (THREAD_GETMEM(self, p_woken_by_cancel) == 0
  89. || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE))
  90. {
  91. /* Count resumes that don't belong to us. */
  92. spurious_wakeup_count++;
  93. continue;
  94. }
  95. break;
  96. }
  97. __pthread_set_own_extricate_if(self, 0);
  98. /* Terminate only if the wakeup came from cancellation. */
  99. /* Otherwise ignore cancellation because we got the semaphore. */
  100. if (THREAD_GETMEM(self, p_woken_by_cancel)
  101. && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
  102. THREAD_SETMEM(self, p_woken_by_cancel, 0);
  103. __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
  104. }
  105. /* We got the semaphore */
  106. return 0;
  107. }
  108. int __new_sem_trywait(sem_t * sem);
  109. int __new_sem_trywait(sem_t * sem)
  110. {
  111. int retval;
  112. __pthread_lock(&sem->__sem_lock, NULL);
  113. if (sem->__sem_value == 0) {
  114. errno = EAGAIN;
  115. retval = -1;
  116. } else {
  117. sem->__sem_value--;
  118. retval = 0;
  119. }
  120. __pthread_unlock(&sem->__sem_lock);
  121. return retval;
  122. }
  123. int __new_sem_post(sem_t * sem);
  124. int __new_sem_post(sem_t * sem)
  125. {
  126. pthread_descr self = thread_self();
  127. pthread_descr th;
  128. struct pthread_request request;
  129. if (THREAD_GETMEM(self, p_in_sighandler) == NULL) {
  130. __pthread_lock(&sem->__sem_lock, self);
  131. if (sem->__sem_waiting == NULL) {
  132. if (sem->__sem_value >= SEM_VALUE_MAX) {
  133. /* Overflow */
  134. errno = ERANGE;
  135. __pthread_unlock(&sem->__sem_lock);
  136. return -1;
  137. }
  138. sem->__sem_value++;
  139. __pthread_unlock(&sem->__sem_lock);
  140. } else {
  141. th = dequeue(&sem->__sem_waiting);
  142. __pthread_unlock(&sem->__sem_lock);
  143. th->p_sem_avail = 1;
  144. WRITE_MEMORY_BARRIER();
  145. restart(th);
  146. }
  147. } else {
  148. /* If we're in signal handler, delegate post operation to
  149. the thread manager. */
  150. if (__pthread_manager_request < 0) {
  151. if (__pthread_initialize_manager() < 0) {
  152. errno = EAGAIN;
  153. return -1;
  154. }
  155. }
  156. request.req_kind = REQ_POST;
  157. request.req_args.post = sem;
  158. TEMP_FAILURE_RETRY(write(__pthread_manager_request,
  159. (char *) &request, sizeof(request)));
  160. }
  161. return 0;
  162. }
  163. int __new_sem_getvalue(sem_t * sem, int * sval);
  164. int __new_sem_getvalue(sem_t * sem, int * sval)
  165. {
  166. *sval = sem->__sem_value;
  167. return 0;
  168. }
  169. int __new_sem_destroy(sem_t * sem);
  170. int __new_sem_destroy(sem_t * sem)
  171. {
  172. if (sem->__sem_waiting != NULL) {
  173. __set_errno (EBUSY);
  174. return -1;
  175. }
  176. return 0;
  177. }
  178. sem_t *sem_open(const char *name attribute_unused, int oflag attribute_unused, ...)
  179. {
  180. __set_errno (ENOSYS);
  181. return SEM_FAILED;
  182. }
  183. int sem_close(sem_t *sem attribute_unused)
  184. {
  185. __set_errno (ENOSYS);
  186. return -1;
  187. }
  188. int sem_unlink(const char *name attribute_unused)
  189. {
  190. __set_errno (ENOSYS);
  191. return -1;
  192. }
  193. int sem_timedwait(sem_t *sem, const struct timespec *abstime)
  194. {
  195. pthread_descr self = thread_self();
  196. pthread_extricate_if extr;
  197. int already_canceled = 0;
  198. int spurious_wakeup_count;
  199. __pthread_lock(&sem->__sem_lock, self);
  200. if (sem->__sem_value > 0) {
  201. --sem->__sem_value;
  202. __pthread_unlock(&sem->__sem_lock);
  203. return 0;
  204. }
  205. if (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) {
  206. /* The standard requires that if the function would block and the
  207. time value is illegal, the function returns with an error. */
  208. __pthread_unlock(&sem->__sem_lock);
  209. __set_errno (EINVAL);
  210. return -1;
  211. }
  212. /* Set up extrication interface */
  213. extr.pu_object = sem;
  214. extr.pu_extricate_func = new_sem_extricate_func;
  215. /* Register extrication interface */
  216. THREAD_SETMEM(self, p_sem_avail, 0);
  217. __pthread_set_own_extricate_if(self, &extr);
  218. /* Enqueue only if not already cancelled. */
  219. if (!(THREAD_GETMEM(self, p_canceled)
  220. && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
  221. enqueue(&sem->__sem_waiting, self);
  222. else
  223. already_canceled = 1;
  224. __pthread_unlock(&sem->__sem_lock);
  225. if (already_canceled) {
  226. __pthread_set_own_extricate_if(self, 0);
  227. __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
  228. }
  229. spurious_wakeup_count = 0;
  230. while (1)
  231. {
  232. if (timedsuspend(self, abstime) == 0) {
  233. int was_on_queue;
  234. /* __pthread_lock will queue back any spurious restarts that
  235. may happen to it. */
  236. __pthread_lock(&sem->__sem_lock, self);
  237. was_on_queue = remove_from_queue(&sem->__sem_waiting, self);
  238. __pthread_unlock(&sem->__sem_lock);
  239. if (was_on_queue) {
  240. __pthread_set_own_extricate_if(self, 0);
  241. __set_errno (ETIMEDOUT);
  242. return -1;
  243. }
  244. /* Eat the outstanding restart() from the signaller */
  245. suspend(self);
  246. }
  247. if (THREAD_GETMEM(self, p_sem_avail) == 0
  248. && (THREAD_GETMEM(self, p_woken_by_cancel) == 0
  249. || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE))
  250. {
  251. /* Count resumes that don't belong to us. */
  252. spurious_wakeup_count++;
  253. continue;
  254. }
  255. break;
  256. }
  257. __pthread_set_own_extricate_if(self, 0);
  258. /* Terminate only if the wakeup came from cancellation. */
  259. /* Otherwise ignore cancellation because we got the semaphore. */
  260. if (THREAD_GETMEM(self, p_woken_by_cancel)
  261. && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
  262. THREAD_SETMEM(self, p_woken_by_cancel, 0);
  263. __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
  264. }
  265. /* We got the semaphore */
  266. return 0;
  267. }
  268. weak_alias (__new_sem_init, sem_init)
  269. weak_alias (__new_sem_wait, sem_wait)
  270. weak_alias (__new_sem_trywait, sem_trywait)
  271. weak_alias (__new_sem_post, sem_post)
  272. weak_alias (__new_sem_getvalue, sem_getvalue)
  273. weak_alias (__new_sem_destroy, sem_destroy)