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

嵌入式Linux

开发平台:

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