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
700 lines
21 KiB
//-----------------------------------------------------------------------------
|
|
//
|
|
//
|
|
// File: bitmap.cpp
|
|
//
|
|
// Description: Contains code for implementation of bitmap functions
|
|
//
|
|
// Owner: mikeswa
|
|
//
|
|
// Copyright (C) 1997 Microsoft Corporation
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "aqprecmp.h"
|
|
#include "bitmap.h"
|
|
|
|
#define BITS_PER_DWORD 32
|
|
|
|
//Set up static masks for quick parsing
|
|
const DWORD s_rgdwMasks[8] =
|
|
{
|
|
0xF0000000,
|
|
0x0F000000,
|
|
0x00F00000,
|
|
0x000F0000,
|
|
0x0000F000,
|
|
0x00000F00,
|
|
0x000000F0,
|
|
0x0000000F
|
|
};
|
|
|
|
//Used for fast conversion from index to bitmap
|
|
const DWORD s_rgdwIndexMasks[32] =
|
|
{
|
|
0x80000000, 0x40000000, 0x20000000, 0x10000000,
|
|
0x08000000, 0x04000000, 0x02000000, 0x01000000,
|
|
0x00800000, 0x00400000, 0x00200000, 0x00100000,
|
|
0x00080000, 0x00040000, 0x00020000, 0x00010000,
|
|
0x00008000, 0x00004000, 0x00002000, 0x00001000,
|
|
0x00000800, 0x00000400, 0x00000200, 0x00000100,
|
|
0x00000080, 0x00000040, 0x00000020, 0x00000010,
|
|
0x00000008, 0x00000004, 0x00000002, 0x00000001
|
|
};
|
|
|
|
//Used to check for zero'd bitmaps with cBits does not fill up a DWORD
|
|
const DWORD s_rgdwZeroMasks[32] =
|
|
{
|
|
0x80000000, 0xC0000000, 0xE0000000, 0xF0000000,
|
|
0xF8000000, 0xFC000000, 0xFE000000, 0xFF000000,
|
|
0xFF800000, 0xFFC00000, 0xFFE00000, 0xFFF00000,
|
|
0xFFF80000, 0xFFFC0000, 0xFFFE0000, 0xFFFF0000,
|
|
0xFFFF8000, 0xFFFFC000, 0xFFFFE000, 0xFFFFF000,
|
|
0xFFFFF800, 0xFFFFFC00, 0xFFFFFE00, 0xFFFFFF00,
|
|
0xFFFFFF80, 0xFFFFFFC0, 0xFFFFFFE0, 0xFFFFFFF0,
|
|
0xFFFFFFF8, 0xFFFFFFFC, 0xFFFFFFFE, 0xFFFFFFFF,
|
|
};
|
|
|
|
//---[ fInterlockedDWORDCompareExchange ]--------------------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// Provide an inline function to handle the type-checking, casts,
|
|
// and comparison in DWORD chunks.
|
|
// Parameters:
|
|
// pdwDest Destination to update
|
|
// dwNewValue Value to update with
|
|
// dwCompare Old value to check against
|
|
// Returns:
|
|
// TRUE if update succeeded
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
inline BOOL fInterlockedDWORDCompareExchange(LPDWORD pdwDest, DWORD dwNewValue,
|
|
DWORD dwCompare)
|
|
{
|
|
return(
|
|
((DWORD) InterlockedCompareExchange((PLONG)pdwDest,
|
|
(LONG) dwNewValue, (LONG) dwCompare))
|
|
== dwCompare);
|
|
}
|
|
|
|
//---[ CMsgBitMap::new ]----------------------------------------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// Overide the new operator to allow for the variable size of this class.
|
|
// A good optimization would be to use the C-pool type stuff for the
|
|
// 90% case of 1 domain, and allocate the rest on the fly
|
|
// Parameters:
|
|
// cBits the number of bits this message is being delivered to.
|
|
// Returns:
|
|
// -
|
|
//-----------------------------------------------------------------------------
|
|
void * CMsgBitMap::operator new(size_t stIgnored, unsigned int cBits)
|
|
{
|
|
void *pvThis = NULL;
|
|
int i = 0;
|
|
|
|
_ASSERT(size(cBits) >= sizeof(DWORD));
|
|
pvThis = pvMalloc(size(cBits));
|
|
|
|
return (pvThis);
|
|
}
|
|
|
|
//---[ CMsgBitMap::CMsgBitMap ]------------------------------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// Class constructor. Will zero memory for a bitmap that is not part of
|
|
// a message reference
|
|
// Parameters:
|
|
// cBits - The number of bits in the bitmap
|
|
// Returns:
|
|
//
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
CMsgBitMap::CMsgBitMap(DWORD cBits)
|
|
{
|
|
DWORD cDWORDs = cGetNumDWORDS(cBits);
|
|
ZeroMemory(m_rgdwBitMap, cDWORDs*sizeof(DWORD));
|
|
}
|
|
|
|
//---[ CMsgBitMap::FAllClear ]-------------------------------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// Checks to see of all relevant bits (1st cBits) are 0
|
|
// Parameters:
|
|
// cBits the number of bits in the bitmap
|
|
// Returns:
|
|
// TRUE if all bits are 0, FALSE otherwise
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL CMsgBitMap::FAllClear(DWORD cBits)
|
|
{
|
|
TraceFunctEnterEx((LPARAM) this, "CMsgBitMap::FAllClear");
|
|
BOOL fResult = TRUE;
|
|
DWORD cDWORDs = cGetNumDWORDS(cBits) ;
|
|
|
|
//verify all DWORD's by checking if 0
|
|
for (DWORD i = 0; i < cDWORDs; i++)
|
|
{
|
|
if (m_rgdwBitMap[i] != 0x00000000)
|
|
{
|
|
fResult = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
TraceFunctLeave();
|
|
return fResult;
|
|
}
|
|
|
|
//---[ CMsgBitMap::FAllSet ]---------------------------------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// Checks to see of all relevant bits (1st cBits) are 1
|
|
// Parameters:
|
|
// cBits the number of bits in the bitmap
|
|
// Returns:
|
|
// TRUE if all bits are 1, FALSE otherwise
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL CMsgBitMap::FAllSet(DWORD cBits)
|
|
{
|
|
TraceFunctEnterEx((LPARAM) this, "CMsgBitMap::FAllClear");
|
|
BOOL fResult = TRUE;
|
|
DWORD cDWORDs = cGetNumDWORDS(cBits+1) -1; //check all but last DWORD
|
|
DWORD iZeroIndex = cBits & 0x0000001F;
|
|
|
|
//verify all DWORD's by checking if 0
|
|
for (DWORD i = 0; i < cDWORDs; i++)
|
|
{
|
|
if (m_rgdwBitMap[i] != 0xFFFFFFFF)
|
|
{
|
|
fResult = FALSE;
|
|
goto Exit; //if we hit the iZeroIndex clause, we might assert
|
|
}
|
|
}
|
|
|
|
_ASSERT(i || iZeroIndex || !fResult); //We must check at least 1 DWORD
|
|
|
|
if (iZeroIndex)
|
|
{
|
|
iZeroIndex--; //we cBits is a count... our index starts at 0.
|
|
//last DWORD should be a subset of the ZeroMask
|
|
_ASSERT(s_rgdwZeroMasks[iZeroIndex] ==
|
|
(s_rgdwZeroMasks[iZeroIndex] | m_rgdwBitMap[cDWORDs]));
|
|
|
|
if (s_rgdwZeroMasks[iZeroIndex] != m_rgdwBitMap[cDWORDs])
|
|
fResult = FALSE;
|
|
}
|
|
|
|
Exit:
|
|
TraceFunctLeave();
|
|
return fResult;
|
|
}
|
|
|
|
//---[ CMsgBitMap::HrMarkBits ]------------------------------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// Marks the bits (as 0 or 1) that corresponds to the given indexes
|
|
//
|
|
// Parameters:
|
|
// IN DWORD cBits
|
|
// IN DWORD cIndexes # of indexes in array
|
|
// IN DWORD rgiBits SORTED array of indexes of bits to mark
|
|
// IN BOOL fSet TRUE => set to 1, 0 otherwise
|
|
// Returns:
|
|
// S_OK on success
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CMsgBitMap::HrMarkBits(IN DWORD cBits, IN DWORD cIndexes,
|
|
IN DWORD *rgiBits, IN BOOL fSet)
|
|
{
|
|
TraceFunctEnterEx((LPARAM) this, "CMsgBitMap::HrMarkBits");
|
|
HRESULT hr = S_OK;
|
|
DWORD cDWORDs = cGetNumDWORDS(cBits);
|
|
DWORD dwTmp;
|
|
DWORD dwIndex = 0x00000000;
|
|
DWORD i;
|
|
DWORD iCurrentIndex = 0; //current index in rgiBits
|
|
DWORD iCurrentLimit = BITS_PER_DWORD -1; //current limit of 32 bit range for values of rgiBits
|
|
|
|
_ASSERT(cIndexes);
|
|
_ASSERT(cIndexes <= cBits);
|
|
|
|
for (i = 0; i < cDWORDs; i++)
|
|
{
|
|
dwIndex = 0x00000000;
|
|
while ((iCurrentIndex < cIndexes) &&
|
|
(rgiBits[iCurrentIndex] <= iCurrentLimit))
|
|
{
|
|
_ASSERT(rgiBits[iCurrentIndex] < cBits);
|
|
dwIndex |= s_rgdwIndexMasks[(rgiBits[iCurrentIndex] % BITS_PER_DWORD)];
|
|
iCurrentIndex++;
|
|
}
|
|
|
|
if (dwIndex != 0x00000000) //don't perform costly interlocked op if we don't need to
|
|
{
|
|
if (fSet) //set bit
|
|
{
|
|
SpinTry1:
|
|
dwTmp = m_rgdwBitMap[i];
|
|
if (!fInterlockedDWORDCompareExchange(&(m_rgdwBitMap[i]), (dwIndex | dwTmp), dwTmp))
|
|
goto SpinTry1;
|
|
}
|
|
else //clear bit
|
|
{
|
|
SpinTry2:
|
|
dwTmp = m_rgdwBitMap[i];
|
|
if (!fInterlockedDWORDCompareExchange(&(m_rgdwBitMap[i]), ((~dwIndex) & dwTmp), dwTmp))
|
|
goto SpinTry2;
|
|
}
|
|
}
|
|
|
|
if (iCurrentIndex >= cIndexes)
|
|
break; //don't do more work than we have to
|
|
|
|
iCurrentLimit += BITS_PER_DWORD;
|
|
}
|
|
|
|
TraceFunctLeave();
|
|
return hr;
|
|
}
|
|
|
|
//---[ CMsgBitMap::HrGetIndexes ]----------------------------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// Generates an array of indexes represented by the bitmap
|
|
// Parameters:
|
|
// IN DWORD cBits
|
|
// OUT DWORD *pcIndexes //# of indexes returned
|
|
// OUT DWORD **prgdwIndexes //array of indexes
|
|
// Returns:
|
|
// S_OK on success
|
|
// E_OUTOFMEMORY if memory allocation fails
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CMsgBitMap::HrGetIndexes(IN DWORD cBits, OUT DWORD *pcIndexes,
|
|
OUT DWORD **prgdwIndexes)
|
|
{
|
|
TraceFunctEnterEx((LPARAM) this, "CMsgBitMap::HrGetIndexes");
|
|
HRESULT hr = S_OK;
|
|
DWORD *pdwIndexes = NULL;
|
|
DWORD dwIndex = 0;
|
|
DWORD dwIndexOffset = 0;
|
|
DWORD cDWORDs = cGetNumDWORDS(cBits);
|
|
DWORD cdwAllocated = 0;
|
|
DWORD cCurrentIndexes = 0;
|
|
DWORD i = 0;
|
|
DWORD *pdwTmp = NULL;
|
|
|
|
//$$REVIEW: How do we balance CPU usage vs memory usage here? We know the
|
|
// max size of the output array is cBits DWORDS, but in actuality it can
|
|
// little as 1 DWORD. Prognosticating the actual size accurately would
|
|
// require scanning the bitmap multiple times.
|
|
//
|
|
// Easy(studpid) way: Count bits, allocate array, recount and add indexes to array
|
|
//
|
|
// Idea #1: Allocate in chunks of 32 DWORDS, Realloc if we run out Should
|
|
// not have to worry about reallocing for 90% of the cases.
|
|
//
|
|
// Idea #2: Add some stats to this class, and run some stress tests in debug
|
|
// mode, and develop a heuristic that limits reallocs and such (ie alloc
|
|
// lg(cBits) to start with).
|
|
//
|
|
// Idea #3: Continue with Idea #2, but add self-tuning stats
|
|
Assert(pcIndexes);
|
|
Assert(prgdwIndexes);
|
|
|
|
pdwIndexes = (DWORD *) pvMalloc(BITS_PER_DWORD*sizeof(DWORD));
|
|
if (pdwIndexes == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Exit;
|
|
}
|
|
cdwAllocated = BITS_PER_DWORD;
|
|
|
|
cCurrentIndexes = 0;
|
|
|
|
for (i = 0; i < cDWORDs; i++)
|
|
{
|
|
dwIndex = 0;
|
|
while (dwIndex < BITS_PER_DWORD)
|
|
{
|
|
//can use mask to check if possible
|
|
if ((!(dwIndex & 0x00000003)) && //if %4 == 0
|
|
!(s_rgdwMasks[dwIndex/4] & m_rgdwBitMap[i]))
|
|
{
|
|
dwIndex += 4; //Can skip ahead 4
|
|
}
|
|
else
|
|
{
|
|
if (s_rgdwIndexMasks[dwIndex] & m_rgdwBitMap[i]) //Found it!
|
|
{
|
|
//Write index and check if re-allocation is needed
|
|
if (cCurrentIndexes >= cdwAllocated)
|
|
{
|
|
cdwAllocated += BITS_PER_DWORD;
|
|
pdwTmp = (DWORD *) pvRealloc(pdwIndexes, cdwAllocated*sizeof(DWORD));
|
|
if (NULL == pdwTmp)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Exit;
|
|
}
|
|
pdwIndexes = pdwTmp;
|
|
}
|
|
*(pdwIndexes + cCurrentIndexes) = (dwIndex + dwIndexOffset);
|
|
cCurrentIndexes++;
|
|
}
|
|
dwIndex++;
|
|
}
|
|
}
|
|
|
|
//Use dwIndexOffset to break down index generation into 32-bit chunks
|
|
dwIndexOffset += BITS_PER_DWORD;
|
|
}
|
|
|
|
*prgdwIndexes = pdwIndexes; //set OUT value
|
|
*pcIndexes = cCurrentIndexes;
|
|
|
|
Exit:
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
*prgdwIndexes = NULL;
|
|
*pcIndexes = 0;
|
|
FreePv(pdwIndexes);
|
|
}
|
|
|
|
TraceFunctLeave();
|
|
return hr;
|
|
}
|
|
|
|
//---[ CMsgBitMap::HrGroupOr ]-------------------------------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// Sets thir bitmap to the logical OR of the given list of bitmaps. This
|
|
// is used to prepare a bitmap that represents the domains being delivered
|
|
// over a list (or destmsg queue). Current bitmap is NOT cleared prior to
|
|
// this operation.
|
|
// Parameters:
|
|
// IN DWORD cBits number of bits in bitmap
|
|
// IN DWORD cBitMaps number of bitmaps in array
|
|
// IN CMsgBitMap **rgpBitMaps array of bitmaps to OR
|
|
// Returns:
|
|
// S_OK on success
|
|
//
|
|
// Note: This is NOT thread safe.. it's intended use is only for tmp bitmaps
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CMsgBitMap::HrGroupOr(IN DWORD cBits, IN DWORD cBitMaps,
|
|
IN CMsgBitMap **rgpBitMaps)
|
|
{
|
|
TraceFunctEnterEx((LPARAM) this, "CMsgBitMap::HrGroupOr");
|
|
HRESULT hr = S_OK;
|
|
DWORD cDWORDs = cGetNumDWORDS(cBits);
|
|
DWORD i, j;
|
|
|
|
for (i = 0; i < cDWORDs; i++)
|
|
{
|
|
for (j = 0; j < cBitMaps; j++)
|
|
{
|
|
Assert(rgpBitMaps[j]);
|
|
m_rgdwBitMap[i] |= rgpBitMaps[j]->m_rgdwBitMap[i];
|
|
}
|
|
}
|
|
|
|
TraceFunctLeave();
|
|
return hr;
|
|
}
|
|
|
|
//---[ CMsgBitMap::HrFilter ]--------------------------------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// Filters the current bitmap by setting only the bits that are SET in
|
|
// in and UNSET in the given bitmap..
|
|
// Performs a logical AND with the complement of the given bitmap
|
|
// Parameters:
|
|
// IN DWORD cBits # of bits in bitmap
|
|
// IN CMsgBitMap *pmbmap bitmap to filter against
|
|
// Returns:
|
|
// S_OK on success
|
|
//
|
|
// Truth Table:
|
|
// A => this bitmap
|
|
// B => pmbmap
|
|
//
|
|
// A B | A'B'
|
|
// ===========
|
|
// 0 0 | 0 0
|
|
// 0 1 | 0 1
|
|
// 1 0 | 1 0
|
|
// 1 1 | 0 1
|
|
//
|
|
// Note: This is NOT thread safe.. it's intended use is only for tmp bitmaps
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CMsgBitMap::HrFilter(IN DWORD cBits, IN CMsgBitMap *pmbmap)
|
|
{
|
|
TraceFunctEnterEx((LPARAM) this, "CMsgBitMap::HrFilter");
|
|
HRESULT hr = S_OK;
|
|
DWORD cDWORDs = cGetNumDWORDS(cBits);
|
|
|
|
Assert(pmbmap);
|
|
|
|
for (DWORD i = 0; i < cDWORDs; i++)
|
|
{
|
|
m_rgdwBitMap[i] &= ~(pmbmap->m_rgdwBitMap[i]);
|
|
}
|
|
|
|
TraceFunctLeave();
|
|
return hr;
|
|
}
|
|
|
|
//---[ CMsgBitMap::HrFilterSet ]-----------------------------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// Filters the current bitmap and sets those bits to 1 in the given
|
|
// bitmap. Unlike HrFilter, this modifies the given bitmap and does so
|
|
// in a thread-safe manner.
|
|
// Parameters:
|
|
// IN DWORD cBits # of bits in bitmap
|
|
// IN CMsgBitMap *pmbmap bitmap to filter against
|
|
// Returns:
|
|
// S_OK on success
|
|
//
|
|
// Truth Table:
|
|
// A => this bitmap
|
|
// B => pmbmap
|
|
//
|
|
// A B | A'B'
|
|
// ===========
|
|
// 0 0 | 0 0
|
|
// 0 1 | 0 1
|
|
// 1 0 | 1 1
|
|
// 1 1 | 0 1
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CMsgBitMap::HrFilterSet(IN DWORD cBits, IN CMsgBitMap *pmbmap)
|
|
{
|
|
TraceFunctEnterEx((LPARAM) this, "CMsgBitMap::HrFilterSet");
|
|
Assert(pmbmap);
|
|
|
|
HRESULT hr = S_OK;
|
|
DWORD cDWORDs = cGetNumDWORDS(cBits);
|
|
DWORD dwSelfNew;
|
|
DWORD dwOtherNew;
|
|
DWORD dwOtherOld;
|
|
DWORD i;
|
|
BOOL fDone = FALSE;
|
|
|
|
for (i = 0; i < cDWORDs; i++)
|
|
{
|
|
fDone = FALSE;
|
|
dwSelfNew = m_rgdwBitMap[i];
|
|
while (!fDone)
|
|
{
|
|
dwOtherNew = pmbmap->m_rgdwBitMap[i];
|
|
dwOtherOld = dwOtherNew;
|
|
|
|
dwSelfNew &= ~dwOtherNew; //filter
|
|
dwOtherNew ^= dwSelfNew; //set
|
|
|
|
if (fInterlockedDWORDCompareExchange(&(pmbmap->m_rgdwBitMap[i]),
|
|
dwOtherNew, dwOtherOld))
|
|
{
|
|
fDone = TRUE;
|
|
m_rgdwBitMap[i] = dwSelfNew;
|
|
}
|
|
}
|
|
}
|
|
|
|
TraceFunctLeave();
|
|
return hr;
|
|
}
|
|
|
|
//---[ CMsgBitMap::HrFilterUnset ]-----------------------------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// Uses the current bitmap and sets those bits that are 1 on it to 0 in the
|
|
// given bitmap. Unlike HrFilterSet, only the pmbmap is modified.
|
|
//
|
|
// This also checks that all bits that are 1 in self are also 1 in the
|
|
// other... ie that the 1 bits in this are a subset of pmbmap
|
|
// Parameters:
|
|
// IN DWORD cBits # of bits in bitmap
|
|
// IN CMsgBitMap *pmbmap bitmap to filter against
|
|
// Returns:
|
|
// S_OK on success
|
|
//
|
|
// Truth Table:
|
|
// A => this bitmap
|
|
// B => pmbmap
|
|
//
|
|
// A B | A'B'
|
|
// ===========
|
|
// 0 0 | 0 0
|
|
// 0 1 | 0 1
|
|
// 1 0 | x x - undefined (will assert)
|
|
// 1 1 | 1 0
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CMsgBitMap::HrFilterUnset(IN DWORD cBits, IN CMsgBitMap *pmbmap)
|
|
{
|
|
TraceFunctEnterEx((LPARAM) this, "CMsgBitMap::HrFilterUnset");
|
|
Assert(pmbmap);
|
|
|
|
HRESULT hr = S_OK;
|
|
DWORD cDWORDs = cGetNumDWORDS(cBits);
|
|
BOOL fDone = FALSE;
|
|
DWORD i;
|
|
DWORD dwOtherNew;
|
|
DWORD dwOtherOld;
|
|
|
|
for (i = 0; i < cDWORDs; i++)
|
|
{
|
|
fDone = FALSE;
|
|
|
|
while (!fDone)
|
|
{
|
|
dwOtherNew = pmbmap->m_rgdwBitMap[i];
|
|
dwOtherOld = dwOtherNew;
|
|
|
|
if (m_rgdwBitMap[i] & ~dwOtherNew)
|
|
{
|
|
//this bitmap is NOT a subset of the given bitmap
|
|
_ASSERT(0); //caller's mistake
|
|
hr = E_FAIL;
|
|
goto Exit;
|
|
}
|
|
|
|
dwOtherNew ^= m_rgdwBitMap[i]; //unset
|
|
|
|
if (fInterlockedDWORDCompareExchange(&(pmbmap->m_rgdwBitMap[i]),
|
|
dwOtherNew, dwOtherOld))
|
|
{
|
|
fDone = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
Exit:
|
|
TraceFunctLeave();
|
|
return hr;
|
|
}
|
|
|
|
|
|
//---[ CMsgBitMap::FTestAndSet ]-----------------------------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// An Interlocked function to test and set a bit on the this bit map.
|
|
// Looks for the bit that is set in the given bitmap, if that bit is also
|
|
// 1 in this bitmap, returns FALSE. If that bit is 0, it sets it to 1,
|
|
// and returns TRUE.
|
|
//
|
|
// NOTE: Results are UNDEFINED if there is more than 1 bit set in pmbmap.
|
|
// Parameters:
|
|
// cBits # of bits in bitmap
|
|
// pmbmap Bitmap to check against
|
|
// Returns:
|
|
// TRUE if the corresponding bit was 0 (and is now set to 1)
|
|
// FALSE if the corresponding bit was already1
|
|
// History:
|
|
// 11/8/98 - MikeSwa Created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL CMsgBitMap::FTestAndSet(IN DWORD cBits, IN CMsgBitMap *pmbmap)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
DWORD cDWORDs = cGetNumDWORDS(cBits);
|
|
BOOL fDone = FALSE;
|
|
DWORD dwThisNew = 0;
|
|
DWORD dwThisOld = 0;
|
|
DWORD i = 0;
|
|
|
|
for (i = 0; i < cDWORDs; i++)
|
|
{
|
|
|
|
if (pmbmap->m_rgdwBitMap[i])
|
|
{
|
|
//We've hit the bit in the given bitmap
|
|
|
|
//See if bit is already set
|
|
if (pmbmap->m_rgdwBitMap[i] & m_rgdwBitMap[i])
|
|
break;
|
|
|
|
while (!fDone)
|
|
{
|
|
dwThisOld = m_rgdwBitMap[i];
|
|
dwThisNew = dwThisOld | pmbmap->m_rgdwBitMap[i];
|
|
|
|
//See if another thread has set it
|
|
if (dwThisOld & pmbmap->m_rgdwBitMap[i])
|
|
break;
|
|
|
|
//Only 1 bit should be set on given bitmap
|
|
_ASSERT((dwThisOld | pmbmap->m_rgdwBitMap[i]) ==
|
|
(dwThisOld ^ pmbmap->m_rgdwBitMap[i]));
|
|
|
|
//Try to set bit
|
|
if (fInterlockedDWORDCompareExchange(&(m_rgdwBitMap[i]),
|
|
dwThisNew, dwThisOld))
|
|
{
|
|
fDone = TRUE;
|
|
fRet = TRUE;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
//---[ CMsgBitMap::FTest ]-----------------------------------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
// Tests this bitmap against a single bit in the given bitmap
|
|
// NOTE: Results are UNDEFINED if there is more than 1 bit set in pmbmap.
|
|
// Parameters:
|
|
// cBits # of bits in bitmap
|
|
// pmbmap Bitmap to check against
|
|
// Returns:
|
|
// TRUE if the corresponding bit is 1
|
|
// FALSE if the corresponding bit is 0
|
|
// History:
|
|
// 11/8/98 - MikeSwa Created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL CMsgBitMap::FTest(IN DWORD cBits, IN CMsgBitMap *pmbmap)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
DWORD cDWORDs = cGetNumDWORDS(cBits);
|
|
DWORD i = 0;
|
|
|
|
for (i = 0; i < cDWORDs; i++)
|
|
{
|
|
//See if we've hit the bit in the given bitmap
|
|
if (pmbmap->m_rgdwBitMap[i])
|
|
{
|
|
//See if bit is already set
|
|
if (pmbmap->m_rgdwBitMap[i] & m_rgdwBitMap[i])
|
|
fRet = TRUE;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|