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.

423 lines
13 KiB

  1. #ifndef _FIND_HPP_
  2. #define _FIND_HPP_
  3. // Ruler
  4. // 1 2 3 4 5 6 7 8
  5. //345678901234567890123456789012345678901234567890123456789012345678901234567890
  6. /********************************************************************/
  7. /* */
  8. /* The standard layout. */
  9. /* */
  10. /* The standard layout for 'hpp' files for this code is as */
  11. /* follows: */
  12. /* */
  13. /* 1. Include files. */
  14. /* 2. Constants exported from the class. */
  15. /* 3. Data structures exported from the class. */
  16. /* 4. Forward references to other data structures. */
  17. /* 5. Class specifications (including inline functions). */
  18. /* 6. Additional large inline functions. */
  19. /* */
  20. /* Any portion that is not required is simply omitted. */
  21. /* */
  22. /********************************************************************/
  23. #include "Global.hpp"
  24. #include "Environment.hpp"
  25. #include "Common.hpp"
  26. #include "List.hpp"
  27. #include "Page.hpp"
  28. #include "Prefetch.hpp"
  29. #include "Rockall.hpp"
  30. #include "Sharelock.hpp"
  31. #include "Spinlock.hpp"
  32. #include "Tls.hpp"
  33. /********************************************************************/
  34. /* */
  35. /* Class forward references. */
  36. /* */
  37. /* We need to refer to the following classes before they are */
  38. /* fully specified so here we list them as forward references. */
  39. /* */
  40. /********************************************************************/
  41. class CACHE;
  42. class HEAP;
  43. /********************************************************************/
  44. /* */
  45. /* Find a memory allocation. */
  46. /* */
  47. /* When a memory allocation is released all we are given is . */
  48. /* the allocation address. This is not very helpful as the */
  49. /* allocation information is not stored relative to this */
  50. /* address. Instead we use a hash table to map the allocation */
  51. /* address to the allocation information. */
  52. /* */
  53. /********************************************************************/
  54. class FIND : public ENVIRONMENT, public COMMON
  55. {
  56. //
  57. // Private type specifications.
  58. //
  59. // We need to do a recursive search in the find
  60. // table in order to locate the associated page
  61. // from an address. As this is expensive there
  62. // is also a cache that slaves common translations
  63. // to improve performance.
  64. //
  65. typedef struct
  66. {
  67. VOID *Address;
  68. PAGE *Page;
  69. #ifdef DEBUGGING
  70. SBIT32 Version;
  71. #endif
  72. }
  73. LOOK_ASIDE;
  74. //
  75. // Private data.
  76. //
  77. // All the page descriptions are stored in the
  78. // hash table so they can be quickly found. The
  79. // key is the address of the first byte on the
  80. // page. The 'MaxHash' is the number of elements
  81. // in the hash table and is always a power of two.
  82. // The 'HashMask' is a bit mask to remove any
  83. // unwanted part of the hash key. The 'HashShift'
  84. // is the number of bits required to shift and is
  85. // as a substitute for divide. The 'Resize' flag
  86. // indicates whether the hash table is permitted
  87. // to grow.
  88. //
  89. SBIT32 MaxHash;
  90. SBIT32 HashMask;
  91. SBIT32 HashShift;
  92. BOOLEAN Resize;
  93. //
  94. // The hash table allows addresses to be mapped to
  95. // page descriptions quickly. Nonetheless, it is
  96. // not fast enough. To enhance performance a look
  97. // aside cache slaves the hottest translations. The
  98. // 'MaxLookAside' is the number of elements in the
  99. // cache. The 'MaxAddressMask' is a mask that removes
  100. // low order bits of an address and represents the
  101. // span of each cache entry. The 'LookAsideActions'
  102. // is a simple count of requests to the cache. The
  103. // 'LookAsideMask' and 'LookAsideShift' parallel the
  104. // fields above in the hash table. The 'LookAsideThreshold'
  105. // determines at what point the cache will become
  106. // active. The 'ThreadSafe' flag indicates whether
  107. // locking is required.
  108. //
  109. SBIT32 MaxLookAside;
  110. BIT32 MaxAddressMask;
  111. BIT32 MinAddressMask;
  112. SBIT32 LookAsideActions;
  113. SBIT32 LookAsideMask;
  114. SBIT32 LookAsideShift;
  115. SBIT32 LookAsideThreshold;
  116. BOOLEAN ThreadSafe;
  117. //
  118. // When a request is made to translate an address to
  119. // a page description the cache is the first port of
  120. // call. If the translation is not found then the
  121. // hash table is tried. The 'Hash' points to the hash
  122. // table. The 'LookAside' points to the lookaside
  123. // hash table. The 'Rockall' points to the external API
  124. // to give access to the low level external allocation
  125. // functions.
  126. //
  127. LIST *Hash;
  128. LOOK_ASIDE *LookAside;
  129. ROCKALL *Rockall;
  130. //
  131. // The translation of addresses to page descriptions
  132. // is very common. So care has been taken to ensure
  133. // it is not a bottleneck when locking is enabled. The
  134. // 'Sharelock' is a fast reader/writer lock and is used
  135. // almost all the time. The 'Spinlock' is an exclusive
  136. // lock and is only used when the 'Hash' and 'LookAside'
  137. // tables are resized.
  138. //
  139. PREFETCH Prefetch;
  140. SHARELOCK Sharelock;
  141. SPINLOCK Spinlock;
  142. #ifdef ENABLE_HEAP_STATISTICS
  143. //
  144. // Statistics data.
  145. //
  146. // There is a concern with any hash table about
  147. // poor hashing keys and poor performance. The
  148. // statistics monitor various data so as to allow
  149. // the performance metrics to be monitored. The
  150. // 'Fills' counter keeps track of the number of
  151. // cache fills. The 'Hits' counter monitors the
  152. // number of cache hits. The 'MaxPages' counter
  153. // is the high water mark of hash table entries.
  154. // The 'MaxTests' is the max number of compares
  155. // done while searching an entry. The 'Misses'
  156. // counter keeps track of the number of cache misses.
  157. // The 'Scans' counter monitors the number of hash
  158. // table searches. The 'Tests' counter is the
  159. // total number of tests performed while searching
  160. // for entries.
  161. //
  162. SBIT32 Fills;
  163. SBIT32 Hits;
  164. SBIT32 MaxPages;
  165. SBIT32 MaxTests;
  166. SBIT32 Misses;
  167. SBIT32 Scans;
  168. SBIT32 Tests;
  169. #endif
  170. SBIT32 Used;
  171. #ifndef ENABLE_RECURSIVE_LOCKS
  172. //
  173. // Static private data.
  174. //
  175. // It is not uncommon for developers to have some
  176. // form of bias. I dislike recursive locks so here
  177. // I introduce a TLS value to indicate whether the
  178. // current thread has a global lock. If so all
  179. // locking in the other classes is disabled.
  180. //
  181. STATIC THREAD_LOCAL_STORE LockCount;
  182. #endif
  183. public:
  184. //
  185. // Public functions.
  186. //
  187. // The translation functionality supplied by this
  188. // class is only applicable after an allocation
  189. // has been made. Hence, all of the APIs supported
  190. // relate to the need to translate an allocation
  191. // address to the host page description.
  192. //
  193. FIND
  194. (
  195. SBIT32 NewMaxHash,
  196. SBIT32 NewMaxLookAside,
  197. SBIT32 NewFindThreshold,
  198. ROCKALL *NewRockall,
  199. BOOLEAN NewResize,
  200. BOOLEAN NewThreadSafe
  201. );
  202. BOOLEAN Delete( VOID *Address,CACHE *ParentCache );
  203. VOID DeleteFromFindList( PAGE *Page );
  204. BOOLEAN Details
  205. (
  206. VOID *Address,
  207. SEARCH_PAGE *Details,
  208. CACHE *ParentCache,
  209. SBIT32 *Size
  210. );
  211. PAGE *FindPage( VOID *Address,CACHE *ParentCache );
  212. VOID InsertInFindList( PAGE *Page );
  213. BOOLEAN KnownArea( VOID *Address,CACHE *ParentCache );
  214. VOID ReleaseFindShareLockAndUpdate
  215. (
  216. VOID *Address,
  217. PAGE *Page,
  218. SBIT32 Version
  219. );
  220. BOOLEAN Walk
  221. (
  222. BOOLEAN *Active,
  223. VOID **Address,
  224. CACHE *ParentCache,
  225. SBIT32 *Size
  226. );
  227. VOID UpdateFind
  228. (
  229. BIT32 NewMaxAddressMask,
  230. BIT32 NewMinAddressMask
  231. );
  232. ~FIND( VOID );
  233. //
  234. // Public inline functions.
  235. //
  236. // Although this class is perhaps the most self
  237. // contained. Nonetheless, there is still lots
  238. // of situations when other classes need to
  239. // interact and get information about the current
  240. // situation.
  241. //
  242. INLINE VOID ClaimFindExclusiveLock( VOID )
  243. {
  244. if ( (ThreadSafe) && (GetLockCount() == 0) )
  245. { Sharelock.ClaimExclusiveLock(); }
  246. }
  247. INLINE VOID ClaimFindShareLock( VOID )
  248. {
  249. if ( (ThreadSafe) && (GetLockCount() == 0) )
  250. { Sharelock.ClaimShareLock(); }
  251. }
  252. INLINE VOID DeleteAll( VOID )
  253. { LookAsideActions = 0; }
  254. INLINE VOID ReleaseFindExclusiveLock( VOID )
  255. {
  256. if ( (ThreadSafe) && (GetLockCount() == 0) )
  257. { Sharelock.ReleaseExclusiveLock(); }
  258. }
  259. INLINE VOID ReleaseFindShareLock( VOID )
  260. {
  261. if ( (ThreadSafe) && (GetLockCount() == 0) )
  262. { Sharelock.ReleaseShareLock(); }
  263. }
  264. //
  265. // Static public inline functions.
  266. //
  267. // There is a strong case for removing the lock
  268. // count functionality from this class. However,
  269. // as it consists of a single declaration and the
  270. // following inline functions I have not been
  271. // driven to fix this yet. Maybe some day.
  272. //
  273. #ifndef ENABLE_RECURSIVE_LOCKS
  274. STATIC INLINE VOID DecrementLockCount( VOID )
  275. {
  276. LockCount.SetPointer
  277. (
  278. ((VOID*) (((SBIT32) LockCount.GetPointer()) - 1))
  279. );
  280. }
  281. STATIC INLINE SBIT32 GetLockCount( VOID )
  282. { return ((SBIT32) LockCount.GetPointer()); }
  283. STATIC INLINE VOID IncrementLockCount( VOID )
  284. {
  285. LockCount.SetPointer
  286. (
  287. ((VOID*) (((SBIT32) LockCount.GetPointer()) + 1))
  288. );
  289. }
  290. #else
  291. STATIC INLINE VOID DecrementLockCount( VOID )
  292. { /* void */ }
  293. STATIC INLINE SBIT32 GetLockCount( VOID )
  294. { return 0; }
  295. STATIC INLINE VOID IncrementLockCount( VOID )
  296. { /* void */ }
  297. #endif
  298. #ifdef ENABLE_HEAP_STATISTICS
  299. //
  300. // Public inline statistic functions.
  301. //
  302. // The statistics are typically provided in
  303. // debug builds to provide good information
  304. // about allocation patterns.
  305. //
  306. INLINE SBIT32 AverageHashLength( VOID )
  307. { return (Tests / ((Scans > 0) ? Scans : 1)); }
  308. INLINE SBIT32 CacheFills( VOID )
  309. { return Fills; }
  310. INLINE SBIT32 CacheHits( VOID )
  311. { return Hits; }
  312. INLINE SBIT32 CacheMisses( VOID )
  313. { return Misses; }
  314. INLINE SBIT32 MaxHashLength( VOID )
  315. { return MaxTests; }
  316. INLINE SBIT32 MaxHashSize( VOID )
  317. { return MaxHash; }
  318. INLINE SBIT32 MaxLookAsideSize( VOID )
  319. { return MaxLookAside; }
  320. INLINE SBIT32 MaxUsage( VOID )
  321. { return ((MaxPages * 100) / MaxHash); }
  322. INLINE SBIT32 TotalScans( VOID )
  323. { return Scans; }
  324. #endif
  325. private:
  326. //
  327. // Private functions.
  328. //
  329. // Although the hashed lookup functionality is
  330. // externally visable the look aside cache is
  331. // hidden from view along with the ability to
  332. // resize the hash table.
  333. //
  334. BOOLEAN FindLookAside( VOID *Address,PAGE **Page );
  335. VOID ResizeHashTable( VOID );
  336. //
  337. // Private inline functions.
  338. //
  339. // Although I am not keen on code in the headers
  340. // certain functions are so small or so hot that
  341. // I have to submit to the desire to do it.
  342. //
  343. INLINE VOID ChangeToExclusiveLock( VOID )
  344. {
  345. if ( (ThreadSafe) && (GetLockCount() == 0) )
  346. { Sharelock.ChangeSharedLockToExclusiveLock(); }
  347. }
  348. INLINE LIST *FindHashHead( VOID *Address )
  349. {
  350. REGISTER BIT32 Value = (((BIT32) Address) * 2964557531);
  351. return (& Hash[ ((Value >> HashShift) & HashMask) ]);
  352. }
  353. INLINE LOOK_ASIDE *FindLookAsideHead( VOID *Address )
  354. {
  355. REGISTER BIT32 Value = (((BIT32) Address) * 2964557531);
  356. return (& LookAside[ ((Value >> LookAsideShift) & LookAsideMask) ]);
  357. }
  358. //
  359. // Disabled operations.
  360. //
  361. // All copy constructors and class assignment
  362. // operations are disabled.
  363. //
  364. FIND( CONST FIND & Copy );
  365. VOID operator=( CONST FIND & Copy );
  366. };
  367. #endif