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

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * BK Id: SCCS/s.semaphore.c 1.12 05/17/01 18:14:22 cort
  3.  */
  4. /*
  5.  * PowerPC-specific semaphore code.
  6.  *
  7.  * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
  8.  *
  9.  * This program is free software; you can redistribute it and/or
  10.  * modify it under the terms of the GNU General Public License
  11.  * as published by the Free Software Foundation; either version
  12.  * 2 of the License, or (at your option) any later version.
  13.  *
  14.  * April 2001 - Reworked by Paul Mackerras <paulus@samba.org>
  15.  * to eliminate the SMP races in the old version between the updates
  16.  * of `count' and `waking'.  Now we use negative `count' values to
  17.  * indicate that some process(es) are waiting for the semaphore.
  18.  */
  19. #include <linux/sched.h>
  20. #include <asm/atomic.h>
  21. #include <asm/semaphore.h>
  22. /*
  23.  * Atomically update sem->count.
  24.  * This does the equivalent of the following:
  25.  *
  26.  * old_count = sem->count;
  27.  * tmp = MAX(old_count, 0) + incr;
  28.  * sem->count = tmp;
  29.  * return old_count;
  30.  */
  31. static inline int __sem_update_count(struct semaphore *sem, int incr)
  32. {
  33. int old_count, tmp;
  34. __asm__ __volatile__("n"
  35. "1: lwarx %0,0,%3n"
  36. " srawi %1,%0,31n"
  37. " andc %1,%0,%1n"
  38. " add %1,%1,%4n"
  39. " stwcx. %1,0,%3n"
  40. " bne 1b"
  41. : "=&r" (old_count), "=&r" (tmp), "=m" (sem->count)
  42. : "r" (&sem->count), "r" (incr), "m" (sem->count)
  43. : "cc");
  44. return old_count;
  45. }
  46. void __up(struct semaphore *sem)
  47. {
  48. /*
  49.  * Note that we incremented count in up() before we came here,
  50.  * but that was ineffective since the result was <= 0, and
  51.  * any negative value of count is equivalent to 0.
  52.  * This ends up setting count to 1, unless count is now > 0
  53.  * (i.e. because some other cpu has called up() in the meantime),
  54.  * in which case we just increment count.
  55.  */
  56. __sem_update_count(sem, 1);
  57. wake_up(&sem->wait);
  58. }
  59. /*
  60.  * Note that when we come in to __down or __down_interruptible,
  61.  * we have already decremented count, but that decrement was
  62.  * ineffective since the result was < 0, and any negative value
  63.  * of count is equivalent to 0.
  64.  * Thus it is only when we decrement count from some value > 0
  65.  * that we have actually got the semaphore.
  66.  */
  67. void __down(struct semaphore *sem)
  68. {
  69. struct task_struct *tsk = current;
  70. DECLARE_WAITQUEUE(wait, tsk);
  71. tsk->state = TASK_UNINTERRUPTIBLE;
  72. add_wait_queue_exclusive(&sem->wait, &wait);
  73. smp_wmb();
  74. /*
  75.  * Try to get the semaphore.  If the count is > 0, then we've
  76.  * got the semaphore; we decrement count and exit the loop.
  77.  * If the count is 0 or negative, we set it to -1, indicating
  78.  * that we are asleep, and then sleep.
  79.  */
  80. while (__sem_update_count(sem, -1) <= 0) {
  81. schedule();
  82. tsk->state = TASK_UNINTERRUPTIBLE;
  83. }
  84. remove_wait_queue(&sem->wait, &wait);
  85. tsk->state = TASK_RUNNING;
  86. /*
  87.  * If there are any more sleepers, wake one of them up so
  88.  * that it can either get the semaphore, or set count to -1
  89.  * indicating that there are still processes sleeping.
  90.  */
  91. wake_up(&sem->wait);
  92. }
  93. int __down_interruptible(struct semaphore * sem)
  94. {
  95. int retval = 0;
  96. struct task_struct *tsk = current;
  97. DECLARE_WAITQUEUE(wait, tsk);
  98. tsk->state = TASK_INTERRUPTIBLE;
  99. add_wait_queue_exclusive(&sem->wait, &wait);
  100. smp_wmb();
  101. while (__sem_update_count(sem, -1) <= 0) {
  102. if (signal_pending(current)) {
  103. /*
  104.  * A signal is pending - give up trying.
  105.  * Set sem->count to 0 if it is negative,
  106.  * since we are no longer sleeping.
  107.  */
  108. __sem_update_count(sem, 0);
  109. retval = -EINTR;
  110. break;
  111. }
  112. schedule();
  113. tsk->state = TASK_INTERRUPTIBLE;
  114. }
  115. tsk->state = TASK_RUNNING;
  116. remove_wait_queue(&sem->wait, &wait);
  117. wake_up(&sem->wait);
  118. return retval;
  119. }