rwsem.h 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. #ifndef _S390_RWSEM_H
  2. #define _S390_RWSEM_H
  3. /*
  4. * S390 version
  5. * Copyright IBM Corp. 2002
  6. * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
  7. *
  8. * Based on asm-alpha/semaphore.h and asm-i386/rwsem.h
  9. */
  10. /*
  11. *
  12. * The MSW of the count is the negated number of active writers and waiting
  13. * lockers, and the LSW is the total number of active locks
  14. *
  15. * The lock count is initialized to 0 (no active and no waiting lockers).
  16. *
  17. * When a writer subtracts WRITE_BIAS, it'll get 0xffff0001 for the case of an
  18. * uncontended lock. This can be determined because XADD returns the old value.
  19. * Readers increment by 1 and see a positive value when uncontended, negative
  20. * if there are writers (and maybe) readers waiting (in which case it goes to
  21. * sleep).
  22. *
  23. * The value of WAITING_BIAS supports up to 32766 waiting processes. This can
  24. * be extended to 65534 by manually checking the whole MSW rather than relying
  25. * on the S flag.
  26. *
  27. * The value of ACTIVE_BIAS supports up to 65535 active processes.
  28. *
  29. * This should be totally fair - if anything is waiting, a process that wants a
  30. * lock will go to the back of the queue. When the currently active lock is
  31. * released, if there's a writer at the front of the queue, then that and only
  32. * that will be woken up; if there's a bunch of consecutive readers at the
  33. * front, then they'll all be woken up, but no other readers will be.
  34. */
  35. #ifndef _LINUX_RWSEM_H
  36. #error "please don't include asm/rwsem.h directly, use linux/rwsem.h instead"
  37. #endif
  38. #define RWSEM_UNLOCKED_VALUE 0x0000000000000000L
  39. #define RWSEM_ACTIVE_BIAS 0x0000000000000001L
  40. #define RWSEM_ACTIVE_MASK 0x00000000ffffffffL
  41. #define RWSEM_WAITING_BIAS (-0x0000000100000000L)
  42. #define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS
  43. #define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
  44. /*
  45. * lock for reading
  46. */
  47. static inline void __down_read(struct rw_semaphore *sem)
  48. {
  49. signed long old, new;
  50. asm volatile(
  51. " lg %0,%2\n"
  52. "0: lgr %1,%0\n"
  53. " aghi %1,%4\n"
  54. " csg %0,%1,%2\n"
  55. " jl 0b"
  56. : "=&d" (old), "=&d" (new), "=Q" (sem->count)
  57. : "Q" (sem->count), "i" (RWSEM_ACTIVE_READ_BIAS)
  58. : "cc", "memory");
  59. if (old < 0)
  60. rwsem_down_read_failed(sem);
  61. }
  62. /*
  63. * trylock for reading -- returns 1 if successful, 0 if contention
  64. */
  65. static inline int __down_read_trylock(struct rw_semaphore *sem)
  66. {
  67. signed long old, new;
  68. asm volatile(
  69. " lg %0,%2\n"
  70. "0: ltgr %1,%0\n"
  71. " jm 1f\n"
  72. " aghi %1,%4\n"
  73. " csg %0,%1,%2\n"
  74. " jl 0b\n"
  75. "1:"
  76. : "=&d" (old), "=&d" (new), "=Q" (sem->count)
  77. : "Q" (sem->count), "i" (RWSEM_ACTIVE_READ_BIAS)
  78. : "cc", "memory");
  79. return old >= 0 ? 1 : 0;
  80. }
  81. /*
  82. * lock for writing
  83. */
  84. static inline long ___down_write(struct rw_semaphore *sem)
  85. {
  86. signed long old, new, tmp;
  87. tmp = RWSEM_ACTIVE_WRITE_BIAS;
  88. asm volatile(
  89. " lg %0,%2\n"
  90. "0: lgr %1,%0\n"
  91. " ag %1,%4\n"
  92. " csg %0,%1,%2\n"
  93. " jl 0b"
  94. : "=&d" (old), "=&d" (new), "=Q" (sem->count)
  95. : "Q" (sem->count), "m" (tmp)
  96. : "cc", "memory");
  97. return old;
  98. }
  99. static inline void __down_write(struct rw_semaphore *sem)
  100. {
  101. if (___down_write(sem))
  102. rwsem_down_write_failed(sem);
  103. }
  104. static inline int __down_write_killable(struct rw_semaphore *sem)
  105. {
  106. if (___down_write(sem))
  107. if (IS_ERR(rwsem_down_write_failed_killable(sem)))
  108. return -EINTR;
  109. return 0;
  110. }
  111. /*
  112. * trylock for writing -- returns 1 if successful, 0 if contention
  113. */
  114. static inline int __down_write_trylock(struct rw_semaphore *sem)
  115. {
  116. signed long old;
  117. asm volatile(
  118. " lg %0,%1\n"
  119. "0: ltgr %0,%0\n"
  120. " jnz 1f\n"
  121. " csg %0,%3,%1\n"
  122. " jl 0b\n"
  123. "1:"
  124. : "=&d" (old), "=Q" (sem->count)
  125. : "Q" (sem->count), "d" (RWSEM_ACTIVE_WRITE_BIAS)
  126. : "cc", "memory");
  127. return (old == RWSEM_UNLOCKED_VALUE) ? 1 : 0;
  128. }
  129. /*
  130. * unlock after reading
  131. */
  132. static inline void __up_read(struct rw_semaphore *sem)
  133. {
  134. signed long old, new;
  135. asm volatile(
  136. " lg %0,%2\n"
  137. "0: lgr %1,%0\n"
  138. " aghi %1,%4\n"
  139. " csg %0,%1,%2\n"
  140. " jl 0b"
  141. : "=&d" (old), "=&d" (new), "=Q" (sem->count)
  142. : "Q" (sem->count), "i" (-RWSEM_ACTIVE_READ_BIAS)
  143. : "cc", "memory");
  144. if (new < 0)
  145. if ((new & RWSEM_ACTIVE_MASK) == 0)
  146. rwsem_wake(sem);
  147. }
  148. /*
  149. * unlock after writing
  150. */
  151. static inline void __up_write(struct rw_semaphore *sem)
  152. {
  153. signed long old, new, tmp;
  154. tmp = -RWSEM_ACTIVE_WRITE_BIAS;
  155. asm volatile(
  156. " lg %0,%2\n"
  157. "0: lgr %1,%0\n"
  158. " ag %1,%4\n"
  159. " csg %0,%1,%2\n"
  160. " jl 0b"
  161. : "=&d" (old), "=&d" (new), "=Q" (sem->count)
  162. : "Q" (sem->count), "m" (tmp)
  163. : "cc", "memory");
  164. if (new < 0)
  165. if ((new & RWSEM_ACTIVE_MASK) == 0)
  166. rwsem_wake(sem);
  167. }
  168. /*
  169. * downgrade write lock to read lock
  170. */
  171. static inline void __downgrade_write(struct rw_semaphore *sem)
  172. {
  173. signed long old, new, tmp;
  174. tmp = -RWSEM_WAITING_BIAS;
  175. asm volatile(
  176. " lg %0,%2\n"
  177. "0: lgr %1,%0\n"
  178. " ag %1,%4\n"
  179. " csg %0,%1,%2\n"
  180. " jl 0b"
  181. : "=&d" (old), "=&d" (new), "=Q" (sem->count)
  182. : "Q" (sem->count), "m" (tmp)
  183. : "cc", "memory");
  184. if (new > 1)
  185. rwsem_downgrade_wake(sem);
  186. }
  187. #endif /* _S390_RWSEM_H */