rcuref.h 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. /*
  2. * rcuref.h
  3. *
  4. * Reference counting for elements of lists/arrays protected by
  5. * RCU.
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  20. *
  21. * Copyright (C) IBM Corporation, 2005
  22. *
  23. * Author: Dipankar Sarma <dipankar@in.ibm.com>
  24. * Ravikiran Thirumalai <kiran_th@gmail.com>
  25. *
  26. * See Documentation/RCU/rcuref.txt for detailed user guide.
  27. *
  28. */
  29. #ifndef _RCUREF_H_
  30. #define _RCUREF_H_
  31. #ifdef __KERNEL__
  32. #include <linux/types.h>
  33. #include <linux/interrupt.h>
  34. #include <linux/spinlock.h>
  35. #include <asm/atomic.h>
  36. /*
  37. * These APIs work on traditional atomic_t counters used in the
  38. * kernel for reference counting. Under special circumstances
  39. * where a lock-free get() operation races with a put() operation
  40. * these APIs can be used. See Documentation/RCU/rcuref.txt.
  41. */
  42. #ifdef __HAVE_ARCH_CMPXCHG
  43. /**
  44. * rcuref_inc - increment refcount for object.
  45. * @rcuref: reference counter in the object in question.
  46. *
  47. * This should be used only for objects where we use RCU and
  48. * use the rcuref_inc_lf() api to acquire a reference
  49. * in a lock-free reader-side critical section.
  50. */
  51. static inline void rcuref_inc(atomic_t *rcuref)
  52. {
  53. atomic_inc(rcuref);
  54. }
  55. /**
  56. * rcuref_dec - decrement refcount for object.
  57. * @rcuref: reference counter in the object in question.
  58. *
  59. * This should be used only for objects where we use RCU and
  60. * use the rcuref_inc_lf() api to acquire a reference
  61. * in a lock-free reader-side critical section.
  62. */
  63. static inline void rcuref_dec(atomic_t *rcuref)
  64. {
  65. atomic_dec(rcuref);
  66. }
  67. /**
  68. * rcuref_dec_and_test - decrement refcount for object and test
  69. * @rcuref: reference counter in the object.
  70. * @release: pointer to the function that will clean up the object
  71. * when the last reference to the object is released.
  72. * This pointer is required.
  73. *
  74. * Decrement the refcount, and if 0, return 1. Else return 0.
  75. *
  76. * This should be used only for objects where we use RCU and
  77. * use the rcuref_inc_lf() api to acquire a reference
  78. * in a lock-free reader-side critical section.
  79. */
  80. static inline int rcuref_dec_and_test(atomic_t *rcuref)
  81. {
  82. return atomic_dec_and_test(rcuref);
  83. }
  84. /*
  85. * cmpxchg is needed on UP too, if deletions to the list/array can happen
  86. * in interrupt context.
  87. */
  88. /**
  89. * rcuref_inc_lf - Take reference to an object in a read-side
  90. * critical section protected by RCU.
  91. * @rcuref: reference counter in the object in question.
  92. *
  93. * Try and increment the refcount by 1. The increment might fail if
  94. * the reference counter has been through a 1 to 0 transition and
  95. * is no longer part of the lock-free list.
  96. * Returns non-zero on successful increment and zero otherwise.
  97. */
  98. static inline int rcuref_inc_lf(atomic_t *rcuref)
  99. {
  100. int c, old;
  101. c = atomic_read(rcuref);
  102. while (c && (old = cmpxchg(&rcuref->counter, c, c + 1)) != c)
  103. c = old;
  104. return c;
  105. }
  106. #else /* !__HAVE_ARCH_CMPXCHG */
  107. extern spinlock_t __rcuref_hash[];
  108. /*
  109. * Use a hash table of locks to protect the reference count
  110. * since cmpxchg is not available in this arch.
  111. */
  112. #ifdef CONFIG_SMP
  113. #define RCUREF_HASH_SIZE 4
  114. #define RCUREF_HASH(k) \
  115. (&__rcuref_hash[(((unsigned long)k)>>8) & (RCUREF_HASH_SIZE-1)])
  116. #else
  117. #define RCUREF_HASH_SIZE 1
  118. #define RCUREF_HASH(k) &__rcuref_hash[0]
  119. #endif /* CONFIG_SMP */
  120. /**
  121. * rcuref_inc - increment refcount for object.
  122. * @rcuref: reference counter in the object in question.
  123. *
  124. * This should be used only for objects where we use RCU and
  125. * use the rcuref_inc_lf() api to acquire a reference in a lock-free
  126. * reader-side critical section.
  127. */
  128. static inline void rcuref_inc(atomic_t *rcuref)
  129. {
  130. unsigned long flags;
  131. spin_lock_irqsave(RCUREF_HASH(rcuref), flags);
  132. rcuref->counter += 1;
  133. spin_unlock_irqrestore(RCUREF_HASH(rcuref), flags);
  134. }
  135. /**
  136. * rcuref_dec - decrement refcount for object.
  137. * @rcuref: reference counter in the object in question.
  138. *
  139. * This should be used only for objects where we use RCU and
  140. * use the rcuref_inc_lf() api to acquire a reference in a lock-free
  141. * reader-side critical section.
  142. */
  143. static inline void rcuref_dec(atomic_t *rcuref)
  144. {
  145. unsigned long flags;
  146. spin_lock_irqsave(RCUREF_HASH(rcuref), flags);
  147. rcuref->counter -= 1;
  148. spin_unlock_irqrestore(RCUREF_HASH(rcuref), flags);
  149. }
  150. /**
  151. * rcuref_dec_and_test - decrement refcount for object and test
  152. * @rcuref: reference counter in the object.
  153. * @release: pointer to the function that will clean up the object
  154. * when the last reference to the object is released.
  155. * This pointer is required.
  156. *
  157. * Decrement the refcount, and if 0, return 1. Else return 0.
  158. *
  159. * This should be used only for objects where we use RCU and
  160. * use the rcuref_inc_lf() api to acquire a reference in a lock-free
  161. * reader-side critical section.
  162. */
  163. static inline int rcuref_dec_and_test(atomic_t *rcuref)
  164. {
  165. unsigned long flags;
  166. spin_lock_irqsave(RCUREF_HASH(rcuref), flags);
  167. rcuref->counter--;
  168. if (!rcuref->counter) {
  169. spin_unlock_irqrestore(RCUREF_HASH(rcuref), flags);
  170. return 1;
  171. } else {
  172. spin_unlock_irqrestore(RCUREF_HASH(rcuref), flags);
  173. return 0;
  174. }
  175. }
  176. /**
  177. * rcuref_inc_lf - Take reference to an object of a lock-free collection
  178. * by traversing a lock-free list/array.
  179. * @rcuref: reference counter in the object in question.
  180. *
  181. * Try and increment the refcount by 1. The increment might fail if
  182. * the reference counter has been through a 1 to 0 transition and
  183. * object is no longer part of the lock-free list.
  184. * Returns non-zero on successful increment and zero otherwise.
  185. */
  186. static inline int rcuref_inc_lf(atomic_t *rcuref)
  187. {
  188. int ret;
  189. unsigned long flags;
  190. spin_lock_irqsave(RCUREF_HASH(rcuref), flags);
  191. if (rcuref->counter)
  192. ret = rcuref->counter++;
  193. else
  194. ret = 0;
  195. spin_unlock_irqrestore(RCUREF_HASH(rcuref), flags);
  196. return ret;
  197. }
  198. #endif /* !__HAVE_ARCH_CMPXCHG */
  199. #endif /* __KERNEL__ */
  200. #endif /* _RCUREF_H_ */