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.

354 lines
7.2 KiB

  1. /*++
  2. Copyright (c) 1998, Microsoft Corporation
  3. Module Name:
  4. compref.h
  5. Abstract:
  6. This module contains declarations for maintaining reference-count
  7. on a component. It provides an asynchronous thread-safe means of
  8. handling cleanup in a module.
  9. The mechanism defined uses a locked reference count and cleanup-routine
  10. to manage the lifetime of the component. When the reference-count
  11. is dropped to zero, the associated cleanup-routine is invoked.
  12. Author:
  13. Abolade Gbadegesin (aboladeg) 6-Mar-1998
  14. Revision History:
  15. --*/
  16. #ifndef _NATHLP_COMPREF_H_
  17. #define _NATHLP_COMPREF_H_
  18. typedef
  19. VOID
  20. (*PCOMPONENT_CLEANUP_ROUTINE)(
  21. VOID
  22. );
  23. //
  24. // Structure: COMPONENT_REFERENCE
  25. //
  26. // This structure must reside in memory for the lifetime of the component
  27. // to which it refers. It is used to synchronize the components execution.
  28. //
  29. typedef struct _COMPONENT_REFERENCE {
  30. KSPIN_LOCK Lock;
  31. ULONG ReferenceCount;
  32. BOOLEAN Deleted;
  33. KEVENT Event;
  34. PCOMPONENT_CLEANUP_ROUTINE CleanupRoutine;
  35. } COMPONENT_REFERENCE, *PCOMPONENT_REFERENCE;
  36. //
  37. // FUNCTION DECLARATIONS
  38. //
  39. __inline
  40. BOOLEAN
  41. AcquireComponentReference(
  42. PCOMPONENT_REFERENCE ComponentReference
  43. );
  44. VOID
  45. __inline
  46. DeleteComponentReference(
  47. PCOMPONENT_REFERENCE ComponentReference
  48. );
  49. ULONG
  50. __inline
  51. InitializeComponentReference(
  52. PCOMPONENT_REFERENCE ComponentReference,
  53. PCOMPONENT_CLEANUP_ROUTINE CleanupRoutine
  54. );
  55. __inline
  56. BOOLEAN
  57. ReleaseComponentReference(
  58. PCOMPONENT_REFERENCE ComponentReference
  59. );
  60. __inline
  61. BOOLEAN
  62. ReleaseInitialComponentReference(
  63. PCOMPONENT_REFERENCE ComponentReference,
  64. BOOLEAN Wait
  65. );
  66. __inline
  67. VOID
  68. ResetComponentReference(
  69. PCOMPONENT_REFERENCE ComponentReference
  70. );
  71. //
  72. // MACRO DECLARATIONS
  73. //
  74. #define RETURN_VOID
  75. #define REFERENCE_COMPONENT(c) \
  76. AcquireComponentReference(c)
  77. #define DEREFERENCE_COMPONENT(c) \
  78. ReleaseComponentReference(c)
  79. #define REFERENCE_COMPONENT_OR_RETURN(c,retcode) \
  80. if (!AcquireComponentReference(c)) { return retcode; }
  81. #define DEREFERENCE_COMPONENT_AND_RETURN(c,retcode) \
  82. ReleaseComponentReference(c); return retcode
  83. //
  84. // INLINE ROUTINE IMPLEMENTATIONS
  85. //
  86. __inline
  87. BOOLEAN
  88. AcquireComponentReference(
  89. PCOMPONENT_REFERENCE ComponentReference
  90. )
  91. /*++
  92. Routine Description:
  93. This routine is called to increment the reference-count to a component.
  94. The attempt may fail if the initial reference has been released
  95. and the component is therefore being deleted.
  96. Arguments:
  97. ComponentReference - the component to be referenced
  98. Return Value:
  99. BOOLEAN - TRUE if the component was referenced, FALSE otherwise.
  100. --*/
  101. {
  102. KIRQL Irql;
  103. KeAcquireSpinLock(&ComponentReference->Lock, &Irql);
  104. if (ComponentReference->Deleted) {
  105. KeReleaseSpinLock(&ComponentReference->Lock, Irql);
  106. return FALSE;
  107. }
  108. ++ComponentReference->ReferenceCount;
  109. KeReleaseSpinLock(&ComponentReference->Lock, Irql);
  110. return TRUE;
  111. } // AcquireComponentReference
  112. VOID
  113. __inline
  114. DeleteComponentReference(
  115. PCOMPONENT_REFERENCE ComponentReference
  116. )
  117. /*++
  118. Routine Description:
  119. This routine is called to destroy a component reference.
  120. It may only be called after the last reference to the component is released,
  121. i.e. after 'ReleaseComponentReference' has returned 'TRUE'.
  122. It may also be called from within the component's 'CleanupRoutine'.
  123. Arguments:
  124. ComponentReference - the component to be destroyed
  125. Return Value:
  126. none.
  127. --*/
  128. {
  129. } // DeleteComponentReference
  130. ULONG
  131. __inline
  132. InitializeComponentReference(
  133. PCOMPONENT_REFERENCE ComponentReference,
  134. PCOMPONENT_CLEANUP_ROUTINE CleanupRoutine
  135. )
  136. /*++
  137. Routine Description:
  138. This routine is called to initialize a component reference.
  139. Arguments:
  140. ComponentReference - the component to be initialized
  141. CleanupRoutine - the routine to be called when the component
  142. is to be cleaned up (within the final 'ReleaseComponentReference').
  143. Return Value:
  144. none.
  145. --*/
  146. {
  147. KeInitializeSpinLock(&ComponentReference->Lock);
  148. KeInitializeEvent(&ComponentReference->Event, NotificationEvent, FALSE);
  149. ComponentReference->Deleted = FALSE;
  150. ComponentReference->ReferenceCount = 1;
  151. ComponentReference->CleanupRoutine = CleanupRoutine;
  152. return STATUS_SUCCESS;
  153. } // InitializeComponentReference
  154. __inline
  155. BOOLEAN
  156. ReleaseComponentReference(
  157. PCOMPONENT_REFERENCE ComponentReference
  158. )
  159. /*++
  160. Routine Description:
  161. This routine is called to drop a reference to a component.
  162. If the reference drops to zero, cleanup is performed.
  163. Otherwise, cleanup occurs later when the last reference is released.
  164. Arguments:
  165. ComponentReference - the component to be referenced
  166. Return Value:
  167. BOOLEAN - TRUE if the component was cleaned up, FALSE otherwise.
  168. --*/
  169. {
  170. KIRQL Irql;
  171. KeAcquireSpinLock(&ComponentReference->Lock, &Irql);
  172. if (--ComponentReference->ReferenceCount) {
  173. KeReleaseSpinLock(&ComponentReference->Lock, Irql);
  174. return FALSE;
  175. }
  176. KeReleaseSpinLock(&ComponentReference->Lock, Irql);
  177. KeSetEvent(&ComponentReference->Event, 0, FALSE);
  178. ComponentReference->CleanupRoutine();
  179. return TRUE;
  180. } // ReleaseComponentReference
  181. __inline
  182. BOOLEAN
  183. ReleaseInitialComponentReference(
  184. PCOMPONENT_REFERENCE ComponentReference,
  185. BOOLEAN Wait
  186. )
  187. /*++
  188. Routine Description:
  189. This routine is called to drop the initial reference to a component,
  190. and mark the component as deleted.
  191. If the reference drops to zero, cleanup is performed right away.
  192. Arguments:
  193. ComponentReference - the component to be referenced
  194. Wait - if TRUE, the routine waits till the last reference is released.
  195. Return Value:
  196. BOOLEAN - TRUE if the component was cleaned up, FALSE otherwise.
  197. --*/
  198. {
  199. KIRQL Irql;
  200. KeAcquireSpinLock(&ComponentReference->Lock, &Irql);
  201. if (ComponentReference->Deleted) {
  202. KeReleaseSpinLock(&ComponentReference->Lock, Irql);
  203. return TRUE;
  204. }
  205. ComponentReference->Deleted = TRUE;
  206. if (--ComponentReference->ReferenceCount) {
  207. if (!Wait) {
  208. KeReleaseSpinLock(&ComponentReference->Lock, Irql);
  209. return FALSE;
  210. }
  211. else {
  212. PKEVENT Event = &ComponentReference->Event;
  213. KeReleaseSpinLock(&ComponentReference->Lock, Irql);
  214. KeWaitForSingleObject(
  215. Event,
  216. Executive,
  217. KernelMode,
  218. FALSE,
  219. NULL
  220. );
  221. return TRUE;
  222. }
  223. }
  224. KeReleaseSpinLock(&ComponentReference->Lock, Irql);
  225. ComponentReference->CleanupRoutine();
  226. return TRUE;
  227. } // ReleaseInitialComponentReference
  228. __inline
  229. VOID
  230. ResetComponentReference(
  231. PCOMPONENT_REFERENCE ComponentReference
  232. )
  233. /*++
  234. Routine Description:
  235. This routine is called to reset a component reference
  236. to an initial state.
  237. Arguments:
  238. ComponentReference - the component to be reset
  239. Return Value:
  240. none.
  241. --*/
  242. {
  243. KIRQL Irql;
  244. KeAcquireSpinLock(&ComponentReference->Lock, &Irql);
  245. ComponentReference->ReferenceCount = 1;
  246. ComponentReference->Deleted = FALSE;
  247. KeReleaseSpinLock(&ComponentReference->Lock, Irql);
  248. } // ReleaseComponentReference
  249. #endif // _NATHLP_COMPREF_H_