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

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * Alpha semaphore implementation.
  3.  *
  4.  * (C) Copyright 1996 Linus Torvalds
  5.  * (C) Copyright 1999, 2000 Richard Henderson
  6.  */
  7. #include <linux/sched.h>
  8. /*
  9.  * Semaphores are implemented using a two-way counter:
  10.  * 
  11.  * The "count" variable is decremented for each process that tries to sleep,
  12.  * while the "waking" variable is incremented when the "up()" code goes to
  13.  * wake up waiting processes.
  14.  *
  15.  * Notably, the inline "up()" and "down()" functions can efficiently test
  16.  * if they need to do any extra work (up needs to do something only if count
  17.  * was negative before the increment operation.
  18.  *
  19.  * waking_non_zero() (from asm/semaphore.h) must execute atomically.
  20.  *
  21.  * When __up() is called, the count was negative before incrementing it,
  22.  * and we need to wake up somebody.
  23.  *
  24.  * This routine adds one to the count of processes that need to wake up and
  25.  * exit.  ALL waiting processes actually wake up but only the one that gets
  26.  * to the "waking" field first will gate through and acquire the semaphore.
  27.  * The others will go back to sleep.
  28.  *
  29.  * Note that these functions are only called when there is contention on the
  30.  * lock, and as such all this is the "non-critical" part of the whole
  31.  * semaphore business. The critical part is the inline stuff in
  32.  * <asm/semaphore.h> where we want to avoid any extra jumps and calls.
  33.  */
  34. /*
  35.  * Perform the "down" function.  Return zero for semaphore acquired,
  36.  * return negative for signalled out of the function.
  37.  *
  38.  * If called from down, the return is ignored and the wait loop is
  39.  * not interruptible.  This means that a task waiting on a semaphore
  40.  * using "down()" cannot be killed until someone does an "up()" on
  41.  * the semaphore.
  42.  *
  43.  * If called from down_interruptible, the return value gets checked
  44.  * upon return.  If the return value is negative then the task continues
  45.  * with the negative value in the return register (it can be tested by
  46.  * the caller).
  47.  *
  48.  * Either form may be used in conjunction with "up()".
  49.  */
  50. void
  51. __down_failed(struct semaphore *sem)
  52. {
  53. DECLARE_WAITQUEUE(wait, current);
  54. #ifdef CONFIG_DEBUG_SEMAPHORE
  55. printk("%s(%d): down failed(%p)n",
  56.        current->comm, current->pid, sem);
  57. #endif
  58. current->state = TASK_UNINTERRUPTIBLE;
  59. wmb();
  60. add_wait_queue_exclusive(&sem->wait, &wait);
  61. /* At this point we know that sem->count is negative.  In order
  62.    to avoid racing with __up, we must check for wakeup before
  63.    going to sleep the first time.  */
  64. while (1) {
  65. long ret, tmp;
  66. /* An atomic conditional decrement of sem->waking.  */
  67. __asm__ __volatile__(
  68. "1: ldl_l %1,%2n"
  69. " blt %1,2fn"
  70. " subl %1,1,%0n"
  71. " stl_c %0,%2n"
  72. " beq %0,3fn"
  73. "2:n"
  74. ".subsection 2n"
  75. "3: br 1bn"
  76. ".previous"
  77. : "=r"(ret), "=&r"(tmp), "=m"(sem->waking)
  78. : "0"(0));
  79. if (ret)
  80. break;
  81. schedule();
  82. set_task_state(current, TASK_UNINTERRUPTIBLE);
  83. }
  84. remove_wait_queue(&sem->wait, &wait);
  85. current->state = TASK_RUNNING;
  86. #ifdef CONFIG_DEBUG_SEMAPHORE
  87. printk("%s(%d): down acquired(%p)n",
  88.        current->comm, current->pid, sem);
  89. #endif
  90. }
  91. int
  92. __down_failed_interruptible(struct semaphore *sem)
  93. {
  94. DECLARE_WAITQUEUE(wait, current);
  95. long ret;
  96. #ifdef CONFIG_DEBUG_SEMAPHORE
  97. printk("%s(%d): down failed(%p)n",
  98.        current->comm, current->pid, sem);
  99. #endif
  100. current->state = TASK_INTERRUPTIBLE;
  101. wmb();
  102. add_wait_queue_exclusive(&sem->wait, &wait);
  103. while (1) {
  104. long tmp, tmp2, tmp3;
  105. /* We must undo the sem->count down_interruptible decrement
  106.    simultaneously and atomicly with the sem->waking
  107.    adjustment, otherwise we can race with __up.  This is
  108.    accomplished by doing a 64-bit ll/sc on two 32-bit words.
  109.    "Equivalent" C.  Note that we have to do this all without
  110.    (taken) branches in order to be a valid ll/sc sequence.
  111.    do {
  112.        tmp = ldq_l;
  113.        ret = 0;
  114.        if (tmp >= 0) { // waking >= 0
  115.            tmp += 0xffffffff00000000; // waking -= 1
  116.            ret = 1;
  117.        }
  118.        else if (pending) {
  119.    // count += 1, but since -1 + 1 carries into the
  120.    // high word, we have to be more careful here.
  121.    tmp = (tmp & 0xffffffff00000000)
  122.  | ((tmp + 1) & 0x00000000ffffffff);
  123.            ret = -EINTR;
  124.        }
  125.        tmp = stq_c = tmp;
  126.    } while (tmp == 0);
  127. */
  128. __asm__ __volatile__(
  129. "1: ldq_l %1,%4n"
  130. " lda %0,0n"
  131. " cmovne %5,%6,%0n"
  132. " addq %1,1,%2n"
  133. " and %1,%7,%3n"
  134. " andnot %2,%7,%2n"
  135. " cmovge %1,1,%0n"
  136. " or %3,%2,%2n"
  137. " addq %1,%7,%3n"
  138. " cmovne %5,%2,%1n"
  139. " cmovge %2,%3,%1n"
  140. " stq_c %1,%4n"
  141. " beq %1,3fn"
  142. "2:n"
  143. ".subsection 2n"
  144. "3: br 1bn"
  145. ".previous"
  146. : "=&r"(ret), "=&r"(tmp), "=&r"(tmp2),
  147.   "=&r"(tmp3), "=m"(*sem)
  148. : "r"(signal_pending(current)), "r"(-EINTR),
  149.   "r"(0xffffffff00000000));
  150. /* At this point we have ret
  151.    1 got the lock
  152.    0 go to sleep
  153.    -EINTR interrupted  */
  154. if (ret != 0)
  155. break;
  156. schedule();
  157. set_task_state(current, TASK_INTERRUPTIBLE);
  158. }
  159. remove_wait_queue(&sem->wait, &wait);
  160. current->state = TASK_RUNNING;
  161. wake_up(&sem->wait);
  162. #ifdef CONFIG_DEBUG_SEMAPHORE
  163. printk("%s(%d): down %s(%p)n",
  164.        current->comm, current->pid,
  165.        (ret < 0 ? "interrupted" : "acquired"), sem);
  166. #endif
  167. /* Convert "got the lock" to 0==success.  */
  168. return (ret < 0 ? ret : 0);
  169. }
  170. void
  171. __up_wakeup(struct semaphore *sem)
  172. {
  173. wake_up(&sem->wait);
  174. }
  175. void
  176. down(struct semaphore *sem)
  177. {
  178. #if WAITQUEUE_DEBUG
  179. CHECK_MAGIC(sem->__magic);
  180. #endif
  181. #ifdef CONFIG_DEBUG_SEMAPHORE
  182. printk("%s(%d): down(%p) <count=%d> from %pn",
  183.        current->comm, current->pid, sem,
  184.        atomic_read(&sem->count), __builtin_return_address(0));
  185. #endif
  186. __down(sem);
  187. }
  188. int
  189. down_interruptible(struct semaphore *sem)
  190. {
  191. #if WAITQUEUE_DEBUG
  192. CHECK_MAGIC(sem->__magic);
  193. #endif
  194. #ifdef CONFIG_DEBUG_SEMAPHORE
  195. printk("%s(%d): down(%p) <count=%d> from %pn",
  196.        current->comm, current->pid, sem,
  197.        atomic_read(&sem->count), __builtin_return_address(0));
  198. #endif
  199. return __down_interruptible(sem);
  200. }
  201. int
  202. down_trylock(struct semaphore *sem)
  203. {
  204. int ret;
  205. #if WAITQUEUE_DEBUG
  206. CHECK_MAGIC(sem->__magic);
  207. #endif
  208. ret = __down_trylock(sem);
  209. #ifdef CONFIG_DEBUG_SEMAPHORE
  210. printk("%s(%d): down_trylock %s from %pn",
  211.        current->comm, current->pid,
  212.        ret ? "failed" : "acquired",
  213.        __builtin_return_address(0));
  214. #endif
  215. return ret;
  216. }
  217. void
  218. up(struct semaphore *sem)
  219. {
  220. #if WAITQUEUE_DEBUG
  221. CHECK_MAGIC(sem->__magic);
  222. #endif
  223. #ifdef CONFIG_DEBUG_SEMAPHORE
  224. printk("%s(%d): up(%p) <count=%d> from %pn",
  225.        current->comm, current->pid, sem,
  226.        atomic_read(&sem->count), __builtin_return_address(0));
  227. #endif
  228. __up(sem);
  229. }