semaphore.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  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 <errno.h>
  16. #include "pthread.h"
  17. #include "semaphore.h"
  18. #include "internals.h"
  19. #include "spinlock.h"
  20. #include "restart.h"
  21. #include "queue.h"
  22. int __new_sem_init(sem_t *sem, int pshared, unsigned int value)
  23. {
  24. if (value > SEM_VALUE_MAX) {
  25. errno = EINVAL;
  26. return -1;
  27. }
  28. if (pshared) {
  29. errno = ENOSYS;
  30. return -1;
  31. }
  32. __pthread_init_lock((struct _pthread_fastlock *) &sem->__sem_lock);
  33. sem->__sem_value = value;
  34. sem->__sem_waiting = NULL;
  35. return 0;
  36. }
  37. /* Function called by pthread_cancel to remove the thread from
  38. waiting inside __new_sem_wait. */
  39. static int new_sem_extricate_func(void *obj, pthread_descr th)
  40. {
  41. volatile pthread_descr self = thread_self();
  42. sem_t *sem = obj;
  43. int did_remove = 0;
  44. __pthread_lock((struct _pthread_fastlock *) &sem->__sem_lock, self);
  45. did_remove = remove_from_queue(&sem->__sem_waiting, th);
  46. __pthread_unlock((struct _pthread_fastlock *) &sem->__sem_lock);
  47. return did_remove;
  48. }
  49. int __new_sem_wait(sem_t * sem)
  50. {
  51. volatile pthread_descr self = thread_self();
  52. pthread_extricate_if extr;
  53. int already_canceled = 0;
  54. /* Set up extrication interface */
  55. extr.pu_object = sem;
  56. extr.pu_extricate_func = new_sem_extricate_func;
  57. __pthread_lock((struct _pthread_fastlock *) &sem->__sem_lock, self);
  58. if (sem->__sem_value > 0) {
  59. sem->__sem_value--;
  60. __pthread_unlock((struct _pthread_fastlock *) &sem->__sem_lock);
  61. return 0;
  62. }
  63. /* Register extrication interface */
  64. __pthread_set_own_extricate_if(self, &extr);
  65. /* Enqueue only if not already cancelled. */
  66. if (!(THREAD_GETMEM(self, p_canceled)
  67. && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
  68. enqueue(&sem->__sem_waiting, self);
  69. else
  70. already_canceled = 1;
  71. __pthread_unlock((struct _pthread_fastlock *) &sem->__sem_lock);
  72. if (already_canceled) {
  73. __pthread_set_own_extricate_if(self, 0);
  74. pthread_exit(PTHREAD_CANCELED);
  75. }
  76. /* Wait for sem_post or cancellation, or fall through if already canceled */
  77. suspend(self);
  78. __pthread_set_own_extricate_if(self, 0);
  79. /* Terminate only if the wakeup came from cancellation. */
  80. /* Otherwise ignore cancellation because we got the semaphore. */
  81. if (THREAD_GETMEM(self, p_woken_by_cancel)
  82. && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
  83. THREAD_SETMEM(self, p_woken_by_cancel, 0);
  84. pthread_exit(PTHREAD_CANCELED);
  85. }
  86. /* We got the semaphore */
  87. return 0;
  88. }
  89. int __new_sem_trywait(sem_t * sem)
  90. {
  91. int retval;
  92. __pthread_lock((struct _pthread_fastlock *) &sem->__sem_lock, NULL);
  93. if (sem->__sem_value == 0) {
  94. errno = EAGAIN;
  95. retval = -1;
  96. } else {
  97. sem->__sem_value--;
  98. retval = 0;
  99. }
  100. __pthread_unlock((struct _pthread_fastlock *) &sem->__sem_lock);
  101. return retval;
  102. }
  103. int __new_sem_post(sem_t * sem)
  104. {
  105. pthread_descr self = thread_self();
  106. pthread_descr th;
  107. struct pthread_request request;
  108. if (THREAD_GETMEM(self, p_in_sighandler) == NULL) {
  109. __pthread_lock((struct _pthread_fastlock *) &sem->__sem_lock, self);
  110. if (sem->__sem_waiting == NULL) {
  111. if (sem->__sem_value >= SEM_VALUE_MAX) {
  112. /* Overflow */
  113. errno = ERANGE;
  114. __pthread_unlock((struct _pthread_fastlock *) &sem->__sem_lock);
  115. return -1;
  116. }
  117. sem->__sem_value++;
  118. __pthread_unlock((struct _pthread_fastlock *) &sem->__sem_lock);
  119. } else {
  120. th = dequeue(&sem->__sem_waiting);
  121. __pthread_unlock((struct _pthread_fastlock *) &sem->__sem_lock);
  122. restart(th);
  123. }
  124. } else {
  125. /* If we're in signal handler, delegate post operation to
  126. the thread manager. */
  127. if (__pthread_manager_request < 0) {
  128. if (__pthread_initialize_manager() < 0) {
  129. errno = EAGAIN;
  130. return -1;
  131. }
  132. }
  133. request.req_kind = REQ_POST;
  134. request.req_args.post = sem;
  135. __libc_write(__pthread_manager_request,
  136. (char *) &request, sizeof(request));
  137. }
  138. return 0;
  139. }
  140. int __new_sem_getvalue(sem_t * sem, int * sval)
  141. {
  142. *sval = sem->__sem_value;
  143. return 0;
  144. }
  145. int __new_sem_destroy(sem_t * sem)
  146. {
  147. if (sem->__sem_waiting != NULL) {
  148. __set_errno (EBUSY);
  149. return -1;
  150. }
  151. return 0;
  152. }
  153. sem_t *sem_open(const char *name, int oflag, ...)
  154. {
  155. __set_errno (ENOSYS);
  156. return SEM_FAILED;
  157. }
  158. int sem_close(sem_t *sem)
  159. {
  160. __set_errno (ENOSYS);
  161. return -1;
  162. }
  163. int sem_unlink(const char *name)
  164. {
  165. __set_errno (ENOSYS);
  166. return -1;
  167. }
  168. #if defined PIC && DO_VERSIONING
  169. default_symbol_version (__new_sem_init, sem_init, GLIBC_2.1);
  170. default_symbol_version (__new_sem_wait, sem_wait, GLIBC_2.1);
  171. default_symbol_version (__new_sem_trywait, sem_trywait, GLIBC_2.1);
  172. default_symbol_version (__new_sem_post, sem_post, GLIBC_2.1);
  173. default_symbol_version (__new_sem_getvalue, sem_getvalue, GLIBC_2.1);
  174. default_symbol_version (__new_sem_destroy, sem_destroy, GLIBC_2.1);
  175. #else
  176. # ifdef weak_alias
  177. weak_alias (__new_sem_init, sem_init)
  178. weak_alias (__new_sem_wait, sem_wait)
  179. weak_alias (__new_sem_trywait, sem_trywait)
  180. weak_alias (__new_sem_post, sem_post)
  181. weak_alias (__new_sem_getvalue, sem_getvalue)
  182. weak_alias (__new_sem_destroy, sem_destroy)
  183. # endif
  184. #endif