semaphore.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. /*
  2. * Alpha semaphore implementation.
  3. *
  4. * (C) Copyright 1996 Linus Torvalds
  5. * (C) Copyright 1999, 2000 Richard Henderson
  6. */
  7. #include <linux/errno.h>
  8. #include <linux/sched.h>
  9. #include <linux/init.h>
  10. /*
  11. * This is basically the PPC semaphore scheme ported to use
  12. * the Alpha ll/sc sequences, so see the PPC code for
  13. * credits.
  14. */
  15. /*
  16. * Atomically update sem->count.
  17. * This does the equivalent of the following:
  18. *
  19. * old_count = sem->count;
  20. * tmp = MAX(old_count, 0) + incr;
  21. * sem->count = tmp;
  22. * return old_count;
  23. */
  24. static inline int __sem_update_count(struct semaphore *sem, int incr)
  25. {
  26. long old_count, tmp = 0;
  27. __asm__ __volatile__(
  28. "1: ldl_l %0,%2\n"
  29. " cmovgt %0,%0,%1\n"
  30. " addl %1,%3,%1\n"
  31. " stl_c %1,%2\n"
  32. " beq %1,2f\n"
  33. " mb\n"
  34. ".subsection 2\n"
  35. "2: br 1b\n"
  36. ".previous"
  37. : "=&r" (old_count), "=&r" (tmp), "=m" (sem->count)
  38. : "Ir" (incr), "1" (tmp), "m" (sem->count));
  39. return old_count;
  40. }
  41. /*
  42. * Perform the "down" function. Return zero for semaphore acquired,
  43. * return negative for signalled out of the function.
  44. *
  45. * If called from down, the return is ignored and the wait loop is
  46. * not interruptible. This means that a task waiting on a semaphore
  47. * using "down()" cannot be killed until someone does an "up()" on
  48. * the semaphore.
  49. *
  50. * If called from down_interruptible, the return value gets checked
  51. * upon return. If the return value is negative then the task continues
  52. * with the negative value in the return register (it can be tested by
  53. * the caller).
  54. *
  55. * Either form may be used in conjunction with "up()".
  56. */
  57. void __sched
  58. __down_failed(struct semaphore *sem)
  59. {
  60. struct task_struct *tsk = current;
  61. DECLARE_WAITQUEUE(wait, tsk);
  62. #ifdef CONFIG_DEBUG_SEMAPHORE
  63. printk("%s(%d): down failed(%p)\n",
  64. tsk->comm, tsk->pid, sem);
  65. #endif
  66. tsk->state = TASK_UNINTERRUPTIBLE;
  67. wmb();
  68. add_wait_queue_exclusive(&sem->wait, &wait);
  69. /*
  70. * Try to get the semaphore. If the count is > 0, then we've
  71. * got the semaphore; we decrement count and exit the loop.
  72. * If the count is 0 or negative, we set it to -1, indicating
  73. * that we are asleep, and then sleep.
  74. */
  75. while (__sem_update_count(sem, -1) <= 0) {
  76. schedule();
  77. set_task_state(tsk, TASK_UNINTERRUPTIBLE);
  78. }
  79. remove_wait_queue(&sem->wait, &wait);
  80. tsk->state = TASK_RUNNING;
  81. /*
  82. * If there are any more sleepers, wake one of them up so
  83. * that it can either get the semaphore, or set count to -1
  84. * indicating that there are still processes sleeping.
  85. */
  86. wake_up(&sem->wait);
  87. #ifdef CONFIG_DEBUG_SEMAPHORE
  88. printk("%s(%d): down acquired(%p)\n",
  89. tsk->comm, tsk->pid, sem);
  90. #endif
  91. }
  92. int __sched
  93. __down_failed_interruptible(struct semaphore *sem)
  94. {
  95. struct task_struct *tsk = current;
  96. DECLARE_WAITQUEUE(wait, tsk);
  97. long ret = 0;
  98. #ifdef CONFIG_DEBUG_SEMAPHORE
  99. printk("%s(%d): down failed(%p)\n",
  100. tsk->comm, tsk->pid, sem);
  101. #endif
  102. tsk->state = TASK_INTERRUPTIBLE;
  103. wmb();
  104. add_wait_queue_exclusive(&sem->wait, &wait);
  105. while (__sem_update_count(sem, -1) <= 0) {
  106. if (signal_pending(current)) {
  107. /*
  108. * A signal is pending - give up trying.
  109. * Set sem->count to 0 if it is negative,
  110. * since we are no longer sleeping.
  111. */
  112. __sem_update_count(sem, 0);
  113. ret = -EINTR;
  114. break;
  115. }
  116. schedule();
  117. set_task_state(tsk, TASK_INTERRUPTIBLE);
  118. }
  119. remove_wait_queue(&sem->wait, &wait);
  120. tsk->state = TASK_RUNNING;
  121. wake_up(&sem->wait);
  122. #ifdef CONFIG_DEBUG_SEMAPHORE
  123. printk("%s(%d): down %s(%p)\n",
  124. current->comm, current->pid,
  125. (ret < 0 ? "interrupted" : "acquired"), sem);
  126. #endif
  127. return ret;
  128. }
  129. void
  130. __up_wakeup(struct semaphore *sem)
  131. {
  132. /*
  133. * Note that we incremented count in up() before we came here,
  134. * but that was ineffective since the result was <= 0, and
  135. * any negative value of count is equivalent to 0.
  136. * This ends up setting count to 1, unless count is now > 0
  137. * (i.e. because some other cpu has called up() in the meantime),
  138. * in which case we just increment count.
  139. */
  140. __sem_update_count(sem, 1);
  141. wake_up(&sem->wait);
  142. }
  143. void __sched
  144. down(struct semaphore *sem)
  145. {
  146. #ifdef WAITQUEUE_DEBUG
  147. CHECK_MAGIC(sem->__magic);
  148. #endif
  149. #ifdef CONFIG_DEBUG_SEMAPHORE
  150. printk("%s(%d): down(%p) <count=%d> from %p\n",
  151. current->comm, current->pid, sem,
  152. atomic_read(&sem->count), __builtin_return_address(0));
  153. #endif
  154. __down(sem);
  155. }
  156. int __sched
  157. down_interruptible(struct semaphore *sem)
  158. {
  159. #ifdef WAITQUEUE_DEBUG
  160. CHECK_MAGIC(sem->__magic);
  161. #endif
  162. #ifdef CONFIG_DEBUG_SEMAPHORE
  163. printk("%s(%d): down(%p) <count=%d> from %p\n",
  164. current->comm, current->pid, sem,
  165. atomic_read(&sem->count), __builtin_return_address(0));
  166. #endif
  167. return __down_interruptible(sem);
  168. }
  169. int
  170. down_trylock(struct semaphore *sem)
  171. {
  172. int ret;
  173. #ifdef WAITQUEUE_DEBUG
  174. CHECK_MAGIC(sem->__magic);
  175. #endif
  176. ret = __down_trylock(sem);
  177. #ifdef CONFIG_DEBUG_SEMAPHORE
  178. printk("%s(%d): down_trylock %s from %p\n",
  179. current->comm, current->pid,
  180. ret ? "failed" : "acquired",
  181. __builtin_return_address(0));
  182. #endif
  183. return ret;
  184. }
  185. void
  186. up(struct semaphore *sem)
  187. {
  188. #ifdef WAITQUEUE_DEBUG
  189. CHECK_MAGIC(sem->__magic);
  190. #endif
  191. #ifdef CONFIG_DEBUG_SEMAPHORE
  192. printk("%s(%d): up(%p) <count=%d> from %p\n",
  193. current->comm, current->pid, sem,
  194. atomic_read(&sem->count), __builtin_return_address(0));
  195. #endif
  196. __up(sem);
  197. }