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.

266 lines
7.5 KiB

  1. #include "stdafx.h"
  2. #include "time.h"
  3. #include "crv.h"
  4. inline BOOL
  5. IsBitOn(
  6. IN BYTE *Byte,
  7. IN BYTE BitNumber
  8. )
  9. {
  10. // the bit number must be in the range [0..8)
  11. _ASSERTE(BitNumber < 8);
  12. return (*Byte & (1 << BitNumber));
  13. }
  14. inline void
  15. SetBit(
  16. IN BYTE *Byte,
  17. IN BYTE BitNumber,
  18. IN BOOL OnOff
  19. )
  20. {
  21. // the bit number must be in the range [0..8)
  22. _ASSERTE(BitNumber < 8);
  23. if(OnOff)
  24. {
  25. // Turn the bit on
  26. *Byte |= (1 << BitNumber);
  27. }
  28. else
  29. { // Turn the bit off
  30. *Byte &= ~(1 << BitNumber);
  31. }
  32. }
  33. ///////////////////////////////////////////////////////////////////////////////
  34. // //
  35. // CRV allocator variables and functions. //
  36. // //
  37. ///////////////////////////////////////////////////////////////////////////////
  38. // these const values are needed for CRV generation
  39. // max number of random number generations needed to
  40. // get a low probability of failure. An assumption of max 10^3
  41. // active calls at a time in a space of 2^15 crv values implies
  42. // that we can reach 1 in 10^6 failure prob. in 4 generations
  43. const BYTE MAX_CALL_REF_RAND_GEN = 4;
  44. // number of different CRV values
  45. const WORD TOTAL_CRVS = 0x8000; // 2^15;
  46. // number of bits needed for the crv bit map
  47. const WORD CRV_BIT_MAP_SIZE = (TOTAL_CRVS/8); // (2^15)/8;
  48. // CODEWORK: We are allocating a huge array 0x1000 bytes - is this okay ?
  49. // number of allocated crvs.
  50. // currently this is only used for a sanity check. it may be used for
  51. // determining the max number of random numbers to generate before trying
  52. // a linear search through the bitmap.
  53. WORD g_NumAllocatedCRVs;
  54. // bitmap array in which each bit represents whether or not the corresponding
  55. // crv has been allocated. The mapping between crv value N and a bit is -
  56. // N <-> CRVBitMap[N/8] byte, N%8 bit
  57. // NOTE: This must be zero'ed out during initialization as a bit is on iff
  58. // it has been allocated
  59. BYTE g_CRVBitMap[CRV_BIT_MAP_SIZE];
  60. // critical section to synchronize access to the bit map data structures
  61. CRITICAL_SECTION g_CRVBitMapCritSec;
  62. HRESULT InitCrvAllocator()
  63. {
  64. // no crvs have been allocated
  65. g_NumAllocatedCRVs = 0;
  66. // zero out the bit map
  67. ZeroMemory(g_CRVBitMap, CRV_BIT_MAP_SIZE);
  68. // 0 is not a valid call ref value and it cannot be allocated or
  69. // deallocated we set the first bit of the first byte to 1 so that
  70. // it is never returned by AllocCallRefVal
  71. g_CRVBitMap[0] = 0x80;
  72. InitializeCriticalSection(&g_CRVBitMapCritSec);
  73. // Seed the random-number generator with current time so that
  74. // the numbers will be different every time we run.
  75. srand( (unsigned)time( NULL ) );
  76. return S_OK;
  77. }
  78. HRESULT CleanupCrvAllocator()
  79. {
  80. DeleteCriticalSection(&g_CRVBitMapCritSec);
  81. return S_OK;
  82. }
  83. // The CRV allocator is locked when this function is called.
  84. // fallback algorithm to linearly search through the bitmap
  85. // for a free call ref value. this should be called very rarely
  86. BOOL
  87. LinearBitMapSearch(
  88. OUT CALL_REF_TYPE &CallRefVal
  89. )
  90. {
  91. // check each byte in the bit map array
  92. // NOTE: we can check 8 bytes at a time using int64, but since this method is
  93. // only called extremely rarely, there is no need to complicate the logic
  94. for(WORD i=0; i < CRV_BIT_MAP_SIZE; i++)
  95. {
  96. // check the byte to see if there is any use checking its bits
  97. if (0xFF == g_CRVBitMap[i])
  98. {
  99. continue;
  100. }
  101. // check all bits from bit 0 to bit 7
  102. for (BYTE j=0; j < 8; j++)
  103. {
  104. if (!IsBitOn(&g_CRVBitMap[i], j))
  105. {
  106. // set the bit on
  107. SetBit(&g_CRVBitMap[i], j, TRUE);
  108. // byte*8 + the bit number gives us the call ref value
  109. CallRefVal = (i << 3) + j;
  110. // increment the number of allocated crvs
  111. g_NumAllocatedCRVs++;
  112. return TRUE;
  113. }
  114. }
  115. }
  116. return FALSE;
  117. }
  118. // CODEWORK: Is all this stuff really worth it ?
  119. // rand() is typically expensive. We probably can leave it this way for now.
  120. //
  121. // try to find a free call ref value by randomly generating one and
  122. // then checking if its free. The assumption here is that the max
  123. // number of call ref values is much less than the size of the call ref
  124. // universe. we check this for a max of MAX_CALL_REF_RAND_GEN attempts.
  125. // MAX_CALL_REF_RAND_GEN can be derived so that the probability
  126. // of failure is very low (say 1 in a million). This may be derived from
  127. // the number of call ref values currently available and the size of
  128. // the call ref value universe. For ex. we believe that atmost 1000 calls
  129. // may be active at any time and the crv universe is of size 2^15. This
  130. // means that the prob. of failure for EACH attempt is < 1/32. Hence 4
  131. // attempts would give us a 1 in a million probability of failure
  132. BOOL
  133. AllocCallRefVal(
  134. OUT CALL_REF_TYPE &CallRefVal
  135. )
  136. {
  137. ///////////////////////////////
  138. //// LOCK the CRV ALLOCATOR
  139. ///////////////////////////////
  140. EnterCriticalSection(&g_CRVBitMapCritSec);
  141. //AUTO_CRIT_LOCK AutoCritLock(g_CRVBitMapCritSec.GetCritSec());
  142. // sanity check to see if we have used up all crvs
  143. if (TOTAL_CRVS == g_NumAllocatedCRVs)
  144. {
  145. DebugF( _T("AllocCallRefVal(&CallRefVal) returning FALSE, all CRVs used up\n"));
  146. LeaveCriticalSection(&g_CRVBitMapCritSec);
  147. return FALSE;
  148. }
  149. // check if crv is free, for a max of MAX_CALL_REF_RAND_GEN times
  150. for (BYTE i=0; i < MAX_CALL_REF_RAND_GEN; i++)
  151. {
  152. // generate random number
  153. // NOTE: the range is [0..RAND_MAX] and RAND_MAX is defined as 0x7fff
  154. // since this is also the range of legal CRVs, we don't need to convert
  155. // the generated number to a new range
  156. CALL_REF_TYPE NewCRV = (CALL_REF_TYPE) rand();
  157. // identify the byte number corresponding to the crv.
  158. // we don't check just try the corresponding bit and check other
  159. // bits in the byte as well. this is done to increase the chances of
  160. // finding a free bit for each random generation
  161. WORD ByteNum = NewCRV / 8;
  162. // check all bits from bit 0 to bit 7
  163. for (BYTE j=0; j < 8; j++)
  164. {
  165. if (!IsBitOn(&g_CRVBitMap[ByteNum], j))
  166. {
  167. // set the bit on
  168. SetBit(&g_CRVBitMap[ByteNum], j, TRUE);
  169. // byte*8 + the bit number gives us the call ref value
  170. CallRefVal = (ByteNum << 3) + j;
  171. // increment the number of allocated crvs
  172. g_NumAllocatedCRVs++;
  173. LeaveCriticalSection(&g_CRVBitMapCritSec);
  174. return TRUE;
  175. }
  176. }
  177. }
  178. // we reach here in extremely rare cases. we can now try a linear search
  179. // through the crv bitmap for a free crv
  180. DebugF(_T("AllocCallRefVal() trying linear search.\n"));
  181. BOOL fRetVal = LinearBitMapSearch(CallRefVal);
  182. LeaveCriticalSection(&g_CRVBitMapCritSec);
  183. return fRetVal;
  184. }
  185. // frees a currently allocated call ref value
  186. void
  187. DeallocCallRefVal(
  188. IN CALL_REF_TYPE CallRefVal
  189. )
  190. {
  191. // 0 is not a valid call ref value and it cannot be allocated or
  192. // deallocated we set the first bit of the first byte to 1 so that
  193. // it is never returned by AllocCallRefVal
  194. if (0 == CallRefVal)
  195. {
  196. _ASSERTE(FALSE);
  197. return;
  198. }
  199. // determine the byte and the bit
  200. WORD ByteNum = CallRefVal / 8;
  201. BYTE BitNum = CallRefVal % 8;
  202. // acquire critical section
  203. EnterCriticalSection(&g_CRVBitMapCritSec);
  204. // the bit should be on (to indicate that its in use)
  205. if (IsBitOn(&g_CRVBitMap[ByteNum], BitNum))
  206. {
  207. // set the bit off
  208. SetBit(&g_CRVBitMap[ByteNum], BitNum, FALSE);
  209. // decrement number of available crvs
  210. g_NumAllocatedCRVs--;
  211. }
  212. else {
  213. DebugF(_T("DeallocCallRefVal: warning, bit was not allocated to begin with, crv %04XH\n"),
  214. CallRefVal);
  215. }
  216. LeaveCriticalSection(&g_CRVBitMapCritSec);
  217. }