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.

659 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. InitializeCriticalSection(&pcache->cs);
  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. ASSERT(!IsBadCodePtr((PROC)pfnFree));
  139. Cache_EnterCS(pcache);
  140. {
  141. if (pcache->hdpa != NULL)
  142. {
  143. CITEM * pitem;
  144. int idpa;
  145. int cItem;
  146. ASSERT(pcache->hdsa != NULL);
  147. cItem = DPA_GetPtrCount(pcache->hdpa);
  148. for (idpa = 0; idpa < cItem; idpa++)
  149. {
  150. pitem = MyGetPtr(pcache, idpa);
  151. if (!IsBadCodePtr((PROC)pfnFree))
  152. pfnFree(pitem->pvValue, hwndOwner);
  153. // Decrement reference count of atomKey
  154. Atom_Delete(pitem->atomKey);
  155. }
  156. DPA_Destroy(pcache->hdpa);
  157. pcache->hdpa = NULL;
  158. }
  159. if (pcache->hdpaFree != NULL)
  160. {
  161. DPA_Destroy(pcache->hdpaFree);
  162. pcache->hdpaFree = NULL;
  163. }
  164. if (pcache->hdsa != NULL)
  165. {
  166. DSA_Destroy(pcache->hdsa);
  167. pcache->hdsa = NULL;
  168. }
  169. }
  170. Cache_LeaveCS(pcache);
  171. }
  172. /*----------------------------------------------------------
  173. Purpose: Deletes the cache's critical section.
  174. Returns: --
  175. Cond: --
  176. */
  177. void PUBLIC Cache_DeleteCS(
  178. CACHE * pcache)
  179. {
  180. // The cache should not be in use now (ie, it should be bogus)
  181. ASSERT(Cache_Bogus(pcache));
  182. if (Cache_Bogus(pcache))
  183. {
  184. DeleteCriticalSection(&pcache->cs);
  185. }
  186. }
  187. /*----------------------------------------------------------
  188. Purpose: Add an item to the cache list.
  189. Returns: TRUE on success
  190. Cond: If this fails, pvValue is not automatically freed
  191. */
  192. BOOL PUBLIC Cache_AddItem(
  193. CACHE * pcache,
  194. int atomKey,
  195. LPVOID pvValue)
  196. {
  197. BOOL bRet = FALSE;
  198. CITEM * pitem = NULL;
  199. int cItem;
  200. int cFree;
  201. ASSERT(pcache);
  202. Cache_EnterCS(pcache);
  203. {
  204. VALIDATE_ATOM(atomKey);
  205. if (!Cache_Bogus(pcache))
  206. {
  207. int iItem;
  208. // Add a new entry to the cache. The cache has no set size limitation.
  209. //
  210. cFree = DPA_GetPtrCount(pcache->hdpaFree);
  211. if (cFree > 0)
  212. {
  213. // Use a free entry
  214. //
  215. cFree--;
  216. iItem = PtrToUlong(DPA_DeletePtr(pcache->hdpaFree, cFree));
  217. pitem = DSA_GetItemPtr(pcache->hdsa, iItem);
  218. }
  219. else
  220. {
  221. CITEM itemDummy;
  222. // Allocate a new entry
  223. //
  224. cItem = DSA_GetItemCount(pcache->hdsa);
  225. if ((iItem = DSA_InsertItem(pcache->hdsa, cItem+1, &itemDummy)) != -1)
  226. pitem = DSA_GetItemPtr(pcache->hdsa, iItem);
  227. }
  228. // Fill in the info
  229. //
  230. if (pitem)
  231. {
  232. pitem->ucRef = 0;
  233. pitem->pvValue = pvValue;
  234. pitem->atomKey = atomKey;
  235. DEBUG_CODE( pitem->pszKey = Atom_GetName(atomKey); )
  236. // Now increment the reference count on this atomKey so it doesn't
  237. // get deleted from beneath us!
  238. Atom_AddRef(atomKey);
  239. // Add the new entry to the ptr list and sort
  240. //
  241. cItem = DPA_GetPtrCount(pcache->hdpa);
  242. if (DPA_InsertPtr(pcache->hdpa, cItem+1, IntToPtr(iItem)) == -1)
  243. goto Add_Fail;
  244. DPA_Sort(pcache->hdpa, Cache_CompareIndexes, (LPARAM)pcache->hdsa);
  245. // Reset the FindFirst/FindNext in case this gets called in the
  246. // middle of an enumeration.
  247. //
  248. pcache->atomPrev = ATOM_ERR;
  249. bRet = TRUE;
  250. }
  251. Add_Fail:
  252. if (!bRet)
  253. {
  254. // Add the entry to the free list and fail. If even this
  255. // fails, we simply lose some slight efficiency, but this is
  256. // not a memory leak.
  257. //
  258. DPA_InsertPtr(pcache->hdpaFree, cFree+1, IntToPtr(iItem));
  259. }
  260. }
  261. }
  262. Cache_LeaveCS(pcache);
  263. return bRet;
  264. }
  265. /*----------------------------------------------------------
  266. Purpose: Delete an item from the cache.
  267. If the reference count is 0, we do nothing.
  268. This also frees the actual value as well, using the
  269. pfnFreeValue function.
  270. Returns: The reference count. If 0, then we deleted it from cache.
  271. Cond: N.b. Decrements the reference count.
  272. */
  273. int PUBLIC Cache_DeleteItem(
  274. CACHE * pcache,
  275. int atomKey,
  276. BOOL bNuke, // TRUE to ignore reference count
  277. HWND hwndOwner,
  278. PFNFREEVALUE pfnFree)
  279. {
  280. int nRet = 0;
  281. CITEM item;
  282. CITEM * pitem;
  283. int idpa;
  284. int cFree;
  285. ASSERT(pcache);
  286. ASSERT(!IsBadCodePtr((PROC)pfnFree));
  287. Cache_EnterCS(pcache);
  288. {
  289. if (!Cache_Bogus(pcache))
  290. {
  291. item.atomKey = atomKey;
  292. idpa = DPA_Search(pcache->hdpa, &item, 0, Cache_Compare, (LPARAM)pcache->hdsa,
  293. DPAS_SORTED);
  294. if (idpa != -1)
  295. {
  296. VALIDATE_ATOM(atomKey);
  297. pitem = MyGetPtr(pcache, idpa);
  298. if (!bNuke && pitem->ucRef-- > 0)
  299. {
  300. nRet = pitem->ucRef+1;
  301. }
  302. else
  303. {
  304. int iItem;
  305. DPA_DeletePtr(pcache->hdpa, idpa);
  306. // Free old pointer
  307. if (!IsBadCodePtr((PROC)pfnFree))
  308. pfnFree(pitem->pvValue, hwndOwner);
  309. Atom_Delete(pitem->atomKey);
  310. DEBUG_CODE( pitem->atomKey = -1; )
  311. DEBUG_CODE( pitem->pszKey = NULL; )
  312. DEBUG_CODE( pitem->pvValue = NULL; )
  313. DEBUG_CODE( pitem->ucRef = 0; )
  314. // Reset the FindFirst/FindNext in case this gets
  315. // called in the middle of an enumeration.
  316. //
  317. pcache->atomPrev = ATOM_ERR;
  318. // Add ptr to the free list. If this fails, we simply lose
  319. // some efficiency in reusing this portion of the cache.
  320. // This is not a memory leak.
  321. //
  322. cFree = DPA_GetPtrCount(pcache->hdpaFree);
  323. iItem = DSA_GetPtrIndex(pcache->hdsa, pitem, sizeof(CITEM));
  324. DPA_InsertPtr(pcache->hdpaFree, cFree+1, IntToPtr(iItem));
  325. }
  326. }
  327. }
  328. }
  329. Cache_LeaveCS(pcache);
  330. return nRet;
  331. }
  332. /*----------------------------------------------------------
  333. Purpose: Replace the contents of the value in the cache list.
  334. If a value does not exist for the given key, return FALSE.
  335. Returns: TRUE if success
  336. Cond: --
  337. */
  338. BOOL PUBLIC Cache_ReplaceItem(
  339. CACHE * pcache,
  340. int atomKey,
  341. LPVOID pvBuf,
  342. int cbBuf)
  343. {
  344. BOOL bRet = FALSE;
  345. CITEM item;
  346. CITEM * pitem;
  347. int idpa;
  348. ASSERT(pcache);
  349. Cache_EnterCS(pcache);
  350. {
  351. if (!Cache_Bogus(pcache))
  352. {
  353. // Search for an existing cache entry
  354. //
  355. item.atomKey = atomKey;
  356. idpa = DPA_Search(pcache->hdpa, &item, 0, Cache_Compare, (LPARAM)pcache->hdsa,
  357. DPAS_SORTED);
  358. if (idpa != -1)
  359. {
  360. // Found a value for this key. Replace the contents.
  361. //
  362. pitem = MyGetPtr(pcache, idpa);
  363. ASSERT(pitem);
  364. BltByte(pvBuf, pitem->pvValue, cbBuf);
  365. bRet = TRUE;
  366. // No need to sort because key hasn't changed.
  367. }
  368. }
  369. }
  370. Cache_LeaveCS(pcache);
  371. return bRet;
  372. }
  373. /*----------------------------------------------------------
  374. Purpose: Get the value of the given key and return a ptr to it
  375. Returns: Ptr to actual entry
  376. Cond: Reference count is incremented
  377. */
  378. LPVOID PUBLIC Cache_GetPtr(
  379. CACHE * pcache,
  380. int atomKey)
  381. {
  382. LPVOID pvRet = NULL;
  383. CITEM item;
  384. CITEM * pitem;
  385. int idpa;
  386. ASSERT(pcache);
  387. Cache_EnterCS(pcache);
  388. {
  389. if (!Cache_Bogus(pcache))
  390. {
  391. item.atomKey = atomKey;
  392. idpa = DPA_Search(pcache->hdpa, &item, 0, Cache_Compare, (LPARAM)pcache->hdsa,
  393. DPAS_SORTED);
  394. if (idpa != -1)
  395. {
  396. pitem = MyGetPtr(pcache, idpa);
  397. ASSERT(pitem);
  398. pitem->ucRef++;
  399. pvRet = pitem->pvValue;
  400. }
  401. }
  402. }
  403. Cache_LeaveCS(pcache);
  404. return pvRet;
  405. }
  406. #ifdef DEBUG
  407. /*----------------------------------------------------------
  408. Purpose: Get the current reference count
  409. Returns: Ptr to actual entry
  410. Cond: Used for debugging
  411. */
  412. UINT PUBLIC Cache_GetRefCount(
  413. CACHE * pcache,
  414. int atomKey)
  415. {
  416. UINT ucRef = (UINT)-1;
  417. CITEM item;
  418. CITEM * pitem;
  419. int idpa;
  420. ASSERT(pcache);
  421. Cache_EnterCS(pcache);
  422. {
  423. if (!Cache_Bogus(pcache))
  424. {
  425. item.atomKey = atomKey;
  426. idpa = DPA_Search(pcache->hdpa, &item, 0, Cache_Compare, (LPARAM)pcache->hdsa,
  427. DPAS_SORTED);
  428. if (idpa != -1)
  429. {
  430. pitem = MyGetPtr(pcache, idpa);
  431. ASSERT(pitem);
  432. ucRef = pitem->ucRef;
  433. }
  434. }
  435. }
  436. Cache_LeaveCS(pcache);
  437. return ucRef;
  438. }
  439. #endif
  440. /*----------------------------------------------------------
  441. Purpose: Get the value of the given key and return a copy of it
  442. in the supplied buffer
  443. Returns: Copy of value in buffer
  444. TRUE if found, FALSE if not
  445. Cond: --
  446. */
  447. BOOL PUBLIC Cache_GetItem(
  448. CACHE * pcache,
  449. int atomKey,
  450. LPVOID pvBuf,
  451. int cbBuf)
  452. {
  453. BOOL bRet = FALSE;
  454. CITEM item;
  455. CITEM * pitem;
  456. int idpa;
  457. ASSERT(pcache);
  458. Cache_EnterCS(pcache);
  459. {
  460. if (!Cache_Bogus(pcache))
  461. {
  462. item.atomKey = atomKey;
  463. idpa = DPA_Search(pcache->hdpa, &item, 0, Cache_Compare, (LPARAM)pcache->hdsa,
  464. DPAS_SORTED);
  465. if (idpa != -1)
  466. {
  467. pitem = MyGetPtr(pcache, idpa);
  468. ASSERT(pitem);
  469. BltByte(pvBuf, pitem->pvValue, cbBuf);
  470. bRet = TRUE;
  471. }
  472. }
  473. }
  474. Cache_LeaveCS(pcache);
  475. return bRet;
  476. }
  477. /*----------------------------------------------------------
  478. Purpose: Get the first key in the cache.
  479. Returns: Atom
  480. ATOM_ERR if cache is empty
  481. Cond: --
  482. */
  483. int PUBLIC Cache_FindFirstKey(
  484. CACHE * pcache)
  485. {
  486. int atomRet = ATOM_ERR;
  487. CITEM * pitem;
  488. ASSERT(pcache);
  489. Cache_EnterCS(pcache);
  490. {
  491. if (!Cache_Bogus(pcache))
  492. {
  493. int i;
  494. pcache->iPrev = 0;
  495. if (DPA_GetPtrCount(pcache->hdpa) > 0)
  496. {
  497. i = PtrToUlong(DPA_FastGetPtr(pcache->hdpa, 0));
  498. pitem = DSA_GetItemPtr(pcache->hdsa, i);
  499. pcache->atomPrev = pitem->atomKey;
  500. atomRet = pitem->atomKey;
  501. VALIDATE_ATOM(atomRet);
  502. }
  503. }
  504. }
  505. Cache_LeaveCS(pcache);
  506. return atomRet;
  507. }
  508. /*----------------------------------------------------------
  509. Purpose: Get the next key in the cache.
  510. Returns: Atom
  511. ATOM_ERR if we're at the end of the cache
  512. Cond: --
  513. */
  514. int PUBLIC Cache_FindNextKey(
  515. CACHE * pcache,
  516. int atomPrev)
  517. {
  518. int atomRet = ATOM_ERR;
  519. CITEM * pitem;
  520. ASSERT(pcache);
  521. Cache_EnterCS(pcache);
  522. {
  523. if (!Cache_Bogus(pcache))
  524. {
  525. if (atomPrev != ATOM_ERR)
  526. {
  527. int i;
  528. if (atomPrev != pcache->atomPrev)
  529. {
  530. CITEM item;
  531. // Search for atomPrev or next one nearest to it.
  532. //
  533. item.atomKey = atomPrev;
  534. pcache->iPrev = DPA_Search(pcache->hdpa, &item, 0, Cache_Compare,
  535. (LPARAM)pcache->hdsa, DPAS_SORTED | DPAS_INSERTBEFORE);
  536. }
  537. else
  538. pcache->iPrev++;
  539. if (DPA_GetPtrCount(pcache->hdpa) > pcache->iPrev)
  540. {
  541. i = PtrToUlong(DPA_FastGetPtr(pcache->hdpa, pcache->iPrev));
  542. pitem = DSA_GetItemPtr(pcache->hdsa, i);
  543. pcache->atomPrev = pitem->atomKey;
  544. atomRet = pitem->atomKey;
  545. VALIDATE_ATOM(atomRet);
  546. }
  547. }
  548. }
  549. }
  550. Cache_LeaveCS(pcache);
  551. return atomRet;
  552. }