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.

658 lines
17 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Copyright (c) Microsoft Corporation 1993-1994
  4. //
  5. // File: cache.c
  6. //
  7. // This files contains code for the common cache lists
  8. //
  9. // History:
  10. // 09-02-93 ScottH Created
  11. // 01-31-94 ScottH Split into separate files
  12. //
  13. //---------------------------------------------------------------------------
  14. ///////////////////////////////////////////////////// INCLUDES
  15. #include "brfprv.h" // common headers
  16. ///////////////////////////////////////////////////// TYPEDEFS
  17. typedef struct tagCITEM
  18. {
  19. int atomKey;
  20. DEBUG_CODE( LPCTSTR pszKey; )
  21. LPVOID pvValue;
  22. UINT ucRef;
  23. } CITEM; // item for generic cache
  24. #define Cache_EnterCS(this) EnterCriticalSection(&(this)->cs)
  25. #define Cache_LeaveCS(this) LeaveCriticalSection(&(this)->cs)
  26. #define CACHE_GROW 8
  27. #define Cache_Bogus(this) (!(this)->hdpa || !(this)->hdpaFree || !(this)->hdsa)
  28. // Given an index into the DPA, get the pointer to the DSA
  29. //
  30. #define MyGetPtr(this, idpa) DSA_GetItemPtr((this)->hdsa, PtrToUlong(DPA_FastGetPtr((this)->hdpa, idpa)))
  31. #define DSA_GetPtrIndex(hdsa, ptr, cbItem) \
  32. ((int)( (DWORD_PTR)(ptr) - (DWORD_PTR)DSA_GetItemPtr(hdsa, 0) ) / (cbItem))
  33. /*----------------------------------------------------------
  34. Purpose: Compare two CRLs by pathname
  35. Returns: -1 if <, 0 if ==, 1 if >
  36. Cond: --
  37. */
  38. int CALLBACK _export Cache_CompareIndexes(
  39. LPVOID lpv1,
  40. LPVOID lpv2,
  41. LPARAM lParam)
  42. {
  43. int i1 = PtrToUlong(lpv1);
  44. int i2 = PtrToUlong(lpv2);
  45. HDSA hdsa = (HDSA)lParam;
  46. CITEM * pitem1 = (CITEM *)DSA_GetItemPtr(hdsa, i1);
  47. CITEM * pitem2 = (CITEM *)DSA_GetItemPtr(hdsa, i2);
  48. if (pitem1->atomKey < pitem2->atomKey)
  49. return -1;
  50. else if (pitem1->atomKey == pitem2->atomKey)
  51. return 0;
  52. else
  53. return 1;
  54. }
  55. /*----------------------------------------------------------
  56. Purpose: Compare two CRLs by pathname
  57. Returns: -1 if <, 0 if ==, 1 if >
  58. Cond: --
  59. */
  60. int CALLBACK _export Cache_Compare(
  61. LPVOID lpv1,
  62. LPVOID lpv2,
  63. LPARAM lParam)
  64. {
  65. // HACK: we know the first param is the address to a struct
  66. // that contains the search criteria. The second is an index
  67. // into the DSA.
  68. //
  69. int i2 = PtrToUlong(lpv2);
  70. HDSA hdsa = (HDSA)lParam;
  71. CITEM * pitem1 = (CITEM *)lpv1;
  72. CITEM * pitem2 = (CITEM *)DSA_GetItemPtr(hdsa, i2);
  73. if (pitem1->atomKey < pitem2->atomKey)
  74. return -1;
  75. else if (pitem1->atomKey == pitem2->atomKey)
  76. return 0;
  77. else
  78. return 1;
  79. }
  80. /*----------------------------------------------------------
  81. Purpose: Initialize the cache structure
  82. Returns: TRUE on success
  83. Cond: --
  84. */
  85. BOOL PUBLIC Cache_Init(
  86. CACHE * pcache)
  87. {
  88. BOOL bRet;
  89. ASSERT(pcache);
  90. Cache_EnterCS(pcache);
  91. {
  92. if ((pcache->hdsa = DSA_Create(sizeof(CITEM), CACHE_GROW)) != NULL)
  93. {
  94. if ((pcache->hdpa = DPA_Create(CACHE_GROW)) == NULL)
  95. {
  96. DSA_Destroy(pcache->hdsa);
  97. pcache->hdsa = NULL;
  98. }
  99. else
  100. {
  101. if ((pcache->hdpaFree = DPA_Create(CACHE_GROW)) == NULL)
  102. {
  103. DPA_Destroy(pcache->hdpa);
  104. DSA_Destroy(pcache->hdsa);
  105. pcache->hdpa = NULL;
  106. pcache->hdsa = NULL;
  107. }
  108. }
  109. }
  110. bRet = pcache->hdsa != NULL;
  111. }
  112. Cache_LeaveCS(pcache);
  113. return bRet;
  114. }
  115. /*----------------------------------------------------------
  116. Purpose: Initializes the cache's critical section.
  117. Returns: --
  118. Cond: --
  119. */
  120. void PUBLIC Cache_InitCS(
  121. CACHE * pcache)
  122. {
  123. ASSERT(pcache);
  124. ZeroInit(pcache, CACHE);
  125. InitializeCriticalSectionAndSpinCount(&pcache->cs, 0);
  126. }
  127. /*----------------------------------------------------------
  128. Purpose: Destroy the cache
  129. Returns: --
  130. Cond: --
  131. */
  132. void PUBLIC Cache_Term(
  133. CACHE * pcache,
  134. HWND hwndOwner,
  135. PFNFREEVALUE pfnFree)
  136. {
  137. ASSERT(pcache);
  138. Cache_EnterCS(pcache);
  139. {
  140. if (pcache->hdpa != NULL)
  141. {
  142. CITEM * pitem;
  143. int idpa;
  144. int cItem;
  145. ASSERT(pcache->hdsa != NULL);
  146. cItem = DPA_GetPtrCount(pcache->hdpa);
  147. for (idpa = 0; idpa < cItem; idpa++)
  148. {
  149. pitem = MyGetPtr(pcache, idpa);
  150. if (pfnFree != NULL)
  151. pfnFree(pitem->pvValue, hwndOwner);
  152. // Decrement reference count of atomKey
  153. Atom_Delete(pitem->atomKey);
  154. }
  155. DPA_Destroy(pcache->hdpa);
  156. pcache->hdpa = NULL;
  157. }
  158. if (pcache->hdpaFree != NULL)
  159. {
  160. DPA_Destroy(pcache->hdpaFree);
  161. pcache->hdpaFree = NULL;
  162. }
  163. if (pcache->hdsa != NULL)
  164. {
  165. DSA_Destroy(pcache->hdsa);
  166. pcache->hdsa = NULL;
  167. }
  168. }
  169. Cache_LeaveCS(pcache);
  170. }
  171. /*----------------------------------------------------------
  172. Purpose: Deletes the cache's critical section.
  173. Returns: --
  174. Cond: --
  175. */
  176. void PUBLIC Cache_DeleteCS(
  177. CACHE * pcache)
  178. {
  179. // The cache should not be in use now (ie, it should be bogus)
  180. ASSERT(Cache_Bogus(pcache));
  181. if (Cache_Bogus(pcache))
  182. {
  183. DeleteCriticalSection(&pcache->cs);
  184. }
  185. }
  186. /*----------------------------------------------------------
  187. Purpose: Add an item to the cache list.
  188. Returns: TRUE on success
  189. Cond: If this fails, pvValue is not automatically freed
  190. */
  191. BOOL PUBLIC Cache_AddItem(
  192. CACHE * pcache,
  193. int atomKey,
  194. LPVOID pvValue)
  195. {
  196. BOOL bRet = FALSE;
  197. CITEM * pitem = NULL;
  198. int cItem;
  199. int cFree;
  200. ASSERT(pcache);
  201. Cache_EnterCS(pcache);
  202. {
  203. VALIDATE_ATOM(atomKey);
  204. if (!Cache_Bogus(pcache))
  205. {
  206. int iItem;
  207. // Add a new entry to the cache. The cache has no set size limitation.
  208. //
  209. cFree = DPA_GetPtrCount(pcache->hdpaFree);
  210. if (cFree > 0)
  211. {
  212. // Use a free entry
  213. //
  214. cFree--;
  215. iItem = PtrToUlong(DPA_DeletePtr(pcache->hdpaFree, cFree));
  216. pitem = DSA_GetItemPtr(pcache->hdsa, iItem);
  217. }
  218. else
  219. {
  220. CITEM itemDummy;
  221. // Allocate a new entry
  222. //
  223. cItem = DSA_GetItemCount(pcache->hdsa);
  224. if ((iItem = DSA_InsertItem(pcache->hdsa, cItem+1, &itemDummy)) != -1)
  225. pitem = DSA_GetItemPtr(pcache->hdsa, iItem);
  226. }
  227. // Fill in the info
  228. //
  229. if (pitem)
  230. {
  231. pitem->ucRef = 0;
  232. pitem->pvValue = pvValue;
  233. pitem->atomKey = atomKey;
  234. DEBUG_CODE( pitem->pszKey = Atom_GetName(atomKey); )
  235. // Now increment the reference count on this atomKey so it doesn't
  236. // get deleted from beneath us!
  237. Atom_AddRef(atomKey);
  238. // Add the new entry to the ptr list and sort
  239. //
  240. cItem = DPA_GetPtrCount(pcache->hdpa);
  241. if (DPA_InsertPtr(pcache->hdpa, cItem+1, IntToPtr(iItem)) == -1)
  242. goto Add_Fail;
  243. DPA_Sort(pcache->hdpa, Cache_CompareIndexes, (LPARAM)pcache->hdsa);
  244. // Reset the FindFirst/FindNext in case this gets called in the
  245. // middle of an enumeration.
  246. //
  247. pcache->atomPrev = ATOM_ERR;
  248. bRet = TRUE;
  249. }
  250. Add_Fail:
  251. if (!bRet)
  252. {
  253. // Add the entry to the free list and fail. If even this
  254. // fails, we simply lose some slight efficiency, but this is
  255. // not a memory leak.
  256. //
  257. DPA_InsertPtr(pcache->hdpaFree, cFree+1, IntToPtr(iItem));
  258. }
  259. }
  260. }
  261. Cache_LeaveCS(pcache);
  262. return bRet;
  263. }
  264. /*----------------------------------------------------------
  265. Purpose: Delete an item from the cache.
  266. If the reference count is 0, we do nothing.
  267. This also frees the actual value as well, using the
  268. pfnFreeValue function.
  269. Returns: The reference count. If 0, then we deleted it from cache.
  270. Cond: N.b. Decrements the reference count.
  271. */
  272. int PUBLIC Cache_DeleteItem(
  273. CACHE * pcache,
  274. int atomKey,
  275. BOOL bNuke, // TRUE to ignore reference count
  276. HWND hwndOwner,
  277. PFNFREEVALUE pfnFree)
  278. {
  279. int nRet = 0;
  280. CITEM item;
  281. CITEM * pitem;
  282. int idpa;
  283. int cFree;
  284. ASSERT(pcache);
  285. Cache_EnterCS(pcache);
  286. {
  287. if (!Cache_Bogus(pcache))
  288. {
  289. item.atomKey = atomKey;
  290. idpa = DPA_Search(pcache->hdpa, &item, 0, Cache_Compare, (LPARAM)pcache->hdsa,
  291. DPAS_SORTED);
  292. if (idpa != -1)
  293. {
  294. VALIDATE_ATOM(atomKey);
  295. pitem = MyGetPtr(pcache, idpa);
  296. if (!bNuke && pitem->ucRef-- > 0)
  297. {
  298. nRet = pitem->ucRef+1;
  299. }
  300. else
  301. {
  302. int iItem;
  303. DPA_DeletePtr(pcache->hdpa, idpa);
  304. // Free old pointer
  305. if (pfnFree != NULL)
  306. pfnFree(pitem->pvValue, hwndOwner);
  307. Atom_Delete(pitem->atomKey);
  308. DEBUG_CODE( pitem->atomKey = -1; )
  309. DEBUG_CODE( pitem->pszKey = NULL; )
  310. DEBUG_CODE( pitem->pvValue = NULL; )
  311. DEBUG_CODE( pitem->ucRef = 0; )
  312. // Reset the FindFirst/FindNext in case this gets
  313. // called in the middle of an enumeration.
  314. //
  315. pcache->atomPrev = ATOM_ERR;
  316. // Add ptr to the free list. If this fails, we simply lose
  317. // some efficiency in reusing this portion of the cache.
  318. // This is not a memory leak.
  319. //
  320. cFree = DPA_GetPtrCount(pcache->hdpaFree);
  321. iItem = DSA_GetPtrIndex(pcache->hdsa, pitem, sizeof(CITEM));
  322. DPA_InsertPtr(pcache->hdpaFree, cFree+1, IntToPtr(iItem));
  323. }
  324. }
  325. }
  326. }
  327. Cache_LeaveCS(pcache);
  328. return nRet;
  329. }
  330. /*----------------------------------------------------------
  331. Purpose: Replace the contents of the value in the cache list.
  332. If a value does not exist for the given key, return FALSE.
  333. Returns: TRUE if success
  334. Cond: --
  335. */
  336. BOOL PUBLIC Cache_ReplaceItem(
  337. CACHE * pcache,
  338. int atomKey,
  339. LPVOID pvBuf,
  340. int cbBuf)
  341. {
  342. BOOL bRet = FALSE;
  343. CITEM item;
  344. CITEM * pitem;
  345. int idpa;
  346. ASSERT(pcache);
  347. Cache_EnterCS(pcache);
  348. {
  349. if (!Cache_Bogus(pcache))
  350. {
  351. // Search for an existing cache entry
  352. //
  353. item.atomKey = atomKey;
  354. idpa = DPA_Search(pcache->hdpa, &item, 0, Cache_Compare, (LPARAM)pcache->hdsa,
  355. DPAS_SORTED);
  356. if (idpa != -1)
  357. {
  358. // Found a value for this key. Replace the contents.
  359. //
  360. pitem = MyGetPtr(pcache, idpa);
  361. ASSERT(pitem);
  362. BltByte(pvBuf, pitem->pvValue, cbBuf);
  363. bRet = TRUE;
  364. // No need to sort because key hasn't changed.
  365. }
  366. }
  367. }
  368. Cache_LeaveCS(pcache);
  369. return bRet;
  370. }
  371. /*----------------------------------------------------------
  372. Purpose: Get the value of the given key and return a ptr to it
  373. Returns: Ptr to actual entry
  374. Cond: Reference count is incremented
  375. */
  376. LPVOID PUBLIC Cache_GetPtr(
  377. CACHE * pcache,
  378. int atomKey)
  379. {
  380. LPVOID pvRet = NULL;
  381. CITEM item;
  382. CITEM * pitem;
  383. int idpa;
  384. ASSERT(pcache);
  385. Cache_EnterCS(pcache);
  386. {
  387. if (!Cache_Bogus(pcache))
  388. {
  389. item.atomKey = atomKey;
  390. idpa = DPA_Search(pcache->hdpa, &item, 0, Cache_Compare, (LPARAM)pcache->hdsa,
  391. DPAS_SORTED);
  392. if (idpa != -1)
  393. {
  394. pitem = MyGetPtr(pcache, idpa);
  395. ASSERT(pitem);
  396. pitem->ucRef++;
  397. pvRet = pitem->pvValue;
  398. }
  399. }
  400. }
  401. Cache_LeaveCS(pcache);
  402. return pvRet;
  403. }
  404. #ifdef DEBUG
  405. /*----------------------------------------------------------
  406. Purpose: Get the current reference count
  407. Returns: Ptr to actual entry
  408. Cond: Used for debugging
  409. */
  410. UINT PUBLIC Cache_GetRefCount(
  411. CACHE * pcache,
  412. int atomKey)
  413. {
  414. UINT ucRef = (UINT)-1;
  415. CITEM item;
  416. CITEM * pitem;
  417. int idpa;
  418. ASSERT(pcache);
  419. Cache_EnterCS(pcache);
  420. {
  421. if (!Cache_Bogus(pcache))
  422. {
  423. item.atomKey = atomKey;
  424. idpa = DPA_Search(pcache->hdpa, &item, 0, Cache_Compare, (LPARAM)pcache->hdsa,
  425. DPAS_SORTED);
  426. if (idpa != -1)
  427. {
  428. pitem = MyGetPtr(pcache, idpa);
  429. ASSERT(pitem);
  430. ucRef = pitem->ucRef;
  431. }
  432. }
  433. }
  434. Cache_LeaveCS(pcache);
  435. return ucRef;
  436. }
  437. #endif
  438. /*----------------------------------------------------------
  439. Purpose: Get the value of the given key and return a copy of it
  440. in the supplied buffer
  441. Returns: Copy of value in buffer
  442. TRUE if found, FALSE if not
  443. Cond: --
  444. */
  445. BOOL PUBLIC Cache_GetItem(
  446. CACHE * pcache,
  447. int atomKey,
  448. LPVOID pvBuf,
  449. int cbBuf)
  450. {
  451. BOOL bRet = FALSE;
  452. CITEM item;
  453. CITEM * pitem;
  454. int idpa;
  455. ASSERT(pcache);
  456. Cache_EnterCS(pcache);
  457. {
  458. if (!Cache_Bogus(pcache))
  459. {
  460. item.atomKey = atomKey;
  461. idpa = DPA_Search(pcache->hdpa, &item, 0, Cache_Compare, (LPARAM)pcache->hdsa,
  462. DPAS_SORTED);
  463. if (idpa != -1)
  464. {
  465. pitem = MyGetPtr(pcache, idpa);
  466. ASSERT(pitem);
  467. BltByte(pvBuf, pitem->pvValue, cbBuf);
  468. bRet = TRUE;
  469. }
  470. }
  471. }
  472. Cache_LeaveCS(pcache);
  473. return bRet;
  474. }
  475. /*----------------------------------------------------------
  476. Purpose: Get the first key in the cache.
  477. Returns: Atom
  478. ATOM_ERR if cache is empty
  479. Cond: --
  480. */
  481. int PUBLIC Cache_FindFirstKey(
  482. CACHE * pcache)
  483. {
  484. int atomRet = ATOM_ERR;
  485. CITEM * pitem;
  486. ASSERT(pcache);
  487. Cache_EnterCS(pcache);
  488. {
  489. if (!Cache_Bogus(pcache))
  490. {
  491. int i;
  492. pcache->iPrev = 0;
  493. if (DPA_GetPtrCount(pcache->hdpa) > 0)
  494. {
  495. i = PtrToUlong(DPA_FastGetPtr(pcache->hdpa, 0));
  496. pitem = DSA_GetItemPtr(pcache->hdsa, i);
  497. pcache->atomPrev = pitem->atomKey;
  498. atomRet = pitem->atomKey;
  499. VALIDATE_ATOM(atomRet);
  500. }
  501. }
  502. }
  503. Cache_LeaveCS(pcache);
  504. return atomRet;
  505. }
  506. /*----------------------------------------------------------
  507. Purpose: Get the next key in the cache.
  508. Returns: Atom
  509. ATOM_ERR if we're at the end of the cache
  510. Cond: --
  511. */
  512. int PUBLIC Cache_FindNextKey(
  513. CACHE * pcache,
  514. int atomPrev)
  515. {
  516. int atomRet = ATOM_ERR;
  517. CITEM * pitem;
  518. ASSERT(pcache);
  519. Cache_EnterCS(pcache);
  520. {
  521. if (!Cache_Bogus(pcache))
  522. {
  523. if (atomPrev != ATOM_ERR)
  524. {
  525. int i;
  526. if (atomPrev != pcache->atomPrev)
  527. {
  528. CITEM item;
  529. // Search for atomPrev or next one nearest to it.
  530. //
  531. item.atomKey = atomPrev;
  532. pcache->iPrev = DPA_Search(pcache->hdpa, &item, 0, Cache_Compare,
  533. (LPARAM)pcache->hdsa, DPAS_SORTED | DPAS_INSERTBEFORE);
  534. }
  535. else
  536. pcache->iPrev++;
  537. if (DPA_GetPtrCount(pcache->hdpa) > pcache->iPrev)
  538. {
  539. i = PtrToUlong(DPA_FastGetPtr(pcache->hdpa, pcache->iPrev));
  540. pitem = DSA_GetItemPtr(pcache->hdsa, i);
  541. pcache->atomPrev = pitem->atomKey;
  542. atomRet = pitem->atomKey;
  543. VALIDATE_ATOM(atomRet);
  544. }
  545. }
  546. }
  547. }
  548. Cache_LeaveCS(pcache);
  549. return atomRet;
  550. }