Leaked source code of windows server 2003
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.

413 lines
8.0 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. Shreedhar Madhavapeddi (ShreeM) 15-March-1999
  12. Revision History:
  13. --*/
  14. //
  15. // Include Files
  16. //
  17. #include "precomp.h"
  18. #define EXPAND_TAG(t) ((CHAR *)(&Tag))[0],((CHAR *)(&Tag))[1],((CHAR *)(&Tag))[2],((CHAR *)(&Tag))[3]
  19. VOID
  20. ReferenceInit
  21. (
  22. IN PREF_CNT pRefCnt,
  23. PVOID InstanceHandle,
  24. VOID (*DeleteHandler)( PVOID )
  25. )
  26. /*++
  27. Routine Description:
  28. ReferenceInit initializes and adds one reference to the
  29. supplied Reference Control Block. If provided, an instance
  30. handle and delete handler are saved for use by the ReferenceRemove
  31. function when all references to the instance are removed.
  32. Arguments:
  33. pRefCnt - pointer to uninitialized Reference Control Block
  34. InstanceHandle - handle to the managed instance.
  35. DeleteHandler - pointer to delete function, NULL is OK.
  36. Return Value:
  37. The function's value is VOID.
  38. --*/
  39. {
  40. IF_DEBUG(REFCOUNTX) {
  41. WSPRINT(( "ReferenceInit( 0x%x, 0x%x, 0x%x )\n",
  42. pRefCnt, InstanceHandle, DeleteHandler ));
  43. }
  44. ASSERT( pRefCnt );
  45. // Set the reference to 1 and save the instance
  46. // handle and the delete handler.
  47. pRefCnt->Count = 0;
  48. pRefCnt->Instance = InstanceHandle;
  49. pRefCnt->DeleteHandler = DeleteHandler;
  50. #if DBG
  51. pRefCnt->Sig = REF_SIG;
  52. RtlZeroMemory(pRefCnt->Tags, sizeof(REF_TAG) * TAG_CNT);
  53. pRefCnt->Tags[0].Tag = 'LTOT';
  54. RefInitLock(pRefCnt->Lock);
  55. #endif
  56. }
  57. VOID
  58. ReferenceAdd
  59. (
  60. IN PREF_CNT pRefCnt
  61. )
  62. /*++
  63. Routine Description:
  64. Arguments:
  65. Return Value:
  66. --*/
  67. {
  68. ASSERT( pRefCnt );
  69. InterlockedIncrement(&pRefCnt->Count);
  70. IF_DEBUG(REFCOUNTX) {
  71. WSPRINT(( "R+%d\n", pRefCnt->Count ));
  72. }
  73. }
  74. VOID
  75. ReferenceAddCount
  76. (
  77. IN PREF_CNT pRefCnt,
  78. IN UINT Count
  79. )
  80. /*++
  81. Routine Description:
  82. Arguments:
  83. Return Value:
  84. --*/
  85. {
  86. ASSERT( pRefCnt->Count > 0 );
  87. InterlockedExchangeAdd(&pRefCnt->Count, Count);
  88. }
  89. PVOID
  90. ReferenceRemove
  91. (
  92. IN PREF_CNT pRefCnt
  93. )
  94. /*++
  95. Routine Description:
  96. Arguments:
  97. Return Value:
  98. --*/
  99. {
  100. UINT Count;
  101. UINT NoReference;
  102. UINT i;
  103. PVOID pInstance;
  104. ASSERT( pRefCnt );
  105. // Trap remove reference on a zero count
  106. ASSERT(pRefCnt->Count>0);
  107. pInstance = pRefCnt->Instance;
  108. //ASSERT( pRefCnt->Count > 0 );
  109. // If the decremented count is non zero return the instance handle
  110. if (InterlockedDecrement(&pRefCnt->Count) > 0 )
  111. {
  112. IF_DEBUG(REFCOUNTX) {
  113. WSPRINT(( "R-%d\n", pRefCnt->Count ));
  114. WSPRINT(( "ReferenceRemove:remaining: %d\n", pRefCnt->Count ));
  115. }
  116. #if DBG
  117. RefFreeLock(pRefCnt->Lock);
  118. #endif
  119. return(pInstance);
  120. }
  121. // Delete this instance if a delete handler is available
  122. if( pRefCnt->DeleteHandler )
  123. {
  124. #if DBG
  125. // sanity check
  126. for (i = 1; i < TAG_CNT; i++)
  127. {
  128. if ((pRefCnt->Tags[i].Tag != 0) && (pRefCnt->Tags[i].Count != 0))
  129. {
  130. IF_DEBUG(ERRORS) {
  131. WSPRINT(("Allors!! There is a NON-zero ref and we are deleting...\n"));
  132. }
  133. DEBUGBREAK();
  134. }
  135. }
  136. IF_DEBUG(REFCOUNTX) {
  137. WSPRINT(( "Executing DeleteHandler for %X\n", pRefCnt->Instance ));
  138. }
  139. //
  140. // All the Dereference* code takes the locks, so lets take it here.
  141. // Also, Take the global lock before releasing the ref lock.
  142. //
  143. // Time to delete the ref lock too.
  144. RefFreeLock(pRefCnt->Lock);
  145. #endif
  146. GetLock(pGlobals->Lock);
  147. #if DBG
  148. RefDeleteLock(pRefCnt->Lock);
  149. #endif
  150. (pRefCnt->DeleteHandler)( pRefCnt->Instance );
  151. FreeLock(pGlobals->Lock);
  152. }
  153. // Indicate no active references to this instance
  154. return( NULL );
  155. }
  156. //
  157. // API Test Support
  158. //
  159. #if DBG
  160. VOID
  161. ReferenceApiTest( VOID )
  162. {
  163. REF_CNT RefCnt;
  164. IF_DEBUG(REFCOUNTX) {
  165. WSPRINT(
  166. ( "\nReferenceApiTest\n" ));
  167. WSPRINT(( "\nTest #1: NULL delete handler\n" ));
  168. }
  169. ReferenceInit( &RefCnt, &RefCnt, NULL );
  170. ReferenceAdd( &RefCnt );
  171. ReferenceAdd( &RefCnt );
  172. ReferenceAdd( &RefCnt );
  173. while( ReferenceRemove( &RefCnt ) )
  174. {
  175. ;
  176. }
  177. IF_DEBUG(REFCOUNTX) {
  178. WSPRINT(( "\nTest #2: Delete Handler - TBD\n" ));
  179. }
  180. }
  181. VOID
  182. ReferenceAddDbg(PREF_CNT pRefCnt, ULONG Tag)
  183. {
  184. int i;
  185. int TotalPerArray = 0;
  186. RefGetLock(pRefCnt->Lock);
  187. //ASSERT(pRefCnt->Sig == REF_SIG);
  188. if (pRefCnt->Sig != REF_SIG) {
  189. DEBUGBREAK();
  190. }
  191. IF_DEBUG(REFCOUNTX) {
  192. WSPRINT(("TCREF: add %X (%c%c%c%c) %d\n",
  193. pRefCnt, EXPAND_TAG(Tag), pRefCnt->Count));
  194. }
  195. for (i = 1; i < TAG_CNT; i++)
  196. {
  197. if (pRefCnt->Tags[i].Tag == 0 || pRefCnt->Tags[i].Tag == Tag)
  198. {
  199. pRefCnt->Tags[i].Tag = Tag;
  200. InterlockedIncrement(&pRefCnt->Tags[i].Count);
  201. break;
  202. }
  203. }
  204. //ASSERT(i < TAG_CNT);
  205. if (i >= TAG_CNT) {
  206. DEBUGBREAK();
  207. }
  208. ReferenceAdd(pRefCnt);
  209. InterlockedIncrement(&pRefCnt->Tags[0].Count);
  210. // sanity check
  211. for (i = 1; i < TAG_CNT; i++)
  212. {
  213. if (pRefCnt->Tags[i].Tag != 0)
  214. {
  215. TotalPerArray += pRefCnt->Tags[i].Count;
  216. continue;
  217. }
  218. }
  219. ASSERT(TotalPerArray == pRefCnt->Tags[0].Count);
  220. if (TotalPerArray != pRefCnt->Tags[0].Count)
  221. {
  222. DbgBreakPoint();
  223. }
  224. RefFreeLock(pRefCnt->Lock);
  225. }
  226. VOID
  227. ReferenceRemoveDbg(PREF_CNT pRefCnt, ULONG Tag)
  228. {
  229. int i;
  230. int TotalPerArray = 0;
  231. BOOLEAN FoundIt = FALSE;
  232. RefGetLock(pRefCnt->Lock);
  233. if (pRefCnt->Sig != REF_SIG) {
  234. DEBUGBREAK();
  235. }
  236. //ASSERT(pRefCnt->Sig == REF_SIG);
  237. IF_DEBUG(REFCOUNTX) {
  238. WSPRINT(("TCREF: remove %X (%c%c%c%c) %d\n",
  239. pRefCnt, EXPAND_TAG(Tag), pRefCnt->Count));
  240. }
  241. for (i = 1; i < TAG_CNT; i++)
  242. {
  243. if (pRefCnt->Tags[i].Tag == Tag)
  244. {
  245. FoundIt = TRUE;
  246. if(pRefCnt->Tags[i].Count <= 0) {
  247. DEBUGBREAK();
  248. }
  249. //ASSERT(pRefCnt->Tags[i].Count > 0);
  250. InterlockedDecrement(&pRefCnt->Tags[i].Count);
  251. if (pRefCnt->Tags[i].Count == 0)
  252. pRefCnt->Tags[i].Tag = Tag;
  253. break;
  254. }
  255. }
  256. if (!FoundIt) {
  257. DEBUGBREAK();
  258. }
  259. ASSERT(FoundIt);
  260. ASSERT(pRefCnt->Tags[0].Count > 0);
  261. InterlockedDecrement(&pRefCnt->Tags[0].Count);
  262. // sanity check
  263. for (i = 1; i < TAG_CNT; i++)
  264. {
  265. if (pRefCnt->Tags[i].Tag != 0)
  266. {
  267. TotalPerArray += pRefCnt->Tags[i].Count;
  268. continue;
  269. }
  270. }
  271. ASSERT(TotalPerArray == pRefCnt->Tags[0].Count);
  272. if (TotalPerArray != pRefCnt->Tags[0].Count)
  273. {
  274. DbgPrint("Tag %X, RefCnt %X, perArray %d, total %d\n", Tag, pRefCnt,
  275. TotalPerArray, pRefCnt->Tags[0].Count);
  276. DbgBreakPoint();
  277. }
  278. ReferenceRemove(pRefCnt);
  279. }
  280. #endif