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.

383 lines
7.1 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. refcnt.c
  5. Abstract:
  6. This module exports Reference Counting support functions. By
  7. including a Reference Count Control Block (REF_CNT) in a
  8. dynamic type, and using this API, a Reference scheme can be
  9. implemented for that type.
  10. Author:
  11. Edward Buchwalter (v-edbuc) 14-Aug-1996
  12. Revision History:
  13. Shreedhar Madhavapeddi (ShreeM) 16-April-1999
  14. Adapted for NT and GPC by ShreeM\MBert.
  15. --*/
  16. //
  17. // Include Files
  18. //
  19. #include "gpcpre.h"
  20. #define EXPAND_TAG(t) ((CHAR *)(&Tag))[0],((CHAR *)(&Tag))[1],((CHAR *)(&Tag))[2],((CHAR *)(&Tag))[3]
  21. VOID
  22. ReferenceInit
  23. (
  24. IN PREF_CNT pRefCnt,
  25. PVOID InstanceHandle,
  26. VOID (*DeleteHandler)( PVOID )
  27. )
  28. /*++
  29. Routine Description:
  30. ReferenceInit initializes and adds one reference to the
  31. supplied Reference Control Block. If provided, an instance
  32. handle and delete handler are saved for use by the ReferenceRemove
  33. function when all references to the instance are removed.
  34. Arguments:
  35. pRefCnt - pointer to uninitialized Reference Control Block
  36. InstanceHandle - handle to the managed instance.
  37. DeleteHandler - pointer to delete function, NULL is OK.
  38. Return Value:
  39. The function's value is VOID.
  40. --*/
  41. {
  42. TRACE(REFCOUNT, pRefCnt, InstanceHandle, "ReferenceInit( 0x%x, 0x%x )\n");
  43. ASSERT( pRefCnt );
  44. // Set the reference to 1 and save the instance
  45. // handle and the delete handler.
  46. pRefCnt->Count = 0;
  47. pRefCnt->Instance = InstanceHandle;
  48. pRefCnt->DeleteHandler = DeleteHandler;
  49. #if DBG
  50. pRefCnt->Sig = REF_SIG;
  51. RtlZeroMemory(pRefCnt->Tags, sizeof(REF_TAG) * TAG_CNT);
  52. pRefCnt->Tags[0].Tag = 'LTOT';
  53. CTEInitLock(&pRefCnt->Lock);
  54. #endif
  55. }
  56. VOID
  57. ReferenceAdd
  58. (
  59. IN PREF_CNT pRefCnt
  60. )
  61. /*++
  62. Routine Description:
  63. Arguments:
  64. Return Value:
  65. --*/
  66. {
  67. ASSERT( pRefCnt );
  68. InterlockedIncrement(&pRefCnt->Count);
  69. TRACE(REFCOUNT, pRefCnt->Count, 0, "R+%d\n");
  70. }
  71. VOID
  72. ReferenceAddCount
  73. (
  74. IN PREF_CNT pRefCnt,
  75. IN UINT Count
  76. )
  77. /*++
  78. Routine Description:
  79. Arguments:
  80. Return Value:
  81. --*/
  82. {
  83. ASSERT( pRefCnt->Count > 0 );
  84. CTEInterlockedExchangeAdd(&pRefCnt->Count, Count);
  85. }
  86. PVOID
  87. ReferenceRemove
  88. (
  89. IN PREF_CNT pRefCnt
  90. )
  91. /*++
  92. Routine Description:
  93. Arguments:
  94. Return Value:
  95. --*/
  96. {
  97. ASSERT( pRefCnt );
  98. // Trap remove reference on a zero count
  99. ASSERT( pRefCnt->Count > 0 );
  100. // If the decremented count is non zero return the instance handle
  101. if (InterlockedDecrement(&pRefCnt->Count) > 0 )
  102. {
  103. TRACE(REFCOUNT, pRefCnt->Count, 0, "R-%d\n");
  104. TRACE(REFCOUNT, pRefCnt->Count, 0, "ReferenceRemove:remaining: %d\n");
  105. return( pRefCnt->Instance );
  106. }
  107. // Delete this instance if a delete handler is available
  108. if( pRefCnt->DeleteHandler )
  109. {
  110. TRACE(REFCOUNT, 0, 0, "Executing DeleteHandler\n");
  111. (pRefCnt->DeleteHandler)( pRefCnt->Instance );
  112. }
  113. // Indicate no active references to this instance
  114. return( NULL );
  115. }
  116. //
  117. // API Test Support
  118. //
  119. #if DBG
  120. VOID
  121. ReferenceApiTest( VOID )
  122. {
  123. REF_CNT RefCnt;
  124. TRACE(REFCOUNT, 0, 0, "\nReferenceApiTest\n");
  125. TRACE(REFCOUNT, 0, 0, "\nTest #1: NULL delete handler\n");
  126. ReferenceInit( &RefCnt, &RefCnt, NULL );
  127. ReferenceAdd( &RefCnt );
  128. ReferenceAdd( &RefCnt );
  129. ReferenceAdd( &RefCnt );
  130. while( ReferenceRemove( &RefCnt ) )
  131. {
  132. ;
  133. }
  134. TRACE( REFCOUNT, 0, 0, "\nTest #2: Delete Handler - TBD\n");
  135. }
  136. VOID
  137. ReferenceAddDbg(PREF_CNT pRefCnt, ULONG Tag)
  138. {
  139. int i;
  140. CTELockHandle hLock;
  141. int TotalPerArray = 0;
  142. ASSERT(pRefCnt->Sig == REF_SIG);
  143. TRACE(REFCOUNT, EXPAND_TAG(Tag), pRefCnt->Count, ("GPC REF: add (%c%c%c%c) %d\n"));
  144. CTEGetLock(&pRefCnt->Lock, &hLock);
  145. for (i = 1; i < TAG_CNT; i++)
  146. {
  147. if (pRefCnt->Tags[i].Tag == 0 || pRefCnt->Tags[i].Tag == Tag)
  148. {
  149. pRefCnt->Tags[i].Tag = Tag;
  150. InterlockedIncrement(&pRefCnt->Tags[i].Count);
  151. break;
  152. }
  153. }
  154. ASSERT(i < TAG_CNT);
  155. InterlockedIncrement(&pRefCnt->Tags[0].Count);
  156. InterlockedIncrement(&pRefCnt->Count);
  157. ASSERT(pRefCnt->Tags[0].Count == pRefCnt->Count);
  158. // sanity check
  159. /*
  160. for (i = 1; i < TAG_CNT; i++)
  161. {
  162. if (pRefCnt->Tags[i].Tag != 0)
  163. {
  164. TotalPerArray += pRefCnt->Tags[i].Count;
  165. continue;
  166. }
  167. }
  168. ASSERT(TotalPerArray == pRefCnt->Tags[0].Count);
  169. if (TotalPerArray != pRefCnt->Tags[0].Count)
  170. {
  171. DbgBreakPoint();
  172. }
  173. */
  174. CTEFreeLock(&pRefCnt->Lock, hLock);
  175. }
  176. VOID
  177. ReferenceRemoveDbg(PREF_CNT pRefCnt, ULONG Tag)
  178. {
  179. int i;
  180. CTELockHandle hLock;
  181. int TotalPerArray = 0;
  182. BOOLEAN FoundIt = FALSE;
  183. ASSERT(pRefCnt->Sig == REF_SIG);
  184. TRACE(REFCOUNT, EXPAND_TAG(Tag), pRefCnt->Count, "GPC REF: remove (%c%c%c%c) %d\n");
  185. CTEGetLock(&pRefCnt->Lock, &hLock);
  186. for (i = 1; i < TAG_CNT; i++)
  187. {
  188. if (pRefCnt->Tags[i].Tag == Tag)
  189. {
  190. FoundIt = TRUE;
  191. ASSERT(pRefCnt->Tags[i].Count > 0);
  192. InterlockedDecrement(&pRefCnt->Tags[i].Count);
  193. if (pRefCnt->Tags[i].Count == 0)
  194. pRefCnt->Tags[i].Tag = Tag;
  195. break;
  196. }
  197. }
  198. ASSERT(FoundIt);
  199. ASSERT(pRefCnt->Tags[0].Count > 0);
  200. ASSERT(pRefCnt->Tags[0].Count == pRefCnt->Count);
  201. InterlockedDecrement(&pRefCnt->Tags[0].Count);
  202. if (InterlockedDecrement(&pRefCnt->Count) > 0 )
  203. {
  204. CTEFreeLock(&pRefCnt->Lock, hLock);
  205. }
  206. else if (pRefCnt->DeleteHandler)
  207. {
  208. TRACE(REFCOUNT, 0 , 0, "Executing DeleteHandler\n");
  209. CTEFreeLock(&pRefCnt->Lock, hLock);
  210. (pRefCnt->DeleteHandler)( pRefCnt->Instance );
  211. }
  212. else
  213. {
  214. CTEFreeLock(&pRefCnt->Lock, hLock);
  215. }
  216. /*
  217. // sanity check
  218. for (i = 1; i < TAG_CNT; i++)
  219. {
  220. if (pRefCnt->Tags[i].Tag != 0)
  221. {
  222. TotalPerArray += pRefCnt->Tags[i].Count;
  223. continue;
  224. }
  225. }
  226. ASSERT(TotalPerArray == pRefCnt->Tags[0].Count);
  227. if (TotalPerArray != pRefCnt->Tags[0].Count)
  228. {
  229. DbgPrint(TEXT("Tag %X, RefCnt %X, perArray %d, total %d\n"), Tag, pRefCnt,
  230. TotalPerArray, pRefCnt->Tags[0].Count);
  231. DbgBreakPoint();
  232. }
  233. */
  234. }
  235. VOID
  236. ReferenceCheckForZeroRef(PREF_CNT pRefCnt, ULONG Tag)
  237. {
  238. int i;
  239. CTELockHandle hLock;
  240. int TotalPerArray = 0;
  241. BOOLEAN FoundIt = FALSE;
  242. ASSERT(pRefCnt->Sig == REF_SIG);
  243. CTEGetLock(&pRefCnt->Lock, &hLock);
  244. for (i = 1; i < TAG_CNT; i++)
  245. {
  246. if (pRefCnt->Tags[i].Tag == Tag)
  247. {
  248. FoundIt = TRUE;
  249. ASSERT(pRefCnt->Tags[i].Count == 0);
  250. break;
  251. }
  252. }
  253. ASSERT(FoundIt);
  254. CTEFreeLock(&pRefCnt->Lock, hLock);
  255. }
  256. #endif