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.

455 lines
8.8 KiB

  1. /*++
  2. Copyright (c) 1999-2001 Microsoft Corporation
  3. Module Name:
  4. opaqueidp.h
  5. Abstract:
  6. This module contains declarations private to the opaque ID table. These
  7. declarations are placed in a separate .H file to make it easier to access
  8. them from within the kernel debugger extension DLL.
  9. Author:
  10. Keith Moore (keithmo) 10-Sep-1999
  11. Revision History:
  12. --*/
  13. #ifndef _OPAQUEIDP_H_
  14. #define _OPAQUEIDP_H_
  15. #ifdef __cplusplus
  16. extern "C" {
  17. #endif
  18. //
  19. // The internal structure of an HTTP_OPAQUE_ID.
  20. //
  21. // N.B. This structure must be EXACTLY the same size as an HTTP_OPAQUE_ID!
  22. //
  23. #define PROCESSOR_BIT_WIDTH 6
  24. #define FIRST_INDEX_BIT_WIDTH 18
  25. #define SECOND_INDEX_BIT_WIDTH 8
  26. #define OPAQUE_ID_CYCLIC_BIT_WIDTH 29
  27. #define OPAQUE_ID_TYPE_BIT_WIDTH 3
  28. typedef union _UL_OPAQUE_ID_INTERNAL
  29. {
  30. HTTP_OPAQUE_ID OpaqueId;
  31. struct
  32. {
  33. union
  34. {
  35. ULONG Index;
  36. struct
  37. {
  38. ULONG Processor : PROCESSOR_BIT_WIDTH;
  39. ULONG FirstIndex : FIRST_INDEX_BIT_WIDTH;
  40. ULONG SecondIndex : SECOND_INDEX_BIT_WIDTH;
  41. };
  42. };
  43. union
  44. {
  45. ULONG Cyclic;
  46. struct
  47. {
  48. ULONG OpaqueIdCyclic : OPAQUE_ID_CYCLIC_BIT_WIDTH;
  49. ULONG OpaqueIdType : OPAQUE_ID_TYPE_BIT_WIDTH;
  50. };
  51. };
  52. };
  53. } UL_OPAQUE_ID_INTERNAL, *PUL_OPAQUE_ID_INTERNAL;
  54. C_ASSERT( sizeof(HTTP_OPAQUE_ID) == sizeof(UL_OPAQUE_ID_INTERNAL) );
  55. C_ASSERT( 8 * sizeof(HTTP_OPAQUE_ID) == (PROCESSOR_BIT_WIDTH + \
  56. FIRST_INDEX_BIT_WIDTH + \
  57. SECOND_INDEX_BIT_WIDTH + \
  58. OPAQUE_ID_CYCLIC_BIT_WIDTH + \
  59. OPAQUE_ID_TYPE_BIT_WIDTH \
  60. ));
  61. C_ASSERT((1 << PROCESSOR_BIT_WIDTH) >= MAXIMUM_PROCESSORS);
  62. //
  63. // A per-entry opaque ID lock.
  64. //
  65. #define OPAQUE_ID_DPC
  66. #ifdef OPAQUE_ID_DPC
  67. typedef KSPIN_LOCK UL_OPAQUE_ID_LOCK, *PUL_OPAQUE_ID_LOCK;
  68. __inline
  69. VOID
  70. FASTCALL
  71. UlpInitializeOpaqueIdLock(
  72. IN PUL_OPAQUE_ID_LOCK pLock
  73. )
  74. {
  75. KeInitializeSpinLock( pLock );
  76. }
  77. __inline
  78. VOID
  79. FASTCALL
  80. UlpAcquireOpaqueIdLock(
  81. IN PUL_OPAQUE_ID_LOCK pLock,
  82. OUT PKIRQL pOldIrql
  83. )
  84. {
  85. KeAcquireSpinLock( pLock, pOldIrql );
  86. }
  87. __inline
  88. VOID
  89. FASTCALL
  90. UlpReleaseOpaqueIdLock(
  91. IN PUL_OPAQUE_ID_LOCK pLock,
  92. IN KIRQL OldIrql
  93. )
  94. {
  95. KeReleaseSpinLock( pLock, OldIrql );
  96. }
  97. #else
  98. typedef volatile LONG UL_OPAQUE_ID_LOCK, *PUL_OPAQUE_ID_LOCK;
  99. __inline
  100. VOID
  101. FASTCALL
  102. UlpInitializeOpaqueIdLock(
  103. IN PUL_OPAQUE_ID_LOCK pLock
  104. )
  105. {
  106. *pLock = 0;
  107. }
  108. __inline
  109. VOID
  110. FASTCALL
  111. UlpAcquireOpaqueIdLock(
  112. IN PUL_OPAQUE_ID_LOCK pLock,
  113. OUT PKIRQL pOldIrql
  114. )
  115. {
  116. while (TRUE)
  117. {
  118. while (*pLock == 1)
  119. {
  120. PAUSE_PROCESSOR
  121. }
  122. if (0 == InterlockedCompareExchange( pLock, 1, 0 ))
  123. {
  124. break;
  125. }
  126. }
  127. }
  128. __inline
  129. VOID
  130. FASTCALL
  131. UlpReleaseOpaqueIdLock(
  132. IN PUL_OPAQUE_ID_LOCK pLock,
  133. IN KIRQL OldIrql
  134. )
  135. {
  136. ASSERT( *pLock == 1 );
  137. InterlockedExchange( pLock, 0 );
  138. }
  139. #endif
  140. //
  141. // A second-level table entry.
  142. //
  143. // Note that FreeListEntry and pContext are in an anonymous
  144. // union to save space; an entry is either on the free list or in use,
  145. // so only one of these fields will be used at a time.
  146. //
  147. // Also note that Cyclic is in a second anonymous union. It's overlayed
  148. // with FirstLevelIndex (which is basically the second-level table's
  149. // index in the first-level table) and ID type (used to distinguish
  150. // free entries from in-use entries).
  151. //
  152. #define SECOND_LEVEL_TABLE_SIZE 256
  153. C_ASSERT( SECOND_LEVEL_TABLE_SIZE == 1 << SECOND_INDEX_BIT_WIDTH );
  154. typedef struct _UL_OPAQUE_ID_TABLE_ENTRY
  155. {
  156. //
  157. // NonPagedPool
  158. //
  159. union
  160. {
  161. //
  162. // To ensure FreeListEntry is aligned on 8-byte boundary.
  163. //
  164. ULONGLONG Alignment;
  165. struct
  166. {
  167. union
  168. {
  169. //
  170. // An entry to the global ID table's free ID list.
  171. //
  172. SINGLE_LIST_ENTRY FreeListEntry;
  173. //
  174. // Context associated with the opaque ID.
  175. //
  176. PVOID pContext;
  177. };
  178. //
  179. // A per-entry ID cyclic that guarantees we can generate
  180. // 2 ^ OPAQUE_ID_CYCLIC_BIT_WIDTH of opaque IDs from the
  181. // current entry without repeating. This gives us extra
  182. // protection than using a global ID cyclic.
  183. //
  184. ULONG EntryOpaqueIdCyclic;
  185. };
  186. };
  187. //
  188. // A per-entry lock that protects the entry.
  189. //
  190. UL_OPAQUE_ID_LOCK Lock;
  191. //
  192. // The ID index for the opaque ID when the entry is free or the cyclic
  193. // when the entry is in use.
  194. //
  195. union
  196. {
  197. union
  198. {
  199. ULONG Index;
  200. struct
  201. {
  202. ULONG Processor : PROCESSOR_BIT_WIDTH;
  203. ULONG FirstIndex : FIRST_INDEX_BIT_WIDTH;
  204. ULONG Reserved : SECOND_INDEX_BIT_WIDTH;
  205. };
  206. };
  207. union
  208. {
  209. ULONG Cyclic;
  210. struct
  211. {
  212. ULONG OpaqueIdCyclic : OPAQUE_ID_CYCLIC_BIT_WIDTH;
  213. ULONG OpaqueIdType : OPAQUE_ID_TYPE_BIT_WIDTH;
  214. };
  215. };
  216. };
  217. } UL_OPAQUE_ID_TABLE_ENTRY, *PUL_OPAQUE_ID_TABLE_ENTRY;
  218. //
  219. // We keep a per-processor first-level ID tables. A single table is a
  220. // major scalability bottleneck on SMP machines. The size of the first-level
  221. // table is controlled by a registry setting.
  222. //
  223. #if DBG
  224. #define OPAQUE_ID_INSTRUMENTATION
  225. #endif
  226. typedef struct _UL_OPAQUE_ID_TABLE
  227. {
  228. //
  229. // A list of free IDs available on this table.
  230. //
  231. SLIST_HEADER FreeOpaqueIdSListHead;
  232. //
  233. // An arrary of second-level ID table entries.
  234. //
  235. PUL_OPAQUE_ID_TABLE_ENTRY *FirstLevelTable;
  236. //
  237. // The corresponding CPU this table represents.
  238. //
  239. UCHAR Processor;
  240. //
  241. // The lock really only protects FirstLevelTableInUse.
  242. //
  243. UL_SPIN_LOCK Lock;
  244. //
  245. // The current number of first-level tables allocated.
  246. //
  247. ULONG FirstLevelTableInUse;
  248. //
  249. // The maximum size we can grow for the first-level tables.
  250. //
  251. ULONG FirstLevelTableSize;
  252. #ifdef OPAQUE_ID_INSTRUMENTATION
  253. LONGLONG NumberOfAllocations;
  254. LONGLONG NumberOfFrees;
  255. LONGLONG NumberOfTotalGets;
  256. LONGLONG NumberOfSuccessfulGets;
  257. #endif
  258. } UL_OPAQUE_ID_TABLE, *PUL_OPAQUE_ID_TABLE;
  259. //
  260. // Necessary to ensure our array of UL_OPAQUE_ID_TABLE structures is
  261. // cache aligned.
  262. //
  263. typedef union _UL_ALIGNED_OPAQUE_ID_TABLE
  264. {
  265. UL_OPAQUE_ID_TABLE OpaqueIdTable;
  266. UCHAR CacheAlignment[(sizeof(UL_OPAQUE_ID_TABLE) + UL_CACHE_LINE - 1) & ~(UL_CACHE_LINE - 1)];
  267. } UL_ALIGNED_OPAQUE_ID_TABLE, *PUL_ALIGINED_OPAQUE_ID_TABLE;
  268. //
  269. // An inline function that maps a specified HTTP_OPAQUE_ID to the
  270. // corresponding ID table entry.
  271. //
  272. extern UL_ALIGNED_OPAQUE_ID_TABLE g_UlOpaqueIdTable[];
  273. __inline
  274. BOOLEAN
  275. FASTCALL
  276. UlpExtractIndexFromOpaqueId(
  277. IN HTTP_OPAQUE_ID OpaqueId,
  278. OUT PULONG pProcessor,
  279. OUT PULONG pFirstIndex,
  280. OUT PULONG pSecondIndex
  281. )
  282. {
  283. UL_OPAQUE_ID_INTERNAL InternalId;
  284. PUL_OPAQUE_ID_TABLE pOpaqueIdTable;
  285. InternalId.OpaqueId = OpaqueId;
  286. //
  287. // Verify the processor portion of the index.
  288. //
  289. *pProcessor = InternalId.Processor;
  290. if (*pProcessor >= g_UlNumberOfProcessors)
  291. {
  292. return FALSE;
  293. }
  294. //
  295. // Verify the first-level index.
  296. //
  297. pOpaqueIdTable = &g_UlOpaqueIdTable[*pProcessor].OpaqueIdTable;
  298. *pFirstIndex = InternalId.FirstIndex;
  299. if (*pFirstIndex >= pOpaqueIdTable->FirstLevelTableInUse)
  300. {
  301. return FALSE;
  302. }
  303. //
  304. // Second-level index is always valid since we only allocated 8-bits.
  305. //
  306. ASSERT( InternalId.SecondIndex < SECOND_LEVEL_TABLE_SIZE );
  307. *pSecondIndex = InternalId.SecondIndex;
  308. return TRUE;
  309. }
  310. __inline
  311. PUL_OPAQUE_ID_TABLE_ENTRY
  312. FASTCALL
  313. UlpMapOpaqueIdToTableEntry(
  314. IN HTTP_OPAQUE_ID OpaqueId
  315. )
  316. {
  317. PUL_OPAQUE_ID_TABLE pOpaqueIdTable;
  318. ULONG Processor;
  319. ULONG FirstIndex;
  320. ULONG SecondIndex;
  321. if (UlpExtractIndexFromOpaqueId(
  322. OpaqueId,
  323. &Processor,
  324. &FirstIndex,
  325. &SecondIndex
  326. ))
  327. {
  328. pOpaqueIdTable = &g_UlOpaqueIdTable[Processor].OpaqueIdTable;
  329. return pOpaqueIdTable->FirstLevelTable[FirstIndex] + SecondIndex;
  330. }
  331. else
  332. {
  333. return NULL;
  334. }
  335. }
  336. //
  337. // Private prototypes.
  338. //
  339. NTSTATUS
  340. UlpExpandOpaqueIdTable(
  341. IN PUL_OPAQUE_ID_TABLE pOpaqueIdTable,
  342. IN LONG CapturedFirstTableInUse
  343. );
  344. #ifdef __cplusplus
  345. }; // extern "C"
  346. #endif
  347. #endif // _OPAQUEIDP_H_