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.
|
|
#include "stdafx.h"
#include "time.h"
#include "crv.h"
inline BOOL IsBitOn( IN BYTE *Byte, IN BYTE BitNumber ) { // the bit number must be in the range [0..8)
_ASSERTE(BitNumber < 8);
return (*Byte & (1 << BitNumber)); }
inline void SetBit( IN BYTE *Byte, IN BYTE BitNumber, IN BOOL OnOff ) { // the bit number must be in the range [0..8)
_ASSERTE(BitNumber < 8);
if(OnOff) { // Turn the bit on
*Byte |= (1 << BitNumber); } else { // Turn the bit off
*Byte &= ~(1 << BitNumber);
} }
///////////////////////////////////////////////////////////////////////////////
// //
// CRV allocator variables and functions. //
// //
///////////////////////////////////////////////////////////////////////////////
// these const values are needed for CRV generation
// max number of random number generations needed to
// get a low probability of failure. An assumption of max 10^3
// active calls at a time in a space of 2^15 crv values implies
// that we can reach 1 in 10^6 failure prob. in 4 generations
const BYTE MAX_CALL_REF_RAND_GEN = 4;
// number of different CRV values
const WORD TOTAL_CRVS = 0x8000; // 2^15;
// number of bits needed for the crv bit map
const WORD CRV_BIT_MAP_SIZE = (TOTAL_CRVS/8); // (2^15)/8;
// CODEWORK: We are allocating a huge array 0x1000 bytes - is this okay ?
// number of allocated crvs.
// currently this is only used for a sanity check. it may be used for
// determining the max number of random numbers to generate before trying
// a linear search through the bitmap.
WORD g_NumAllocatedCRVs;
// bitmap array in which each bit represents whether or not the corresponding
// crv has been allocated. The mapping between crv value N and a bit is -
// N <-> CRVBitMap[N/8] byte, N%8 bit
// NOTE: This must be zero'ed out during initialization as a bit is on iff
// it has been allocated
BYTE g_CRVBitMap[CRV_BIT_MAP_SIZE];
// critical section to synchronize access to the bit map data structures
CRITICAL_SECTION g_CRVBitMapCritSec;
HRESULT InitCrvAllocator() { // no crvs have been allocated
g_NumAllocatedCRVs = 0;
// zero out the bit map
ZeroMemory(g_CRVBitMap, CRV_BIT_MAP_SIZE);
// 0 is not a valid call ref value and it cannot be allocated or
// deallocated we set the first bit of the first byte to 1 so that
// it is never returned by AllocCallRefVal
g_CRVBitMap[0] = 0x80;
InitializeCriticalSection(&g_CRVBitMapCritSec); // Seed the random-number generator with current time so that
// the numbers will be different every time we run.
srand( (unsigned)time( NULL ) );
return S_OK; }
HRESULT CleanupCrvAllocator() { DeleteCriticalSection(&g_CRVBitMapCritSec); return S_OK; }
// The CRV allocator is locked when this function is called.
// fallback algorithm to linearly search through the bitmap
// for a free call ref value. this should be called very rarely
BOOL LinearBitMapSearch( OUT CALL_REF_TYPE &CallRefVal ) { // check each byte in the bit map array
// NOTE: we can check 8 bytes at a time using int64, but since this method is
// only called extremely rarely, there is no need to complicate the logic
for(WORD i=0; i < CRV_BIT_MAP_SIZE; i++) { // check the byte to see if there is any use checking its bits
if (0xFF == g_CRVBitMap[i]) { continue; }
// check all bits from bit 0 to bit 7
for (BYTE j=0; j < 8; j++) { if (!IsBitOn(&g_CRVBitMap[i], j)) { // set the bit on
SetBit(&g_CRVBitMap[i], j, TRUE);
// byte*8 + the bit number gives us the call ref value
CallRefVal = (i << 3) + j;
// increment the number of allocated crvs
g_NumAllocatedCRVs++;
return TRUE; } } }
return FALSE; }
// CODEWORK: Is all this stuff really worth it ?
// rand() is typically expensive. We probably can leave it this way for now.
//
// try to find a free call ref value by randomly generating one and
// then checking if its free. The assumption here is that the max
// number of call ref values is much less than the size of the call ref
// universe. we check this for a max of MAX_CALL_REF_RAND_GEN attempts.
// MAX_CALL_REF_RAND_GEN can be derived so that the probability
// of failure is very low (say 1 in a million). This may be derived from
// the number of call ref values currently available and the size of
// the call ref value universe. For ex. we believe that atmost 1000 calls
// may be active at any time and the crv universe is of size 2^15. This
// means that the prob. of failure for EACH attempt is < 1/32. Hence 4
// attempts would give us a 1 in a million probability of failure
BOOL AllocCallRefVal( OUT CALL_REF_TYPE &CallRefVal ) { ///////////////////////////////
//// LOCK the CRV ALLOCATOR
///////////////////////////////
EnterCriticalSection(&g_CRVBitMapCritSec); //AUTO_CRIT_LOCK AutoCritLock(g_CRVBitMapCritSec.GetCritSec());
// sanity check to see if we have used up all crvs
if (TOTAL_CRVS == g_NumAllocatedCRVs) { DebugF( _T("AllocCallRefVal(&CallRefVal) returning FALSE, all CRVs used up\n")); LeaveCriticalSection(&g_CRVBitMapCritSec); return FALSE; }
// check if crv is free, for a max of MAX_CALL_REF_RAND_GEN times
for (BYTE i=0; i < MAX_CALL_REF_RAND_GEN; i++) { // generate random number
// NOTE: the range is [0..RAND_MAX] and RAND_MAX is defined as 0x7fff
// since this is also the range of legal CRVs, we don't need to convert
// the generated number to a new range
CALL_REF_TYPE NewCRV = (CALL_REF_TYPE) rand();
// identify the byte number corresponding to the crv.
// we don't check just try the corresponding bit and check other
// bits in the byte as well. this is done to increase the chances of
// finding a free bit for each random generation
WORD ByteNum = NewCRV / 8;
// check all bits from bit 0 to bit 7
for (BYTE j=0; j < 8; j++) { if (!IsBitOn(&g_CRVBitMap[ByteNum], j)) { // set the bit on
SetBit(&g_CRVBitMap[ByteNum], j, TRUE);
// byte*8 + the bit number gives us the call ref value
CallRefVal = (ByteNum << 3) + j;
// increment the number of allocated crvs
g_NumAllocatedCRVs++;
LeaveCriticalSection(&g_CRVBitMapCritSec);
return TRUE; } } }
// we reach here in extremely rare cases. we can now try a linear search
// through the crv bitmap for a free crv
DebugF(_T("AllocCallRefVal() trying linear search.\n")); BOOL fRetVal = LinearBitMapSearch(CallRefVal); LeaveCriticalSection(&g_CRVBitMapCritSec); return fRetVal; }
// frees a currently allocated call ref value
void DeallocCallRefVal( IN CALL_REF_TYPE CallRefVal ) { // 0 is not a valid call ref value and it cannot be allocated or
// deallocated we set the first bit of the first byte to 1 so that
// it is never returned by AllocCallRefVal
if (0 == CallRefVal) { _ASSERTE(FALSE); return; }
// determine the byte and the bit
WORD ByteNum = CallRefVal / 8; BYTE BitNum = CallRefVal % 8;
// acquire critical section
EnterCriticalSection(&g_CRVBitMapCritSec);
// the bit should be on (to indicate that its in use)
if (IsBitOn(&g_CRVBitMap[ByteNum], BitNum)) { // set the bit off
SetBit(&g_CRVBitMap[ByteNum], BitNum, FALSE);
// decrement number of available crvs
g_NumAllocatedCRVs--; } else { DebugF(_T("DeallocCallRefVal: warning, bit was not allocated to begin with, crv %04XH\n"), CallRefVal); }
LeaveCriticalSection(&g_CRVBitMapCritSec); }
|