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

嵌入式Linux

开发平台:

Unix_Linux

  1. /* $Id: semaphore.c,v 1.7 2001/04/18 21:06:05 davem Exp $ */
  2. /* sparc32 semaphore implementation, based on i386 version */
  3. #include <linux/sched.h>
  4. #include <asm/semaphore.h>
  5. /*
  6.  * Semaphores are implemented using a two-way counter:
  7.  * The "count" variable is decremented for each process
  8.  * that tries to acquire the semaphore, while the "sleeping"
  9.  * variable is a count of such acquires.
  10.  *
  11.  * Notably, the inline "up()" and "down()" functions can
  12.  * efficiently test if they need to do any extra work (up
  13.  * needs to do something only if count was negative before
  14.  * the increment operation.
  15.  *
  16.  * "sleeping" and the contention routine ordering is
  17.  * protected by the semaphore spinlock.
  18.  *
  19.  * Note that these functions are only called when there is
  20.  * contention on the lock, and as such all this is the
  21.  * "non-critical" part of the whole semaphore business. The
  22.  * critical part is the inline stuff in <asm/semaphore.h>
  23.  * where we want to avoid any extra jumps and calls.
  24.  */
  25. /*
  26.  * Logic:
  27.  *  - only on a boundary condition do we need to care. When we go
  28.  *    from a negative count to a non-negative, we wake people up.
  29.  *  - when we go from a non-negative count to a negative do we
  30.  *    (a) synchronize with the "sleeper" count and (b) make sure
  31.  *    that we're on the wakeup list before we synchronize so that
  32.  *    we cannot lose wakeup events.
  33.  */
  34. void __up(struct semaphore *sem)
  35. {
  36. wake_up(&sem->wait);
  37. }
  38. static spinlock_t semaphore_lock = SPIN_LOCK_UNLOCKED;
  39. void __down(struct semaphore * sem)
  40. {
  41. struct task_struct *tsk = current;
  42. DECLARE_WAITQUEUE(wait, tsk);
  43. tsk->state = TASK_UNINTERRUPTIBLE;
  44. add_wait_queue_exclusive(&sem->wait, &wait);
  45. spin_lock_irq(&semaphore_lock);
  46. sem->sleepers++;
  47. for (;;) {
  48. int sleepers = sem->sleepers;
  49. /*
  50.  * Add "everybody else" into it. They aren't
  51.  * playing, because we own the spinlock.
  52.  */
  53. if (!atomic_add_negative(sleepers - 1, &sem->count)) {
  54. sem->sleepers = 0;
  55. break;
  56. }
  57. sem->sleepers = 1; /* us - see -1 above */
  58. spin_unlock_irq(&semaphore_lock);
  59. schedule();
  60. tsk->state = TASK_UNINTERRUPTIBLE;
  61. spin_lock_irq(&semaphore_lock);
  62. }
  63. spin_unlock_irq(&semaphore_lock);
  64. remove_wait_queue(&sem->wait, &wait);
  65. tsk->state = TASK_RUNNING;
  66. wake_up(&sem->wait);
  67. }
  68. int __down_interruptible(struct semaphore * sem)
  69. {
  70. int retval = 0;
  71. struct task_struct *tsk = current;
  72. DECLARE_WAITQUEUE(wait, tsk);
  73. tsk->state = TASK_INTERRUPTIBLE;
  74. add_wait_queue_exclusive(&sem->wait, &wait);
  75. spin_lock_irq(&semaphore_lock);
  76. sem->sleepers ++;
  77. for (;;) {
  78. int sleepers = sem->sleepers;
  79. /*
  80.  * With signals pending, this turns into
  81.  * the trylock failure case - we won't be
  82.  * sleeping, and we* can't get the lock as
  83.  * it has contention. Just correct the count
  84.  * and exit.
  85.  */
  86. if (signal_pending(current)) {
  87. retval = -EINTR;
  88. sem->sleepers = 0;
  89. atomic_add(sleepers, &sem->count);
  90. break;
  91. }
  92. /*
  93.  * Add "everybody else" into it. They aren't
  94.  * playing, because we own the spinlock. The
  95.  * "-1" is because we're still hoping to get
  96.  * the lock.
  97.  */
  98. if (!atomic_add_negative(sleepers - 1, &sem->count)) {
  99. sem->sleepers = 0;
  100. break;
  101. }
  102. sem->sleepers = 1; /* us - see -1 above */
  103. spin_unlock_irq(&semaphore_lock);
  104. schedule();
  105. tsk->state = TASK_INTERRUPTIBLE;
  106. spin_lock_irq(&semaphore_lock);
  107. }
  108. spin_unlock_irq(&semaphore_lock);
  109. tsk->state = TASK_RUNNING;
  110. remove_wait_queue(&sem->wait, &wait);
  111. wake_up(&sem->wait);
  112. return retval;
  113. }
  114. /*
  115.  * Trylock failed - make sure we correct for
  116.  * having decremented the count.
  117.  */
  118. int __down_trylock(struct semaphore * sem)
  119. {
  120. int sleepers;
  121. unsigned long flags;
  122. spin_lock_irqsave(&semaphore_lock, flags);
  123. sleepers = sem->sleepers + 1;
  124. sem->sleepers = 0;
  125. /*
  126.  * Add "everybody else" and us into it. They aren't
  127.  * playing, because we own the spinlock.
  128.  */
  129. if (!atomic_add_negative(sleepers, &sem->count))
  130. wake_up(&sem->wait);
  131. spin_unlock_irqrestore(&semaphore_lock, flags);
  132. return 1;
  133. }