semaphore.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:6k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  *  ARM semaphore implementation, taken from
  3.  *
  4.  *  i386 semaphore implementation.
  5.  *
  6.  *  (C) Copyright 1999 Linus Torvalds
  7.  *
  8.  *  Modified for ARM by Russell King
  9.  *
  10.  * This program is free software; you can redistribute it and/or modify
  11.  * it under the terms of the GNU General Public License version 2 as
  12.  * published by the Free Software Foundation.
  13.  */
  14. #include <linux/config.h>
  15. #include <linux/sched.h>
  16. #include <asm/semaphore.h>
  17. /*
  18.  * Semaphores are implemented using a two-way counter:
  19.  * The "count" variable is decremented for each process
  20.  * that tries to acquire the semaphore, while the "sleeping"
  21.  * variable is a count of such acquires.
  22.  *
  23.  * Notably, the inline "up()" and "down()" functions can
  24.  * efficiently test if they need to do any extra work (up
  25.  * needs to do something only if count was negative before
  26.  * the increment operation.
  27.  *
  28.  * "sleeping" and the contention routine ordering is
  29.  * protected by the semaphore spinlock.
  30.  *
  31.  * Note that these functions are only called when there is
  32.  * contention on the lock, and as such all this is the
  33.  * "non-critical" part of the whole semaphore business. The
  34.  * critical part is the inline stuff in <asm/semaphore.h>
  35.  * where we want to avoid any extra jumps and calls.
  36.  */
  37. /*
  38.  * Logic:
  39.  *  - only on a boundary condition do we need to care. When we go
  40.  *    from a negative count to a non-negative, we wake people up.
  41.  *  - when we go from a non-negative count to a negative do we
  42.  *    (a) synchronize with the "sleeper" count and (b) make sure
  43.  *    that we're on the wakeup list before we synchronize so that
  44.  *    we cannot lose wakeup events.
  45.  */
  46. void __up(struct semaphore *sem)
  47. {
  48. wake_up(&sem->wait);
  49. }
  50. static spinlock_t semaphore_lock = SPIN_LOCK_UNLOCKED;
  51. void __down(struct semaphore * sem)
  52. {
  53. struct task_struct *tsk = current;
  54. DECLARE_WAITQUEUE(wait, tsk);
  55. tsk->state = TASK_UNINTERRUPTIBLE;
  56. add_wait_queue_exclusive(&sem->wait, &wait);
  57. spin_lock_irq(&semaphore_lock);
  58. sem->sleepers++;
  59. for (;;) {
  60. int sleepers = sem->sleepers;
  61. /*
  62.  * Add "everybody else" into it. They aren't
  63.  * playing, because we own the spinlock.
  64.  */
  65. if (!atomic_add_negative(sleepers - 1, &sem->count)) {
  66. sem->sleepers = 0;
  67. break;
  68. }
  69. sem->sleepers = 1; /* us - see -1 above */
  70. spin_unlock_irq(&semaphore_lock);
  71. schedule();
  72. tsk->state = TASK_UNINTERRUPTIBLE;
  73. spin_lock_irq(&semaphore_lock);
  74. }
  75. spin_unlock_irq(&semaphore_lock);
  76. remove_wait_queue(&sem->wait, &wait);
  77. tsk->state = TASK_RUNNING;
  78. wake_up(&sem->wait);
  79. }
  80. int __down_interruptible(struct semaphore * sem)
  81. {
  82. int retval = 0;
  83. struct task_struct *tsk = current;
  84. DECLARE_WAITQUEUE(wait, tsk);
  85. tsk->state = TASK_INTERRUPTIBLE;
  86. add_wait_queue_exclusive(&sem->wait, &wait);
  87. spin_lock_irq(&semaphore_lock);
  88. sem->sleepers ++;
  89. for (;;) {
  90. int sleepers = sem->sleepers;
  91. /*
  92.  * With signals pending, this turns into
  93.  * the trylock failure case - we won't be
  94.  * sleeping, and we* can't get the lock as
  95.  * it has contention. Just correct the count
  96.  * and exit.
  97.  */
  98. if (signal_pending(current)) {
  99. retval = -EINTR;
  100. sem->sleepers = 0;
  101. atomic_add(sleepers, &sem->count);
  102. break;
  103. }
  104. /*
  105.  * Add "everybody else" into it. They aren't
  106.  * playing, because we own the spinlock. The
  107.  * "-1" is because we're still hoping to get
  108.  * the lock.
  109.  */
  110. if (!atomic_add_negative(sleepers - 1, &sem->count)) {
  111. sem->sleepers = 0;
  112. break;
  113. }
  114. sem->sleepers = 1; /* us - see -1 above */
  115. spin_unlock_irq(&semaphore_lock);
  116. schedule();
  117. tsk->state = TASK_INTERRUPTIBLE;
  118. spin_lock_irq(&semaphore_lock);
  119. }
  120. spin_unlock_irq(&semaphore_lock);
  121. tsk->state = TASK_RUNNING;
  122. remove_wait_queue(&sem->wait, &wait);
  123. wake_up(&sem->wait);
  124. return retval;
  125. }
  126. /*
  127.  * Trylock failed - make sure we correct for
  128.  * having decremented the count.
  129.  *
  130.  * We could have done the trylock with a
  131.  * single "cmpxchg" without failure cases,
  132.  * but then it wouldn't work on a 386.
  133.  */
  134. int __down_trylock(struct semaphore * sem)
  135. {
  136. int sleepers;
  137. unsigned long flags;
  138. spin_lock_irqsave(&semaphore_lock, flags);
  139. sleepers = sem->sleepers + 1;
  140. sem->sleepers = 0;
  141. /*
  142.  * Add "everybody else" and us into it. They aren't
  143.  * playing, because we own the spinlock.
  144.  */
  145. if (!atomic_add_negative(sleepers, &sem->count))
  146. wake_up(&sem->wait);
  147. spin_unlock_irqrestore(&semaphore_lock, flags);
  148. return 1;
  149. }
  150. /*
  151.  * The semaphore operations have a special calling sequence that
  152.  * allow us to do a simpler in-line version of them. These routines
  153.  * need to convert that sequence back into the C sequence when
  154.  * there is contention on the semaphore.
  155.  *
  156.  * ip contains the semaphore pointer on entry. Save the C-clobbered
  157.  * registers (r0 to r3 and lr), but not ip, as we use it as a return
  158.  * value in some cases..
  159.  */
  160. #ifdef CONFIG_CPU_26
  161. asm(" .align 5 n
  162. .globl __down_failed n
  163. __down_failed: n
  164. stmfd sp!, {r0 - r3, lr} n
  165. mov r0, ip n
  166. bl __down n
  167. ldmfd sp!, {r0 - r3, pc}^ n
  168. n
  169. .align 5 n
  170. .globl __down_interruptible_failed n
  171. __down_interruptible_failed: n
  172. stmfd sp!, {r0 - r3, lr} n
  173. mov r0, ip n
  174. bl __down_interruptible n
  175. mov ip, r0 n
  176. ldmfd sp!, {r0 - r3, pc}^ n
  177. n
  178. .align 5 n
  179. .globl __down_trylock_failed n
  180. __down_trylock_failed: n
  181. stmfd sp!, {r0 - r3, lr} n
  182. mov r0, ip n
  183. bl __down_trylock n
  184. mov ip, r0 n
  185. ldmfd sp!, {r0 - r3, pc}^ n
  186. n
  187. .align 5 n
  188. .globl __up_wakeup n
  189. __up_wakeup: n
  190. stmfd sp!, {r0 - r3, lr} n
  191. mov r0, ip n
  192. bl __up n
  193. ldmfd sp!, {r0 - r3, pc}^ n
  194. ");
  195. #else
  196. /* 32 bit version */
  197. asm(" .align 5 n
  198. .globl __down_failed n
  199. __down_failed: n
  200. stmfd sp!, {r0 - r3, lr} n
  201. mov r0, ip n
  202. bl __down n
  203. ldmfd sp!, {r0 - r3, pc} n
  204. n
  205. .align 5 n
  206. .globl __down_interruptible_failed n
  207. __down_interruptible_failed: n
  208. stmfd sp!, {r0 - r3, lr} n
  209. mov r0, ip n
  210. bl __down_interruptible n
  211. mov ip, r0 n
  212. ldmfd sp!, {r0 - r3, pc} n
  213. n
  214. .align 5 n
  215. .globl __down_trylock_failed n
  216. __down_trylock_failed: n
  217. stmfd sp!, {r0 - r3, lr} n
  218. mov r0, ip n
  219. bl __down_trylock n
  220. mov ip, r0 n
  221. ldmfd sp!, {r0 - r3, pc} n
  222. n
  223. .align 5 n
  224. .globl __up_wakeup n
  225. __up_wakeup: n
  226. stmfd sp!, {r0 - r3, lr} n
  227. mov r0, ip n
  228. bl __up n
  229. ldmfd sp!, {r0 - r3, pc} n
  230. ");
  231. #endif