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.

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