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
15 KiB

  1. // Ruler
  2. // 1 2 3 4 5 6 7 8
  3. //345678901234567890123456789012345678901234567890123456789012345678901234567890
  4. /********************************************************************/
  5. /* */
  6. /* The standard layout. */
  7. /* */
  8. /* The standard layout for 'cpp' files in this code is as */
  9. /* follows: */
  10. /* */
  11. /* 1. Include files. */
  12. /* 2. Constants local to the class. */
  13. /* 3. Data structures local to the class. */
  14. /* 4. Data initializations. */
  15. /* 5. Static functions. */
  16. /* 6. Class functions. */
  17. /* */
  18. /* The constructor is typically the first function, class */
  19. /* member functions appear in alphabetical order with the */
  20. /* destructor appearing at the end of the file. Any section */
  21. /* or function this is not required is simply omitted. */
  22. /* */
  23. /********************************************************************/
  24. #include "InterfacePCH.hpp"
  25. #include "Assembly.hpp"
  26. #include "Prefetch.hpp"
  27. #include "Spinlock.hpp"
  28. #include "ZoneHeap.hpp"
  29. /********************************************************************/
  30. /* */
  31. /* Constants local to the class. */
  32. /* */
  33. /* The constants supplied here try to make the layout of the */
  34. /* the caches easier to understand and update. */
  35. /* */
  36. /********************************************************************/
  37. CONST SBIT32 AlignmentMask = (sizeof(double)-1);
  38. CONST SBIT32 FindCacheSize = 2048;
  39. CONST SBIT32 FindCacheThreshold = 0;
  40. CONST SBIT32 FindSize = 1024;
  41. CONST SBIT32 Stride1 = 1024;
  42. CONST SBIT32 Stride2 = 1024;
  43. CONST SBIT32 ZonePageSize = 4096;
  44. /********************************************************************/
  45. /* */
  46. /* The description of the heap. */
  47. /* */
  48. /* A heap is a collection of fixed sized allocation caches. */
  49. /* An allocation cache consists of an allocation size, the */
  50. /* number of pre-built allocations to cache, a chunk size and */
  51. /* a parent page size which is sub-divided to create elements */
  52. /* for this cache. A heap consists of two arrays of caches. */
  53. /* Each of these arrays has a stride (i.e. 'Stride1' and */
  54. /* 'Stride2') which is typically the smallest common factor of */
  55. /* all the allocation sizes in the array. */
  56. /* */
  57. /********************************************************************/
  58. STATIC ROCKALL::CACHE_DETAILS Caches1[] =
  59. {
  60. //
  61. // Bucket Size Of Bucket Parent
  62. // Size Cache Chunks Page Size
  63. //
  64. { 4096, 8, 65536, 65536 },
  65. { 0,0,0,0 }
  66. };
  67. STATIC ROCKALL::CACHE_DETAILS Caches2[] =
  68. {
  69. //
  70. // Bucket Size Of Bucket Parent
  71. // Size Cache Chunks Page Size
  72. //
  73. { 5120, 4, 65536, 65536 },
  74. { 6144, 4, 65536, 65536 },
  75. { 7168, 4, 65536, 65536 },
  76. { 8192, 8, 65536, 65536 },
  77. { 9216, 0, 65536, 65536 },
  78. { 10240, 0, 65536, 65536 },
  79. { 12288, 0, 65536, 65536 },
  80. { 16384, 2, 65536, 65536 },
  81. { 21504, 0, 65536, 65536 },
  82. { 32768, 0, 65536, 65536 },
  83. { 65536, 0, 65536, 65536 },
  84. { 65536, 0, 65536, 65536 },
  85. { 0,0,0,0 }
  86. };
  87. /********************************************************************/
  88. /* */
  89. /* The description bit vectors. */
  90. /* */
  91. /* All heaps keep track of allocations using bit vectors. An */
  92. /* allocation requires 2 bits to keep track of its state. The */
  93. /* following array supplies the size of the available bit */
  94. /* vectors measured in 32 bit words. */
  95. /* */
  96. /********************************************************************/
  97. STATIC int NewPageSizes[] = { 2,0 };
  98. /********************************************************************/
  99. /* */
  100. /* Static data structures. */
  101. /* */
  102. /* The static data structures are initialized and prepared for */
  103. /* use here. */
  104. /* */
  105. /********************************************************************/
  106. STATIC PREFETCH Prefetch;
  107. /********************************************************************/
  108. /* */
  109. /* Class constructor. */
  110. /* */
  111. /* The overall structure and layout of the heap is controlled */
  112. /* by the various constants and calls made in this function. */
  113. /* There is a significant amount of flexibility available to */
  114. /* a heap which can lead to them having dramatically different */
  115. /* properties. */
  116. /* */
  117. /********************************************************************/
  118. ZONE_HEAP::ZONE_HEAP
  119. (
  120. int MaxFreeSpace,
  121. bool Recycle,
  122. bool SingleImage,
  123. bool ThreadSafe
  124. ) :
  125. //
  126. // Call the constructors for the contained classes.
  127. //
  128. ROCKALL
  129. (
  130. Caches1,
  131. Caches2,
  132. FindCacheSize,
  133. FindCacheThreshold,
  134. FindSize,
  135. MaxFreeSpace,
  136. NewPageSizes,
  137. Recycle,
  138. SingleImage,
  139. Stride1,
  140. Stride2,
  141. ThreadSafe
  142. )
  143. {
  144. AUTO ZONE NewZone = { NULL,NULL };
  145. //
  146. // Setup the heap structures.
  147. //
  148. MaxSize = ZonePageSize;
  149. ThreadLocks = ThreadSafe;
  150. Zone = NewZone;
  151. }
  152. /********************************************************************/
  153. /* */
  154. /* Delete all allocations. */
  155. /* */
  156. /* Delete all the heap allocations and return all the space */
  157. /* back to the operating system. */
  158. /* */
  159. /********************************************************************/
  160. void ZONE_HEAP::DeleteAll( bool Recycle )
  161. {
  162. AUTO ZONE Update = { NULL,NULL };
  163. //
  164. // Delete all outstanding allocations.
  165. //
  166. ROCKALL::DeleteAll( Recycle );
  167. //
  168. // Delete the stale zone pointers.
  169. //
  170. WriteZone( & Update );
  171. }
  172. /********************************************************************/
  173. /* */
  174. /* Multiple memory allocations. */
  175. /* */
  176. /* We allocate by advancing a pinter down an array. This */
  177. /* is very fast but means that it can not be deleted except */
  178. /* by destroying the entire heap. */
  179. /* */
  180. /********************************************************************/
  181. bool ZONE_HEAP::MultipleNew
  182. (
  183. int *Actual,
  184. void *Array[],
  185. int Requested,
  186. int Size,
  187. int *Space,
  188. bool Zero
  189. )
  190. {
  191. //
  192. // We simply call 'New' to create each element
  193. // for a zone heap.
  194. //
  195. for ( (*Actual)=0;(*Actual) < Requested;(*Actual) ++ )
  196. {
  197. REGISTER VOID **Current = & Array[ (*Actual) ];
  198. //
  199. // Create an allocation.
  200. //
  201. (*Current) = (ZONE_HEAP::New( Size,Space,Zero ));
  202. //
  203. // Exit if there is no more space.
  204. //
  205. if ( (*Current) == NULL )
  206. { return false; }
  207. }
  208. return true;
  209. }
  210. /********************************************************************/
  211. /* */
  212. /* Memory allocation. */
  213. /* */
  214. /* We allocate by advancing a pinter down an array. This */
  215. /* is very fast but means that it can not be deleted except */
  216. /* by destroying the entire heap. */
  217. /* */
  218. /********************************************************************/
  219. void *ZONE_HEAP::New( int Size,int *Space,bool Zero )
  220. {
  221. //
  222. // We would really hope that nobody would ask
  223. // for a negative amount of memory but just to
  224. // be sure we verify that this is not the case.
  225. //
  226. if ( Size >= 0 )
  227. {
  228. AUTO SBIT32 NewSize = ((Size + AlignmentMask) & ~AlignmentMask);
  229. AUTO ZONE Original;
  230. AUTO ZONE Update;
  231. //
  232. // We would hope to create the allocation on the
  233. // first try but there is a possibility that it
  234. // may take serveral tries.
  235. do
  236. {
  237. //
  238. // Extract a copy of the current zone pointers
  239. // into local variables.
  240. //
  241. Original = Zone;
  242. Update = Original;
  243. //
  244. // We need to ensure that there is enough space
  245. // in the zone for the current allocation.
  246. //
  247. if
  248. (
  249. (Update.Start == NULL)
  250. ||
  251. ((Update.Start += NewSize) > Update.End)
  252. )
  253. {
  254. //
  255. // We do not have enough space. If the size
  256. // seems reasonable then get a new block from
  257. // Rockall. If not just pass the request along
  258. // to Rockall.
  259. //
  260. if ( NewSize <= (MaxSize / 2) )
  261. {
  262. STATIC SPINLOCK Spinlock;
  263. //
  264. // We need to create a new zone page
  265. // so claim a lock.
  266. //
  267. Spinlock.ClaimLock();
  268. //
  269. // We may find that the zone has
  270. // already been updated. If so
  271. // just exit.
  272. //
  273. if ( Update.End == Zone.End )
  274. {
  275. //
  276. // Try to allocate a new zone
  277. // block.
  278. //
  279. Update.Start = ((CHAR*) ROCKALL::New( MaxSize ));
  280. //
  281. // Verify we were able to create
  282. // a new zone page.
  283. //
  284. if ( Update.Start != NULL )
  285. { Update.End = (Update.Start + MaxSize); }
  286. else
  287. { Update.End = NULL; }
  288. //
  289. // Update the zone.
  290. //
  291. WriteZone( & Update );
  292. }
  293. //
  294. // Release the lock.
  295. //
  296. Spinlock.ReleaseLock();
  297. //
  298. // If we were unable to get more
  299. // space then exit.
  300. //
  301. if ( Update.Start == NULL )
  302. { return NULL; }
  303. }
  304. else
  305. { return (ROCKALL::New( Size,Space,Zero )); }
  306. }
  307. }
  308. while ( ! UpdateZone( & Original,& Update ) );
  309. //
  310. // Prefetch the first cache line of
  311. // the allocation if we are running
  312. // a Pentium III or better.
  313. //
  314. Prefetch.L1( ((CHAR*) Original.Start),1 );
  315. //
  316. // If the caller wants to know the real
  317. // size them we supply it.
  318. //
  319. if ( Space != NULL )
  320. { (*Space) = NewSize; }
  321. //
  322. // If we need to zero the allocation
  323. // we do it here.
  324. //
  325. if ( Zero )
  326. { ZeroMemory( Original.Start,NewSize ); }
  327. //
  328. // Exit and return the address.
  329. //
  330. return (Original.Start);
  331. }
  332. else
  333. { return NULL; }
  334. }
  335. /********************************************************************/
  336. /* */
  337. /* Update the zone. */
  338. /* */
  339. /* Ww update the zone when we do an allocation. We do this */
  340. /* atomically if there are multiple threads. */
  341. /* */
  342. /********************************************************************/
  343. bool ZONE_HEAP::UpdateZone( ZONE *Original,ZONE *Update )
  344. {
  345. //
  346. // Do we need to allow for multiple threads. If
  347. // so we need to do the update atomically. If
  348. // not then a simple assignment is fine.
  349. //
  350. if ( ThreadLocks )
  351. {
  352. REGISTER SBIT64 FinalValue =
  353. (
  354. ASSEMBLY::AtomicCompareExchange64
  355. (
  356. ((SBIT64*) & Zone),
  357. (*((SBIT64*) Update)),
  358. (*((SBIT64*) Original))
  359. )
  360. );
  361. return (FinalValue == (*((SBIT64*) Original)));
  362. }
  363. else
  364. {
  365. Zone = (*Update);
  366. return True;
  367. }
  368. }
  369. /********************************************************************/
  370. /* */
  371. /* Class destructor. */
  372. /* */
  373. /* Destory the heap. */
  374. /* */
  375. /********************************************************************/
  376. ZONE_HEAP::~ZONE_HEAP( VOID )
  377. { /* void */ }