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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * SMP- and interrupt-safe semaphores helper functions.
  3.  *
  4.  * Copyright (C) 1996 Linus Torvalds
  5.  * Copyright (C) 1999 Andrea Arcangeli
  6.  * Copyright (C) 1999 Ralf Baechle
  7.  * Copyright (C) 1999 Silicon Graphics, Inc.
  8.  * Copyright (C) 2000 MIPS Technologies, Inc.
  9.  */
  10. #ifndef _ASM_SEMAPHORE_HELPER_H
  11. #define _ASM_SEMAPHORE_HELPER_H
  12. #include <linux/config.h>
  13. #define sem_read(a) ((a)->counter)
  14. #define sem_inc(a) (((a)->counter)++)
  15. #define sem_dec(a) (((a)->counter)--)
  16. /*
  17.  * These two _must_ execute atomically wrt each other.
  18.  */
  19. static inline void wake_one_more(struct semaphore * sem)
  20. {
  21. atomic_inc(&sem->waking);
  22. }
  23. #ifdef CONFIG_CPU_HAS_LLSC
  24. static inline int waking_non_zero(struct semaphore *sem)
  25. {
  26. int ret, tmp;
  27. __asm__ __volatile__(
  28. "1:tllt%1, %2ttt# waking_non_zeront"
  29. "blezt%1, 2fnt"
  30. "subut%0, %1, 1nt"
  31. "sct%0, %2nt"
  32. "beqzt%0, 1bn"
  33. "2:"
  34. : "=r" (ret), "=r" (tmp), "+m" (sem->waking)
  35. : "0"(0));
  36. return ret;
  37. }
  38. #else /* !CONFIG_CPU_HAS_LLSC */
  39. /*
  40.  * It doesn't make sense, IMHO, to endlessly turn interrupts off and on again.
  41.  * Do it once and that's it. ll/sc *has* it's advantages. HK
  42.  */
  43. static inline int waking_non_zero(struct semaphore *sem)
  44. {
  45. unsigned long flags;
  46. int ret = 0;
  47. save_and_cli(flags);
  48. if (sem_read(&sem->waking) > 0) {
  49. sem_dec(&sem->waking);
  50. ret = 1;
  51. }
  52. restore_flags(flags);
  53. return ret;
  54. }
  55. #endif /* !CONFIG_CPU_HAS_LLSC */
  56. #ifdef CONFIG_CPU_HAS_LLDSCD
  57. /*
  58.  * waking_non_zero_interruptible:
  59.  * 1 got the lock
  60.  * 0 go to sleep
  61.  * -EINTR interrupted
  62.  *
  63.  * We must undo the sem->count down_interruptible decrement
  64.  * simultaneously and atomically with the sem->waking adjustment,
  65.  * otherwise we can race with wake_one_more.
  66.  *
  67.  * This is accomplished by doing a 64-bit lld/scd on the 2 32-bit words.
  68.  *
  69.  * This is crazy.  Normally it's strictly forbidden to use 64-bit operations
  70.  * in the 32-bit MIPS kernel.  In this case it's however ok because if an
  71.  * interrupt has destroyed the upper half of registers sc will fail.
  72.  * Note also that this will not work for MIPS32 CPUs!
  73.  *
  74.  * Pseudocode:
  75.  *
  76.  * If(sem->waking > 0) {
  77.  * Decrement(sem->waking)
  78.  * Return(SUCCESS)
  79.  * } else If(signal_pending(tsk)) {
  80.  * Increment(sem->count)
  81.  * Return(-EINTR)
  82.  * } else {
  83.  * Return(SLEEP)
  84.  * }
  85.  */
  86. static inline int
  87. waking_non_zero_interruptible(struct semaphore *sem, struct task_struct *tsk)
  88. {
  89. long ret, tmp;
  90. __asm__ __volatile__(
  91. ".settpushnt"
  92. ".settmips3nt"
  93. ".settnoatn"
  94. "0:tlldt%1, %2nt"
  95. "lit%0, 0nt"
  96. "sllt$1, %1, 0nt"
  97. "blezt$1, 1fnt"
  98. "daddiut%1, %1, -1nt"
  99. "lit%0, 1nt"
  100. "bt2fn"
  101. "1:tbeqzt%3, 2fnt"
  102. "lit%0, %4nt"
  103. "dlit$1, 0x0000000100000000nt"
  104. "daddut%1, %1, $1n"
  105. "2:tscdt%1, %2nt"
  106. "beqzt%1, 0bnt"
  107. ".settpop"
  108. : "=&r" (ret), "=&r" (tmp), "=m" (*sem)
  109. : "r" (signal_pending(tsk)), "i" (-EINTR));
  110. return ret;
  111. }
  112. /*
  113.  * waking_non_zero_trylock is unused.  we do everything in
  114.  * down_trylock and let non-ll/sc hosts bounce around.
  115.  */
  116. static inline int waking_non_zero_trylock(struct semaphore *sem)
  117. {
  118. #if WAITQUEUE_DEBUG
  119. CHECK_MAGIC(sem->__magic);
  120. #endif
  121. return 0;
  122. }
  123. #else /* !CONFIG_CPU_HAS_LLDSCD */
  124. static inline int waking_non_zero_interruptible(struct semaphore *sem,
  125. struct task_struct *tsk)
  126. {
  127. int ret = 0;
  128. unsigned long flags;
  129. save_and_cli(flags);
  130. if (sem_read(&sem->waking) > 0) {
  131. sem_dec(&sem->waking);
  132. ret = 1;
  133. } else if (signal_pending(tsk)) {
  134. sem_inc(&sem->count);
  135. ret = -EINTR;
  136. }
  137. restore_flags(flags);
  138. return ret;
  139. }
  140. static inline int waking_non_zero_trylock(struct semaphore *sem)
  141. {
  142.         int ret = 1;
  143. unsigned long flags;
  144. save_and_cli(flags);
  145. if (sem_read(&sem->waking) <= 0)
  146. sem_inc(&sem->count);
  147. else {
  148. sem_dec(&sem->waking);
  149. ret = 0;
  150. }
  151. restore_flags(flags);
  152. return ret;
  153. }
  154. #endif /* !CONFIG_CPU_HAS_LLDSCD */
  155. #endif /* _ASM_SEMAPHORE_HELPER_H */