semaphore.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. /*
  2. * arch/xtensa/kernel/semaphore.c
  3. *
  4. * Generic semaphore code. Buyer beware. Do your own specific changes
  5. * in <asm/semaphore-helper.h>
  6. *
  7. * This file is subject to the terms and conditions of the GNU General Public
  8. * License. See the file "COPYING" in the main directory of this archive
  9. * for more details.
  10. *
  11. * Copyright (C) 2001 - 2005 Tensilica Inc.
  12. *
  13. * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
  14. * Chris Zankel <chris@zankel.net>
  15. * Marc Gauthier<marc@tensilica.com, marc@alumni.uwaterloo.ca>
  16. * Kevin Chea
  17. */
  18. #include <linux/sched.h>
  19. #include <linux/wait.h>
  20. #include <linux/init.h>
  21. #include <asm/semaphore.h>
  22. #include <asm/errno.h>
  23. /*
  24. * These two _must_ execute atomically wrt each other.
  25. */
  26. static __inline__ void wake_one_more(struct semaphore * sem)
  27. {
  28. atomic_inc((atomic_t *)&sem->sleepers);
  29. }
  30. static __inline__ int waking_non_zero(struct semaphore *sem)
  31. {
  32. unsigned long flags;
  33. int ret = 0;
  34. spin_lock_irqsave(&semaphore_wake_lock, flags);
  35. if (sem->sleepers > 0) {
  36. sem->sleepers--;
  37. ret = 1;
  38. }
  39. spin_unlock_irqrestore(&semaphore_wake_lock, flags);
  40. return ret;
  41. }
  42. /*
  43. * waking_non_zero_interruptible:
  44. * 1 got the lock
  45. * 0 go to sleep
  46. * -EINTR interrupted
  47. *
  48. * We must undo the sem->count down_interruptible() increment while we are
  49. * protected by the spinlock in order to make atomic this atomic_inc() with the
  50. * atomic_read() in wake_one_more(), otherwise we can race. -arca
  51. */
  52. static __inline__ int waking_non_zero_interruptible(struct semaphore *sem,
  53. struct task_struct *tsk)
  54. {
  55. unsigned long flags;
  56. int ret = 0;
  57. spin_lock_irqsave(&semaphore_wake_lock, flags);
  58. if (sem->sleepers > 0) {
  59. sem->sleepers--;
  60. ret = 1;
  61. } else if (signal_pending(tsk)) {
  62. atomic_inc(&sem->count);
  63. ret = -EINTR;
  64. }
  65. spin_unlock_irqrestore(&semaphore_wake_lock, flags);
  66. return ret;
  67. }
  68. /*
  69. * waking_non_zero_trylock:
  70. * 1 failed to lock
  71. * 0 got the lock
  72. *
  73. * We must undo the sem->count down_trylock() increment while we are
  74. * protected by the spinlock in order to make atomic this atomic_inc() with the
  75. * atomic_read() in wake_one_more(), otherwise we can race. -arca
  76. */
  77. static __inline__ int waking_non_zero_trylock(struct semaphore *sem)
  78. {
  79. unsigned long flags;
  80. int ret = 1;
  81. spin_lock_irqsave(&semaphore_wake_lock, flags);
  82. if (sem->sleepers <= 0)
  83. atomic_inc(&sem->count);
  84. else {
  85. sem->sleepers--;
  86. ret = 0;
  87. }
  88. spin_unlock_irqrestore(&semaphore_wake_lock, flags);
  89. return ret;
  90. }
  91. spinlock_t semaphore_wake_lock;
  92. /*
  93. * Semaphores are implemented using a two-way counter:
  94. * The "count" variable is decremented for each process
  95. * that tries to sleep, while the "waking" variable is
  96. * incremented when the "up()" code goes to wake up waiting
  97. * processes.
  98. *
  99. * Notably, the inline "up()" and "down()" functions can
  100. * efficiently test if they need to do any extra work (up
  101. * needs to do something only if count was negative before
  102. * the increment operation.
  103. *
  104. * waking_non_zero() (from asm/semaphore.h) must execute
  105. * atomically.
  106. *
  107. * When __up() is called, the count was negative before
  108. * incrementing it, and we need to wake up somebody.
  109. *
  110. * This routine adds one to the count of processes that need to
  111. * wake up and exit. ALL waiting processes actually wake up but
  112. * only the one that gets to the "waking" field first will gate
  113. * through and acquire the semaphore. The others will go back
  114. * to sleep.
  115. *
  116. * Note that these functions are only called when there is
  117. * contention on the lock, and as such all this is the
  118. * "non-critical" part of the whole semaphore business. The
  119. * critical part is the inline stuff in <asm/semaphore.h>
  120. * where we want to avoid any extra jumps and calls.
  121. */
  122. void __up(struct semaphore *sem)
  123. {
  124. wake_one_more(sem);
  125. wake_up(&sem->wait);
  126. }
  127. /*
  128. * Perform the "down" function. Return zero for semaphore acquired,
  129. * return negative for signalled out of the function.
  130. *
  131. * If called from __down, the return is ignored and the wait loop is
  132. * not interruptible. This means that a task waiting on a semaphore
  133. * using "down()" cannot be killed until someone does an "up()" on
  134. * the semaphore.
  135. *
  136. * If called from __down_interruptible, the return value gets checked
  137. * upon return. If the return value is negative then the task continues
  138. * with the negative value in the return register (it can be tested by
  139. * the caller).
  140. *
  141. * Either form may be used in conjunction with "up()".
  142. *
  143. */
  144. #define DOWN_VAR \
  145. struct task_struct *tsk = current; \
  146. wait_queue_t wait; \
  147. init_waitqueue_entry(&wait, tsk);
  148. #define DOWN_HEAD(task_state) \
  149. \
  150. \
  151. tsk->state = (task_state); \
  152. add_wait_queue(&sem->wait, &wait); \
  153. \
  154. /* \
  155. * Ok, we're set up. sem->count is known to be less than zero \
  156. * so we must wait. \
  157. * \
  158. * We can let go the lock for purposes of waiting. \
  159. * We re-acquire it after awaking so as to protect \
  160. * all semaphore operations. \
  161. * \
  162. * If "up()" is called before we call waking_non_zero() then \
  163. * we will catch it right away. If it is called later then \
  164. * we will have to go through a wakeup cycle to catch it. \
  165. * \
  166. * Multiple waiters contend for the semaphore lock to see \
  167. * who gets to gate through and who has to wait some more. \
  168. */ \
  169. for (;;) {
  170. #define DOWN_TAIL(task_state) \
  171. tsk->state = (task_state); \
  172. } \
  173. tsk->state = TASK_RUNNING; \
  174. remove_wait_queue(&sem->wait, &wait);
  175. void __sched __down(struct semaphore * sem)
  176. {
  177. DOWN_VAR
  178. DOWN_HEAD(TASK_UNINTERRUPTIBLE)
  179. if (waking_non_zero(sem))
  180. break;
  181. schedule();
  182. DOWN_TAIL(TASK_UNINTERRUPTIBLE)
  183. }
  184. int __sched __down_interruptible(struct semaphore * sem)
  185. {
  186. int ret = 0;
  187. DOWN_VAR
  188. DOWN_HEAD(TASK_INTERRUPTIBLE)
  189. ret = waking_non_zero_interruptible(sem, tsk);
  190. if (ret)
  191. {
  192. if (ret == 1)
  193. /* ret != 0 only if we get interrupted -arca */
  194. ret = 0;
  195. break;
  196. }
  197. schedule();
  198. DOWN_TAIL(TASK_INTERRUPTIBLE)
  199. return ret;
  200. }
  201. int __down_trylock(struct semaphore * sem)
  202. {
  203. return waking_non_zero_trylock(sem);
  204. }