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.

700 lines
21 KiB

  1. //-----------------------------------------------------------------------------
  2. //
  3. //
  4. // File: bitmap.cpp
  5. //
  6. // Description: Contains code for implementation of bitmap functions
  7. //
  8. // Owner: mikeswa
  9. //
  10. // Copyright (C) 1997 Microsoft Corporation
  11. //
  12. //-----------------------------------------------------------------------------
  13. #include "aqprecmp.h"
  14. #include "bitmap.h"
  15. #define BITS_PER_DWORD 32
  16. //Set up static masks for quick parsing
  17. const DWORD s_rgdwMasks[8] =
  18. {
  19. 0xF0000000,
  20. 0x0F000000,
  21. 0x00F00000,
  22. 0x000F0000,
  23. 0x0000F000,
  24. 0x00000F00,
  25. 0x000000F0,
  26. 0x0000000F
  27. };
  28. //Used for fast conversion from index to bitmap
  29. const DWORD s_rgdwIndexMasks[32] =
  30. {
  31. 0x80000000, 0x40000000, 0x20000000, 0x10000000,
  32. 0x08000000, 0x04000000, 0x02000000, 0x01000000,
  33. 0x00800000, 0x00400000, 0x00200000, 0x00100000,
  34. 0x00080000, 0x00040000, 0x00020000, 0x00010000,
  35. 0x00008000, 0x00004000, 0x00002000, 0x00001000,
  36. 0x00000800, 0x00000400, 0x00000200, 0x00000100,
  37. 0x00000080, 0x00000040, 0x00000020, 0x00000010,
  38. 0x00000008, 0x00000004, 0x00000002, 0x00000001
  39. };
  40. //Used to check for zero'd bitmaps with cBits does not fill up a DWORD
  41. const DWORD s_rgdwZeroMasks[32] =
  42. {
  43. 0x80000000, 0xC0000000, 0xE0000000, 0xF0000000,
  44. 0xF8000000, 0xFC000000, 0xFE000000, 0xFF000000,
  45. 0xFF800000, 0xFFC00000, 0xFFE00000, 0xFFF00000,
  46. 0xFFF80000, 0xFFFC0000, 0xFFFE0000, 0xFFFF0000,
  47. 0xFFFF8000, 0xFFFFC000, 0xFFFFE000, 0xFFFFF000,
  48. 0xFFFFF800, 0xFFFFFC00, 0xFFFFFE00, 0xFFFFFF00,
  49. 0xFFFFFF80, 0xFFFFFFC0, 0xFFFFFFE0, 0xFFFFFFF0,
  50. 0xFFFFFFF8, 0xFFFFFFFC, 0xFFFFFFFE, 0xFFFFFFFF,
  51. };
  52. //---[ fInterlockedDWORDCompareExchange ]--------------------------------------
  53. //
  54. //
  55. // Description:
  56. // Provide an inline function to handle the type-checking, casts,
  57. // and comparison in DWORD chunks.
  58. // Parameters:
  59. // pdwDest Destination to update
  60. // dwNewValue Value to update with
  61. // dwCompare Old value to check against
  62. // Returns:
  63. // TRUE if update succeeded
  64. //
  65. //-----------------------------------------------------------------------------
  66. inline BOOL fInterlockedDWORDCompareExchange(LPDWORD pdwDest, DWORD dwNewValue,
  67. DWORD dwCompare)
  68. {
  69. return(
  70. ((DWORD) InterlockedCompareExchange((PLONG)pdwDest,
  71. (LONG) dwNewValue, (LONG) dwCompare))
  72. == dwCompare);
  73. }
  74. //---[ CMsgBitMap::new ]----------------------------------------------------------
  75. //
  76. //
  77. // Description:
  78. // Overide the new operator to allow for the variable size of this class.
  79. // A good optimization would be to use the C-pool type stuff for the
  80. // 90% case of 1 domain, and allocate the rest on the fly
  81. // Parameters:
  82. // cBits the number of bits this message is being delivered to.
  83. // Returns:
  84. // -
  85. //-----------------------------------------------------------------------------
  86. void * CMsgBitMap::operator new(size_t stIgnored, unsigned int cBits)
  87. {
  88. void *pvThis = NULL;
  89. int i = 0;
  90. _ASSERT(size(cBits) >= sizeof(DWORD));
  91. pvThis = pvMalloc(size(cBits));
  92. return (pvThis);
  93. }
  94. //---[ CMsgBitMap::CMsgBitMap ]------------------------------------------------
  95. //
  96. //
  97. // Description:
  98. // Class constructor. Will zero memory for a bitmap that is not part of
  99. // a message reference
  100. // Parameters:
  101. // cBits - The number of bits in the bitmap
  102. // Returns:
  103. //
  104. //
  105. //-----------------------------------------------------------------------------
  106. CMsgBitMap::CMsgBitMap(DWORD cBits)
  107. {
  108. DWORD cDWORDs = cGetNumDWORDS(cBits);
  109. ZeroMemory(m_rgdwBitMap, cDWORDs*sizeof(DWORD));
  110. }
  111. //---[ CMsgBitMap::FAllClear ]-------------------------------------------------
  112. //
  113. //
  114. // Description:
  115. // Checks to see of all relevant bits (1st cBits) are 0
  116. // Parameters:
  117. // cBits the number of bits in the bitmap
  118. // Returns:
  119. // TRUE if all bits are 0, FALSE otherwise
  120. //
  121. //-----------------------------------------------------------------------------
  122. BOOL CMsgBitMap::FAllClear(DWORD cBits)
  123. {
  124. TraceFunctEnterEx((LPARAM) this, "CMsgBitMap::FAllClear");
  125. BOOL fResult = TRUE;
  126. DWORD cDWORDs = cGetNumDWORDS(cBits) ;
  127. //verify all DWORD's by checking if 0
  128. for (DWORD i = 0; i < cDWORDs; i++)
  129. {
  130. if (m_rgdwBitMap[i] != 0x00000000)
  131. {
  132. fResult = FALSE;
  133. break;
  134. }
  135. }
  136. TraceFunctLeave();
  137. return fResult;
  138. }
  139. //---[ CMsgBitMap::FAllSet ]---------------------------------------------------
  140. //
  141. //
  142. // Description:
  143. // Checks to see of all relevant bits (1st cBits) are 1
  144. // Parameters:
  145. // cBits the number of bits in the bitmap
  146. // Returns:
  147. // TRUE if all bits are 1, FALSE otherwise
  148. //
  149. //-----------------------------------------------------------------------------
  150. BOOL CMsgBitMap::FAllSet(DWORD cBits)
  151. {
  152. TraceFunctEnterEx((LPARAM) this, "CMsgBitMap::FAllClear");
  153. BOOL fResult = TRUE;
  154. DWORD cDWORDs = cGetNumDWORDS(cBits+1) -1; //check all but last DWORD
  155. DWORD iZeroIndex = cBits & 0x0000001F;
  156. //verify all DWORD's by checking if 0
  157. for (DWORD i = 0; i < cDWORDs; i++)
  158. {
  159. if (m_rgdwBitMap[i] != 0xFFFFFFFF)
  160. {
  161. fResult = FALSE;
  162. goto Exit; //if we hit the iZeroIndex clause, we might assert
  163. }
  164. }
  165. _ASSERT(i || iZeroIndex || !fResult); //We must check at least 1 DWORD
  166. if (iZeroIndex)
  167. {
  168. iZeroIndex--; //we cBits is a count... our index starts at 0.
  169. //last DWORD should be a subset of the ZeroMask
  170. _ASSERT(s_rgdwZeroMasks[iZeroIndex] ==
  171. (s_rgdwZeroMasks[iZeroIndex] | m_rgdwBitMap[cDWORDs]));
  172. if (s_rgdwZeroMasks[iZeroIndex] != m_rgdwBitMap[cDWORDs])
  173. fResult = FALSE;
  174. }
  175. Exit:
  176. TraceFunctLeave();
  177. return fResult;
  178. }
  179. //---[ CMsgBitMap::HrMarkBits ]------------------------------------------------
  180. //
  181. //
  182. // Description:
  183. // Marks the bits (as 0 or 1) that corresponds to the given indexes
  184. //
  185. // Parameters:
  186. // IN DWORD cBits
  187. // IN DWORD cIndexes # of indexes in array
  188. // IN DWORD rgiBits SORTED array of indexes of bits to mark
  189. // IN BOOL fSet TRUE => set to 1, 0 otherwise
  190. // Returns:
  191. // S_OK on success
  192. //-----------------------------------------------------------------------------
  193. HRESULT CMsgBitMap::HrMarkBits(IN DWORD cBits, IN DWORD cIndexes,
  194. IN DWORD *rgiBits, IN BOOL fSet)
  195. {
  196. TraceFunctEnterEx((LPARAM) this, "CMsgBitMap::HrMarkBits");
  197. HRESULT hr = S_OK;
  198. DWORD cDWORDs = cGetNumDWORDS(cBits);
  199. DWORD dwTmp;
  200. DWORD dwIndex = 0x00000000;
  201. DWORD i;
  202. DWORD iCurrentIndex = 0; //current index in rgiBits
  203. DWORD iCurrentLimit = BITS_PER_DWORD -1; //current limit of 32 bit range for values of rgiBits
  204. _ASSERT(cIndexes);
  205. _ASSERT(cIndexes <= cBits);
  206. for (i = 0; i < cDWORDs; i++)
  207. {
  208. dwIndex = 0x00000000;
  209. while ((iCurrentIndex < cIndexes) &&
  210. (rgiBits[iCurrentIndex] <= iCurrentLimit))
  211. {
  212. _ASSERT(rgiBits[iCurrentIndex] < cBits);
  213. dwIndex |= s_rgdwIndexMasks[(rgiBits[iCurrentIndex] % BITS_PER_DWORD)];
  214. iCurrentIndex++;
  215. }
  216. if (dwIndex != 0x00000000) //don't perform costly interlocked op if we don't need to
  217. {
  218. if (fSet) //set bit
  219. {
  220. SpinTry1:
  221. dwTmp = m_rgdwBitMap[i];
  222. if (!fInterlockedDWORDCompareExchange(&(m_rgdwBitMap[i]), (dwIndex | dwTmp), dwTmp))
  223. goto SpinTry1;
  224. }
  225. else //clear bit
  226. {
  227. SpinTry2:
  228. dwTmp = m_rgdwBitMap[i];
  229. if (!fInterlockedDWORDCompareExchange(&(m_rgdwBitMap[i]), ((~dwIndex) & dwTmp), dwTmp))
  230. goto SpinTry2;
  231. }
  232. }
  233. if (iCurrentIndex >= cIndexes)
  234. break; //don't do more work than we have to
  235. iCurrentLimit += BITS_PER_DWORD;
  236. }
  237. TraceFunctLeave();
  238. return hr;
  239. }
  240. //---[ CMsgBitMap::HrGetIndexes ]----------------------------------------------
  241. //
  242. //
  243. // Description:
  244. // Generates an array of indexes represented by the bitmap
  245. // Parameters:
  246. // IN DWORD cBits
  247. // OUT DWORD *pcIndexes //# of indexes returned
  248. // OUT DWORD **prgdwIndexes //array of indexes
  249. // Returns:
  250. // S_OK on success
  251. // E_OUTOFMEMORY if memory allocation fails
  252. //-----------------------------------------------------------------------------
  253. HRESULT CMsgBitMap::HrGetIndexes(IN DWORD cBits, OUT DWORD *pcIndexes,
  254. OUT DWORD **prgdwIndexes)
  255. {
  256. TraceFunctEnterEx((LPARAM) this, "CMsgBitMap::HrGetIndexes");
  257. HRESULT hr = S_OK;
  258. DWORD *pdwIndexes = NULL;
  259. DWORD dwIndex = 0;
  260. DWORD dwIndexOffset = 0;
  261. DWORD cDWORDs = cGetNumDWORDS(cBits);
  262. DWORD cdwAllocated = 0;
  263. DWORD cCurrentIndexes = 0;
  264. DWORD i = 0;
  265. DWORD *pdwTmp = NULL;
  266. //$$REVIEW: How do we balance CPU usage vs memory usage here? We know the
  267. // max size of the output array is cBits DWORDS, but in actuality it can
  268. // little as 1 DWORD. Prognosticating the actual size accurately would
  269. // require scanning the bitmap multiple times.
  270. //
  271. // Easy(studpid) way: Count bits, allocate array, recount and add indexes to array
  272. //
  273. // Idea #1: Allocate in chunks of 32 DWORDS, Realloc if we run out Should
  274. // not have to worry about reallocing for 90% of the cases.
  275. //
  276. // Idea #2: Add some stats to this class, and run some stress tests in debug
  277. // mode, and develop a heuristic that limits reallocs and such (ie alloc
  278. // lg(cBits) to start with).
  279. //
  280. // Idea #3: Continue with Idea #2, but add self-tuning stats
  281. Assert(pcIndexes);
  282. Assert(prgdwIndexes);
  283. pdwIndexes = (DWORD *) pvMalloc(BITS_PER_DWORD*sizeof(DWORD));
  284. if (pdwIndexes == NULL)
  285. {
  286. hr = E_OUTOFMEMORY;
  287. goto Exit;
  288. }
  289. cdwAllocated = BITS_PER_DWORD;
  290. cCurrentIndexes = 0;
  291. for (i = 0; i < cDWORDs; i++)
  292. {
  293. dwIndex = 0;
  294. while (dwIndex < BITS_PER_DWORD)
  295. {
  296. //can use mask to check if possible
  297. if ((!(dwIndex & 0x00000003)) && //if %4 == 0
  298. !(s_rgdwMasks[dwIndex/4] & m_rgdwBitMap[i]))
  299. {
  300. dwIndex += 4; //Can skip ahead 4
  301. }
  302. else
  303. {
  304. if (s_rgdwIndexMasks[dwIndex] & m_rgdwBitMap[i]) //Found it!
  305. {
  306. //Write index and check if re-allocation is needed
  307. if (cCurrentIndexes >= cdwAllocated)
  308. {
  309. cdwAllocated += BITS_PER_DWORD;
  310. pdwTmp = (DWORD *) pvRealloc(pdwIndexes, cdwAllocated*sizeof(DWORD));
  311. if (NULL == pdwTmp)
  312. {
  313. hr = E_OUTOFMEMORY;
  314. goto Exit;
  315. }
  316. pdwIndexes = pdwTmp;
  317. }
  318. *(pdwIndexes + cCurrentIndexes) = (dwIndex + dwIndexOffset);
  319. cCurrentIndexes++;
  320. }
  321. dwIndex++;
  322. }
  323. }
  324. //Use dwIndexOffset to break down index generation into 32-bit chunks
  325. dwIndexOffset += BITS_PER_DWORD;
  326. }
  327. *prgdwIndexes = pdwIndexes; //set OUT value
  328. *pcIndexes = cCurrentIndexes;
  329. Exit:
  330. if (FAILED(hr))
  331. {
  332. *prgdwIndexes = NULL;
  333. *pcIndexes = 0;
  334. FreePv(pdwIndexes);
  335. }
  336. TraceFunctLeave();
  337. return hr;
  338. }
  339. //---[ CMsgBitMap::HrGroupOr ]-------------------------------------------------
  340. //
  341. //
  342. // Description:
  343. // Sets thir bitmap to the logical OR of the given list of bitmaps. This
  344. // is used to prepare a bitmap that represents the domains being delivered
  345. // over a list (or destmsg queue). Current bitmap is NOT cleared prior to
  346. // this operation.
  347. // Parameters:
  348. // IN DWORD cBits number of bits in bitmap
  349. // IN DWORD cBitMaps number of bitmaps in array
  350. // IN CMsgBitMap **rgpBitMaps array of bitmaps to OR
  351. // Returns:
  352. // S_OK on success
  353. //
  354. // Note: This is NOT thread safe.. it's intended use is only for tmp bitmaps
  355. //-----------------------------------------------------------------------------
  356. HRESULT CMsgBitMap::HrGroupOr(IN DWORD cBits, IN DWORD cBitMaps,
  357. IN CMsgBitMap **rgpBitMaps)
  358. {
  359. TraceFunctEnterEx((LPARAM) this, "CMsgBitMap::HrGroupOr");
  360. HRESULT hr = S_OK;
  361. DWORD cDWORDs = cGetNumDWORDS(cBits);
  362. DWORD i, j;
  363. for (i = 0; i < cDWORDs; i++)
  364. {
  365. for (j = 0; j < cBitMaps; j++)
  366. {
  367. Assert(rgpBitMaps[j]);
  368. m_rgdwBitMap[i] |= rgpBitMaps[j]->m_rgdwBitMap[i];
  369. }
  370. }
  371. TraceFunctLeave();
  372. return hr;
  373. }
  374. //---[ CMsgBitMap::HrFilter ]--------------------------------------------------
  375. //
  376. //
  377. // Description:
  378. // Filters the current bitmap by setting only the bits that are SET in
  379. // in and UNSET in the given bitmap..
  380. // Performs a logical AND with the complement of the given bitmap
  381. // Parameters:
  382. // IN DWORD cBits # of bits in bitmap
  383. // IN CMsgBitMap *pmbmap bitmap to filter against
  384. // Returns:
  385. // S_OK on success
  386. //
  387. // Truth Table:
  388. // A => this bitmap
  389. // B => pmbmap
  390. //
  391. // A B | A'B'
  392. // ===========
  393. // 0 0 | 0 0
  394. // 0 1 | 0 1
  395. // 1 0 | 1 0
  396. // 1 1 | 0 1
  397. //
  398. // Note: This is NOT thread safe.. it's intended use is only for tmp bitmaps
  399. //-----------------------------------------------------------------------------
  400. HRESULT CMsgBitMap::HrFilter(IN DWORD cBits, IN CMsgBitMap *pmbmap)
  401. {
  402. TraceFunctEnterEx((LPARAM) this, "CMsgBitMap::HrFilter");
  403. HRESULT hr = S_OK;
  404. DWORD cDWORDs = cGetNumDWORDS(cBits);
  405. Assert(pmbmap);
  406. for (DWORD i = 0; i < cDWORDs; i++)
  407. {
  408. m_rgdwBitMap[i] &= ~(pmbmap->m_rgdwBitMap[i]);
  409. }
  410. TraceFunctLeave();
  411. return hr;
  412. }
  413. //---[ CMsgBitMap::HrFilterSet ]-----------------------------------------------
  414. //
  415. //
  416. // Description:
  417. // Filters the current bitmap and sets those bits to 1 in the given
  418. // bitmap. Unlike HrFilter, this modifies the given bitmap and does so
  419. // in a thread-safe manner.
  420. // Parameters:
  421. // IN DWORD cBits # of bits in bitmap
  422. // IN CMsgBitMap *pmbmap bitmap to filter against
  423. // Returns:
  424. // S_OK on success
  425. //
  426. // Truth Table:
  427. // A => this bitmap
  428. // B => pmbmap
  429. //
  430. // A B | A'B'
  431. // ===========
  432. // 0 0 | 0 0
  433. // 0 1 | 0 1
  434. // 1 0 | 1 1
  435. // 1 1 | 0 1
  436. //
  437. //-----------------------------------------------------------------------------
  438. HRESULT CMsgBitMap::HrFilterSet(IN DWORD cBits, IN CMsgBitMap *pmbmap)
  439. {
  440. TraceFunctEnterEx((LPARAM) this, "CMsgBitMap::HrFilterSet");
  441. Assert(pmbmap);
  442. HRESULT hr = S_OK;
  443. DWORD cDWORDs = cGetNumDWORDS(cBits);
  444. DWORD dwSelfNew;
  445. DWORD dwOtherNew;
  446. DWORD dwOtherOld;
  447. DWORD i;
  448. BOOL fDone = FALSE;
  449. for (i = 0; i < cDWORDs; i++)
  450. {
  451. fDone = FALSE;
  452. dwSelfNew = m_rgdwBitMap[i];
  453. while (!fDone)
  454. {
  455. dwOtherNew = pmbmap->m_rgdwBitMap[i];
  456. dwOtherOld = dwOtherNew;
  457. dwSelfNew &= ~dwOtherNew; //filter
  458. dwOtherNew ^= dwSelfNew; //set
  459. if (fInterlockedDWORDCompareExchange(&(pmbmap->m_rgdwBitMap[i]),
  460. dwOtherNew, dwOtherOld))
  461. {
  462. fDone = TRUE;
  463. m_rgdwBitMap[i] = dwSelfNew;
  464. }
  465. }
  466. }
  467. TraceFunctLeave();
  468. return hr;
  469. }
  470. //---[ CMsgBitMap::HrFilterUnset ]-----------------------------------------------
  471. //
  472. //
  473. // Description:
  474. // Uses the current bitmap and sets those bits that are 1 on it to 0 in the
  475. // given bitmap. Unlike HrFilterSet, only the pmbmap is modified.
  476. //
  477. // This also checks that all bits that are 1 in self are also 1 in the
  478. // other... ie that the 1 bits in this are a subset of pmbmap
  479. // Parameters:
  480. // IN DWORD cBits # of bits in bitmap
  481. // IN CMsgBitMap *pmbmap bitmap to filter against
  482. // Returns:
  483. // S_OK on success
  484. //
  485. // Truth Table:
  486. // A => this bitmap
  487. // B => pmbmap
  488. //
  489. // A B | A'B'
  490. // ===========
  491. // 0 0 | 0 0
  492. // 0 1 | 0 1
  493. // 1 0 | x x - undefined (will assert)
  494. // 1 1 | 1 0
  495. //
  496. //-----------------------------------------------------------------------------
  497. HRESULT CMsgBitMap::HrFilterUnset(IN DWORD cBits, IN CMsgBitMap *pmbmap)
  498. {
  499. TraceFunctEnterEx((LPARAM) this, "CMsgBitMap::HrFilterUnset");
  500. Assert(pmbmap);
  501. HRESULT hr = S_OK;
  502. DWORD cDWORDs = cGetNumDWORDS(cBits);
  503. BOOL fDone = FALSE;
  504. DWORD i;
  505. DWORD dwOtherNew;
  506. DWORD dwOtherOld;
  507. for (i = 0; i < cDWORDs; i++)
  508. {
  509. fDone = FALSE;
  510. while (!fDone)
  511. {
  512. dwOtherNew = pmbmap->m_rgdwBitMap[i];
  513. dwOtherOld = dwOtherNew;
  514. if (m_rgdwBitMap[i] & ~dwOtherNew)
  515. {
  516. //this bitmap is NOT a subset of the given bitmap
  517. _ASSERT(0); //caller's mistake
  518. hr = E_FAIL;
  519. goto Exit;
  520. }
  521. dwOtherNew ^= m_rgdwBitMap[i]; //unset
  522. if (fInterlockedDWORDCompareExchange(&(pmbmap->m_rgdwBitMap[i]),
  523. dwOtherNew, dwOtherOld))
  524. {
  525. fDone = TRUE;
  526. }
  527. }
  528. }
  529. Exit:
  530. TraceFunctLeave();
  531. return hr;
  532. }
  533. //---[ CMsgBitMap::FTestAndSet ]-----------------------------------------------
  534. //
  535. //
  536. // Description:
  537. // An Interlocked function to test and set a bit on the this bit map.
  538. // Looks for the bit that is set in the given bitmap, if that bit is also
  539. // 1 in this bitmap, returns FALSE. If that bit is 0, it sets it to 1,
  540. // and returns TRUE.
  541. //
  542. // NOTE: Results are UNDEFINED if there is more than 1 bit set in pmbmap.
  543. // Parameters:
  544. // cBits # of bits in bitmap
  545. // pmbmap Bitmap to check against
  546. // Returns:
  547. // TRUE if the corresponding bit was 0 (and is now set to 1)
  548. // FALSE if the corresponding bit was already1
  549. // History:
  550. // 11/8/98 - MikeSwa Created
  551. //
  552. //-----------------------------------------------------------------------------
  553. BOOL CMsgBitMap::FTestAndSet(IN DWORD cBits, IN CMsgBitMap *pmbmap)
  554. {
  555. BOOL fRet = FALSE;
  556. DWORD cDWORDs = cGetNumDWORDS(cBits);
  557. BOOL fDone = FALSE;
  558. DWORD dwThisNew = 0;
  559. DWORD dwThisOld = 0;
  560. DWORD i = 0;
  561. for (i = 0; i < cDWORDs; i++)
  562. {
  563. if (pmbmap->m_rgdwBitMap[i])
  564. {
  565. //We've hit the bit in the given bitmap
  566. //See if bit is already set
  567. if (pmbmap->m_rgdwBitMap[i] & m_rgdwBitMap[i])
  568. break;
  569. while (!fDone)
  570. {
  571. dwThisOld = m_rgdwBitMap[i];
  572. dwThisNew = dwThisOld | pmbmap->m_rgdwBitMap[i];
  573. //See if another thread has set it
  574. if (dwThisOld & pmbmap->m_rgdwBitMap[i])
  575. break;
  576. //Only 1 bit should be set on given bitmap
  577. _ASSERT((dwThisOld | pmbmap->m_rgdwBitMap[i]) ==
  578. (dwThisOld ^ pmbmap->m_rgdwBitMap[i]));
  579. //Try to set bit
  580. if (fInterlockedDWORDCompareExchange(&(m_rgdwBitMap[i]),
  581. dwThisNew, dwThisOld))
  582. {
  583. fDone = TRUE;
  584. fRet = TRUE;
  585. }
  586. }
  587. break;
  588. }
  589. }
  590. return fRet;
  591. }
  592. //---[ CMsgBitMap::FTest ]-----------------------------------------------------
  593. //
  594. //
  595. // Description:
  596. // Tests this bitmap against a single bit in the given bitmap
  597. // NOTE: Results are UNDEFINED if there is more than 1 bit set in pmbmap.
  598. // Parameters:
  599. // cBits # of bits in bitmap
  600. // pmbmap Bitmap to check against
  601. // Returns:
  602. // TRUE if the corresponding bit is 1
  603. // FALSE if the corresponding bit is 0
  604. // History:
  605. // 11/8/98 - MikeSwa Created
  606. //
  607. //-----------------------------------------------------------------------------
  608. BOOL CMsgBitMap::FTest(IN DWORD cBits, IN CMsgBitMap *pmbmap)
  609. {
  610. BOOL fRet = FALSE;
  611. DWORD cDWORDs = cGetNumDWORDS(cBits);
  612. DWORD i = 0;
  613. for (i = 0; i < cDWORDs; i++)
  614. {
  615. //See if we've hit the bit in the given bitmap
  616. if (pmbmap->m_rgdwBitMap[i])
  617. {
  618. //See if bit is already set
  619. if (pmbmap->m_rgdwBitMap[i] & m_rgdwBitMap[i])
  620. fRet = TRUE;
  621. break;
  622. }
  623. }
  624. return fRet;
  625. }