semaphore.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:6k
源码类别:

Linux/Unix编程

开发平台:

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
  162. .globl __down_failed
  163. __down_failed:
  164. stmfd sp!, {r0 - r3, lr}
  165. mov r0, ip
  166. bl __down
  167. ldmfd sp!, {r0 - r3, pc}^
  168. .align 5
  169. .globl __down_interruptible_failed
  170. __down_interruptible_failed:
  171. stmfd sp!, {r0 - r3, lr}
  172. mov r0, ip
  173. bl __down_interruptible
  174. mov ip, r0
  175. ldmfd sp!, {r0 - r3, pc}^
  176. .align 5
  177. .globl __down_trylock_failed
  178. __down_trylock_failed:
  179. stmfd sp!, {r0 - r3, lr}
  180. mov r0, ip
  181. bl __down_trylock
  182. mov ip, r0
  183. ldmfd sp!, {r0 - r3, pc}^
  184. .align 5
  185. .globl __up_wakeup
  186. __up_wakeup:
  187. stmfd sp!, {r0 - r3, lr}
  188. mov r0, ip
  189. bl __up
  190. ldmfd sp!, {r0 - r3, pc}^
  191. ");
  192. #else
  193. /* 32 bit version */
  194. asm(" .align 5
  195. .globl __down_failed
  196. __down_failed:
  197. stmfd sp!, {r0 - r3, lr}
  198. mov r0, ip
  199. bl __down
  200. ldmfd sp!, {r0 - r3, pc}
  201. .align 5
  202. .globl __down_interruptible_failed
  203. __down_interruptible_failed:
  204. stmfd sp!, {r0 - r3, lr}
  205. mov r0, ip
  206. bl __down_interruptible
  207. mov ip, r0
  208. ldmfd sp!, {r0 - r3, pc}
  209. .align 5
  210. .globl __down_trylock_failed
  211. __down_trylock_failed:
  212. stmfd sp!, {r0 - r3, lr}
  213. mov r0, ip
  214. bl __down_trylock
  215. mov ip, r0
  216. ldmfd sp!, {r0 - r3, pc}
  217. .align 5
  218. .globl __up_wakeup
  219. __up_wakeup:
  220. stmfd sp!, {r0 - r3, lr}
  221. mov r0, ip
  222. bl __up
  223. ldmfd sp!, {r0 - r3, pc}
  224. ");
  225. #endif