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.

426 lines
8.9 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 component's execution.
  28. //
  29. typedef struct _COMPONENT_REFERENCE {
  30. CRITICAL_SECTION Lock;
  31. ULONG ReferenceCount;
  32. BOOLEAN Deleted;
  33. PCOMPONENT_CLEANUP_ROUTINE CleanupRoutine;
  34. #if COMPREF_TRACKING
  35. struct _COMPREF_RECORD* RecordArray;
  36. ULONG RecordIndex;
  37. #endif
  38. } COMPONENT_REFERENCE, *PCOMPONENT_REFERENCE;
  39. #if COMPREF_TRACKING
  40. #define COMPREF_RECORD_COUNT (1024)
  41. typedef struct _COMPREF_RECORD {
  42. PCHAR File;
  43. USHORT Line;
  44. UCHAR ReferenceCount;
  45. enum {
  46. ComprefAcquireRecord,
  47. ComprefReleaseRecord
  48. } Type;
  49. } COMPREF_RECORD, *PCOMPREF_RECORD;
  50. #endif
  51. //
  52. // FUNCTION DECLARATIONS
  53. //
  54. __inline
  55. BOOLEAN
  56. AcquireComponentReference(
  57. PCOMPONENT_REFERENCE ComponentReference
  58. );
  59. VOID
  60. __inline
  61. DeleteComponentReference(
  62. PCOMPONENT_REFERENCE ComponentReference
  63. );
  64. ULONG
  65. __inline
  66. InitializeComponentReference(
  67. PCOMPONENT_REFERENCE ComponentReference,
  68. PCOMPONENT_CLEANUP_ROUTINE CleanupRoutine
  69. );
  70. #if COMPREF_TRACKING
  71. __inline
  72. BOOLEAN
  73. RecordComponentReference(
  74. PCOMPONENT_REFERENCE ComponentReference,
  75. PCHAR File,
  76. ULONG Line,
  77. UCHAR Type
  78. );
  79. #endif
  80. __inline
  81. BOOLEAN
  82. ReleaseComponentReference(
  83. PCOMPONENT_REFERENCE ComponentReference
  84. );
  85. __inline
  86. BOOLEAN
  87. ReleaseInitialComponentReference(
  88. PCOMPONENT_REFERENCE ComponentReference
  89. );
  90. __inline
  91. VOID
  92. ResetComponentReference(
  93. PCOMPONENT_REFERENCE ComponentReference
  94. );
  95. //
  96. // MACRO DECLARATIONS
  97. //
  98. #define RETURN_VOID
  99. #if COMPREF_TRACKING
  100. #define REFERENCE_COMPONENT(c) \
  101. RecordComponentReference(c, __FILE__, __LINE__, ComprefAcquireRecord)
  102. #define DEREFERENCE_COMPONENT(c) \
  103. RecordComponentReference(c, __FILE__, __LINE__, ComprefReleaseRecord)
  104. #define REFERENCE_COMPONENT_OR_RETURN(c,retcode) \
  105. if (!RecordComponentReference(c, __FILE__, __LINE__, ComprefAcquireRecord)) { return retcode; }
  106. #define DEREFERENCE_COMPONENT_AND_RETURN(c,retcode) \
  107. RecordComponentReference(c, __FILE__, __LINE__, ComprefReleaseRecord); \
  108. return retcode
  109. #else
  110. #define REFERENCE_COMPONENT(c) \
  111. AcquireComponentReference(c)
  112. #define DEREFERENCE_COMPONENT(c) \
  113. ReleaseComponentReference(c)
  114. #define REFERENCE_COMPONENT_OR_RETURN(c,retcode) \
  115. if (!AcquireComponentReference(c)) { return retcode; }
  116. #define DEREFERENCE_COMPONENT_AND_RETURN(c,retcode) \
  117. ReleaseComponentReference(c); return retcode
  118. #endif
  119. //
  120. // INLINE ROUTINE IMPLEMENTATIONS
  121. //
  122. __inline
  123. BOOLEAN
  124. AcquireComponentReference(
  125. PCOMPONENT_REFERENCE ComponentReference
  126. )
  127. /*++
  128. Routine Description:
  129. This routine is called to increment the reference-count to a component.
  130. The attempt may fail if the initial reference has been released
  131. and the component is therefore being deleted.
  132. Arguments:
  133. ComponentReference - the component to be referenced
  134. Return Value:
  135. BOOLEAN - TRUE if the component was referenced, FALSE otherwise.
  136. --*/
  137. {
  138. EnterCriticalSection(&ComponentReference->Lock);
  139. if (ComponentReference->Deleted) {
  140. LeaveCriticalSection(&ComponentReference->Lock);
  141. return FALSE;
  142. }
  143. ++ComponentReference->ReferenceCount;
  144. LeaveCriticalSection(&ComponentReference->Lock);
  145. return TRUE;
  146. } // AcquireComponentReference
  147. VOID
  148. __inline
  149. DeleteComponentReference(
  150. PCOMPONENT_REFERENCE ComponentReference
  151. )
  152. /*++
  153. Routine Description:
  154. This routine is called to destroy a component reference.
  155. It may only be called after the last reference to the component is released,
  156. i.e. after 'ReleaseComponentReference' has returned 'TRUE'.
  157. It may also be called from within the component's 'CleanupRoutine'.
  158. Arguments:
  159. ComponentReference - the component to be destroyed
  160. Return Value:
  161. none.
  162. --*/
  163. {
  164. DeleteCriticalSection(&ComponentReference->Lock);
  165. #if COMPREF_TRACKING
  166. HeapFree(GetProcessHeap(), 0, ComponentReference->RecordArray);
  167. #endif
  168. } // DeleteComponentReference
  169. ULONG
  170. __inline
  171. InitializeComponentReference(
  172. PCOMPONENT_REFERENCE ComponentReference,
  173. PCOMPONENT_CLEANUP_ROUTINE CleanupRoutine
  174. )
  175. /*++
  176. Routine Description:
  177. This routine is called to initialize a component reference.
  178. Arguments:
  179. ComponentReference - the component to be initialized
  180. CleanupRoutine - the routine to be called when the component
  181. is to be cleaned up (within the final 'ReleaseComponentReference').
  182. Return Value:
  183. none.
  184. --*/
  185. {
  186. __try {
  187. InitializeCriticalSection(&ComponentReference->Lock);
  188. }
  189. __except (EXCEPTION_EXECUTE_HANDLER) {
  190. return GetExceptionCode();
  191. }
  192. ComponentReference->Deleted = FALSE;
  193. ComponentReference->ReferenceCount = 1;
  194. ComponentReference->CleanupRoutine = CleanupRoutine;
  195. #if COMPREF_TRACKING
  196. ComponentReference->RecordIndex = 0;
  197. ComponentReference->RecordArray =
  198. HeapAlloc(
  199. GetProcessHeap(), 0, sizeof(COMPREF_RECORD) * COMPREF_RECORD_COUNT
  200. );
  201. #endif
  202. return NO_ERROR;
  203. } // InitializeComponentReference
  204. #if COMPREF_TRACKING
  205. __inline
  206. BOOLEAN
  207. RecordComponentReference(
  208. PCOMPONENT_REFERENCE ComponentReference,
  209. PCHAR File,
  210. ULONG Line,
  211. UCHAR Type
  212. )
  213. {
  214. BOOLEAN Success;
  215. ULONG i = InterlockedIncrement(&ComponentReference->RecordIndex);
  216. i %= COMPREF_RECORD_COUNT;
  217. ComponentReference->RecordArray[i].File = File;
  218. ComponentReference->RecordArray[i].Line = (USHORT)Line;
  219. ComponentReference->RecordArray[i].Type = Type;
  220. if (Type == ComprefAcquireRecord) {
  221. Success = AcquireComponentReference(ComponentReference);
  222. } else {
  223. Success = ReleaseComponentReference(ComponentReference);
  224. }
  225. ComponentReference->RecordArray[i].ReferenceCount =
  226. (UCHAR)ComponentReference->ReferenceCount;
  227. return Success;
  228. }
  229. #endif
  230. __inline
  231. BOOLEAN
  232. ReleaseComponentReference(
  233. PCOMPONENT_REFERENCE ComponentReference
  234. )
  235. /*++
  236. Routine Description:
  237. This routine is called to drop a reference to a component.
  238. If the reference drops to zero, cleanup is performed.
  239. Otherwise, cleanup occurs later when the last reference is released.
  240. Arguments:
  241. ComponentReference - the component to be referenced
  242. Return Value:
  243. BOOLEAN - TRUE if the component was cleaned up, FALSE otherwise.
  244. --*/
  245. {
  246. EnterCriticalSection(&ComponentReference->Lock);
  247. if (--ComponentReference->ReferenceCount) {
  248. LeaveCriticalSection(&ComponentReference->Lock);
  249. return FALSE;
  250. }
  251. LeaveCriticalSection(&ComponentReference->Lock);
  252. ComponentReference->CleanupRoutine();
  253. return TRUE;
  254. } // ReleaseComponentReference
  255. __inline
  256. BOOLEAN
  257. ReleaseInitialComponentReference(
  258. PCOMPONENT_REFERENCE ComponentReference
  259. )
  260. /*++
  261. Routine Description:
  262. This routine is called to drop the initial reference to a component,
  263. and mark the component as deleted.
  264. If the reference drops to zero, cleanup is performed right away.
  265. Arguments:
  266. ComponentReference - the component to be referenced
  267. Return Value:
  268. BOOLEAN - TRUE if the component was cleaned up, FALSE otherwise.
  269. --*/
  270. {
  271. EnterCriticalSection(&ComponentReference->Lock);
  272. if (ComponentReference->Deleted) {
  273. LeaveCriticalSection(&ComponentReference->Lock);
  274. return TRUE;
  275. }
  276. ComponentReference->Deleted = TRUE;
  277. if (--ComponentReference->ReferenceCount) {
  278. LeaveCriticalSection(&ComponentReference->Lock);
  279. return FALSE;
  280. }
  281. LeaveCriticalSection(&ComponentReference->Lock);
  282. ComponentReference->CleanupRoutine();
  283. return TRUE;
  284. } // ReleaseInitialComponentReference
  285. __inline
  286. VOID
  287. ResetComponentReference(
  288. PCOMPONENT_REFERENCE ComponentReference
  289. )
  290. /*++
  291. Routine Description:
  292. This routine is called to reset a component reference
  293. to an initial state.
  294. Arguments:
  295. ComponentReference - the component to be reset
  296. Return Value:
  297. none.
  298. --*/
  299. {
  300. EnterCriticalSection(&ComponentReference->Lock);
  301. ComponentReference->ReferenceCount = 1;
  302. ComponentReference->Deleted = FALSE;
  303. #if COMPREF_TRACKING
  304. ComponentReference->RecordIndex = 0;
  305. ZeroMemory(
  306. ComponentReference->RecordArray,
  307. sizeof(COMPREF_RECORD) * COMPREF_RECORD_COUNT
  308. );
  309. #endif
  310. LeaveCriticalSection(&ComponentReference->Lock);
  311. } // ReleaseComponentReference
  312. #endif // _NATHLP_COMPREF_H_