Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

304 lines
7.3 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. rundown.c
  5. Abstract:
  6. This module houses routines that do fast referencing of object manager
  7. objects. This is just a thin layer around the fast ref package in EX.
  8. The EX routines are all inline so their description is here.
  9. The basic principle of these routines is to allow fast referencing of
  10. objects held in pointers protected by locks. This is done by assuming
  11. the pointer to an object is aligned on a 8 byte boundary and using the
  12. bottom 3 bits of the pointer as a fast referencing mechanism. The
  13. assumption of this algorithm is that the pointer changes far less
  14. frequently than it is referenced.
  15. Given the following bit definition of a
  16. pointer:
  17. +-----------+---+
  18. | p | n |
  19. +-----------+---+
  20. p << 3 : Object pointer. Bottom three bits are zero. p may be null in
  21. which case n must be zero
  22. n : Total number of pre-references unused
  23. For a non-null p the total number of references on the target object
  24. associated with this structure is >= 1 + 7 - n. There is an associated
  25. reference for the pointer itself and one for each of the possible
  26. extra references.
  27. Fast references proceed to perform one of the following transformation:
  28. +-----------+---+ +-----------+-----+
  29. | p | n | => | p | n-1 | n > 0, p != NULL
  30. +-----------+---+ +-----------+-----+
  31. +-----------+---+ +-----------+---+
  32. | NULL | 0 | => | NULL | 0 | NULL pointers are never fast refed
  33. +-----------+---+ +-----------+---+ and never have cached references
  34. Slow references do the following transformation:
  35. +-----------+---+ +-----------+-----+
  36. | p | 0 | => | p | 7 | An addition 8 references are
  37. +-----------+---+ +-----------+-----+ added to the object
  38. The second transformation is either done under a lock or done by the
  39. thread that does the transition with n = 1 => n = 0.
  40. The reference obtained by this fast algorithm may be released by
  41. dereferencing the target object directly or by attempting to return the
  42. reference to the pointer. Returning the reference to the pointer has
  43. the following transformations:
  44. +-----------+---+ +-----------+-----+
  45. | p | n | => | p | n+1 | n < 7, p != NULL
  46. +-----------+---+ +-----------+-----+
  47. +-----------+---+ +-----------+-----+
  48. | p | 7 | => | p | 0 | Dereference the object directly
  49. +-----------+---+ +-----------+-----+
  50. +-----------+---+ +-----------+-----+ Dereference the object directly
  51. | q | n | => | q | n | as the pointer p has been
  52. +-----------+---+ +-----------+-----+ replaced by q. q May be NULL
  53. Author:
  54. Neill Clift (NeillC) 29-Jul-2000
  55. Revision History:
  56. --*/
  57. #include "obp.h"
  58. #pragma hdrstop
  59. #ifdef ALLOC_PRAGMA
  60. #pragma alloc_text(PAGE,ObInitializeFastReference)
  61. #pragma alloc_text(PAGE,ObFastReferenceObject)
  62. #pragma alloc_text(PAGE,ObFastReferenceObjectLocked)
  63. #pragma alloc_text(PAGE,ObFastDereferenceObject)
  64. #pragma alloc_text(PAGE,ObFastReplaceObject)
  65. #endif
  66. NTKERNELAPI
  67. VOID
  68. FASTCALL
  69. ObInitializeFastReference (
  70. IN PEX_FAST_REF FastRef,
  71. IN PVOID Object
  72. )
  73. /*++
  74. Routine Description:
  75. Initialize a fast reference structure.
  76. Arguments:
  77. FastRef - Rundown block to be initialized
  78. Return Value:
  79. None
  80. --*/
  81. {
  82. //
  83. // If an object was given then bias the object reference by the cache size.
  84. //
  85. if (Object != NULL) {
  86. ObReferenceObjectEx (Object, ExFastRefGetAdditionalReferenceCount ());
  87. }
  88. ExFastRefInitialize (FastRef, Object);
  89. }
  90. NTKERNELAPI
  91. PVOID
  92. FASTCALL
  93. ObFastReferenceObject (
  94. IN PEX_FAST_REF FastRef
  95. )
  96. /*++
  97. Routine Description:
  98. This routine attempts a fast reference of an object in a fast ref
  99. structure.
  100. Arguments:
  101. FastRef - Rundown block to be used for the reference
  102. Return Value:
  103. PVOID - Object that was referenced or NULL if we failed
  104. --*/
  105. {
  106. EX_FAST_REF OldRef;
  107. PVOID Object;
  108. ULONG RefsToAdd, Unused;
  109. //
  110. // Attempt the fast reference
  111. //
  112. OldRef = ExFastReference (FastRef);
  113. Object = ExFastRefGetObject (OldRef);
  114. //
  115. // We fail if there wasn't an object or if it has no cached references
  116. // left. Both of these cases had the cached reference count zero.
  117. //
  118. Unused = ExFastRefGetUnusedReferences (OldRef);
  119. if (Unused <= 1) {
  120. if (Unused == 0) {
  121. return NULL;
  122. }
  123. //
  124. // If we took the counter to zero then attempt to make life easier for
  125. // the next referencer by resetting the counter to its max. Since we now
  126. // have a reference to the object we can do this.
  127. //
  128. RefsToAdd = ExFastRefGetAdditionalReferenceCount ();
  129. ObReferenceObjectEx (Object, RefsToAdd);
  130. //
  131. // Try to add the added references to the cache. If we fail then just
  132. // release them.
  133. //
  134. if (!ExFastRefAddAdditionalReferenceCounts (FastRef, Object, RefsToAdd)) {
  135. ObDereferenceObjectEx (Object, RefsToAdd);
  136. }
  137. }
  138. return Object;
  139. }
  140. NTKERNELAPI
  141. PVOID
  142. FASTCALL
  143. ObFastReferenceObjectLocked (
  144. IN PEX_FAST_REF FastRef
  145. )
  146. /*++
  147. Routine Description:
  148. This routine does a slow object reference. This must be called while
  149. holding a lock.
  150. Arguments:
  151. FastRef - Rundown block to be used to reference the object
  152. Return Value:
  153. PVOID - Object that was referenced or NULL if there was no object.
  154. --*/
  155. {
  156. PVOID Object;
  157. EX_FAST_REF OldRef;
  158. OldRef = *FastRef;
  159. Object = ExFastRefGetObject (OldRef);
  160. if (Object != NULL) {
  161. ObReferenceObject (Object);
  162. }
  163. return Object;
  164. }
  165. NTKERNELAPI
  166. VOID
  167. FASTCALL
  168. ObFastDereferenceObject (
  169. IN PEX_FAST_REF FastRef,
  170. IN PVOID Object
  171. )
  172. /*++
  173. Routine Description:
  174. This routine does a fast dereference if possible.
  175. Arguments:
  176. FastRef - Rundown block to be used to dereference the object
  177. Return Value:
  178. None.
  179. --*/
  180. {
  181. if (!ExFastRefDereference (FastRef, Object)) {
  182. //
  183. // If the object changed or there is no space left in the reference
  184. // cache then just deref the object.
  185. //
  186. ObDereferenceObject (Object);
  187. }
  188. }
  189. NTKERNELAPI
  190. PVOID
  191. FASTCALL
  192. ObFastReplaceObject (
  193. IN PEX_FAST_REF FastRef,
  194. IN PVOID Object
  195. )
  196. /*++
  197. Routine Description:
  198. This routine does a swap of the object. This must be called while holding
  199. a lock.
  200. Arguments:
  201. FastRef - Rundown block to be used to do the swap.
  202. Return Value:
  203. PVOID - Object that was in the block before the swap..
  204. --*/
  205. {
  206. EX_FAST_REF OldRef;
  207. PVOID OldObject;
  208. ULONG RefsToReturn;
  209. //
  210. // If we have been given an object then bias it by the correct amount.
  211. //
  212. if (Object != NULL) {
  213. ObReferenceObjectEx (Object, ExFastRefGetAdditionalReferenceCount ());
  214. }
  215. //
  216. // Do the swap
  217. //
  218. OldRef = ExFastRefSwapObject (FastRef, Object);
  219. OldObject = ExFastRefGetObject (OldRef);
  220. //
  221. // If there was an original object then we need to work out how many
  222. // cached references there were (if any) and return them.
  223. //
  224. if (OldObject != NULL) {
  225. RefsToReturn = ExFastRefGetUnusedReferences (OldRef);
  226. if (RefsToReturn > 0) {
  227. ObDereferenceObjectEx (OldObject, RefsToReturn);
  228. }
  229. }
  230. return OldObject;
  231. }