semaphore.c 8.5 KB

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