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.

939 lines
32 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 for 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 that is not required is simply omitted. */
  22. /* */
  23. /********************************************************************/
  24. #include "HeapPCH.hpp"
  25. #include "Bucket.hpp"
  26. #include "Cache.hpp"
  27. #include "Heap.hpp"
  28. /********************************************************************/
  29. /* */
  30. /* Constants local to the class. */
  31. /* */
  32. /* The constants supplied here relate the compuation of the */
  33. /* current active page address range. */
  34. /* */
  35. /********************************************************************/
  36. CONST SBIT32 HighestAddress = -1;
  37. /********************************************************************/
  38. /* */
  39. /* Class constructor. */
  40. /* */
  41. /* Create a new allocation bucket and prepare it for use. */
  42. /* We need to be sure to carefully check everything we have */
  43. /* been supplied as it has come indirectly from the user. */
  44. /* */
  45. /********************************************************************/
  46. BUCKET::BUCKET
  47. (
  48. SBIT32 NewAllocationSize,
  49. SBIT32 NewChunkSize,
  50. SBIT32 NewPageSize
  51. )
  52. {
  53. //
  54. // We want to make sure that the bucket configuration
  55. // appears to make basic sense. If not we have no
  56. // alternative than to throw an expection.
  57. //
  58. if
  59. (
  60. (NewAllocationSize > 0)
  61. &&
  62. (NewChunkSize >= NewAllocationSize)
  63. &&
  64. (NewChunkSize <= NewPageSize)
  65. &&
  66. PowerOfTwo( NewPageSize )
  67. )
  68. {
  69. //
  70. // Create the bucket and prepare it for use.
  71. // Pre-compute any information we can here to
  72. // save work later.
  73. //
  74. AllocationSize = NewAllocationSize;
  75. ChunkSize = NewChunkSize;
  76. PageSize = NewPageSize;
  77. ActivePages = 0;
  78. AllocationShift = 0;
  79. ChunkShift = 0;
  80. //
  81. // Compute the optimization level from the available
  82. // bucket information. The highest level means
  83. // everything is a power of two (just shifts - yipee !!).
  84. // The next means no chunks (i.e. simple scaling), The
  85. // next means simple chunks (i.e. complex scaling).
  86. // The final alternative is to horrid to discuss.
  87. //
  88. if ( ConvertDivideToShift( AllocationSize,& AllocationShift ) )
  89. {
  90. //
  91. // If we are not using chunking we can skip the
  92. // extra compuation that is needed. We can tell
  93. // this is the case if the chunk size and the page
  94. // size match or if the chunk size is a multiple
  95. // of the allocation size.
  96. //
  97. if
  98. (
  99. (ChunkSize == PageSize)
  100. ||
  101. ((ChunkSize % AllocationSize) == 0)
  102. )
  103. {
  104. //
  105. // The best case is when we can use shifts
  106. // instead of multiply and divide.
  107. //
  108. ComputeAddressFunction = ComputeAddressBestCase;
  109. ComputeOffsetFunction = ComputeOffsetBestCase;
  110. }
  111. else
  112. {
  113. //
  114. // When we have chunks we have to do more
  115. // work invloving additional multiples and
  116. // divides. Nonetheless, we try to minimize
  117. // these as far as possible.
  118. //
  119. if ( ConvertDivideToShift( ChunkSize,& ChunkShift ) )
  120. {
  121. //
  122. // We have managed to replace some of the
  123. // multiplies and divides with shifts.
  124. //
  125. ComputeAddressFunction = ComputeAddressPoorCase;
  126. ComputeOffsetFunction = ComputeOffsetPoorCase;
  127. }
  128. else
  129. {
  130. //
  131. // We are unable to optimize this case.
  132. // These calls will really hurt.
  133. //
  134. ComputeAddressFunction = ComputeAddressWorstCase;
  135. ComputeOffsetFunction = ComputeOffsetWorstCase;
  136. }
  137. }
  138. }
  139. else
  140. {
  141. //
  142. // If we are not using chunking we can skip the
  143. // extra compuation that is needed. We can tell
  144. // this is the case if the chunk size and the page
  145. // size match or if the chunk size is a multiple
  146. // of the allocation size.
  147. //
  148. if
  149. (
  150. (ChunkSize == PageSize)
  151. ||
  152. ((ChunkSize % AllocationSize) == 0)
  153. )
  154. {
  155. //
  156. // A good case is when we can use a few
  157. // simple multiplies and divides to do simple
  158. // scaling.
  159. //
  160. ComputeAddressFunction = ComputeAddressGoodCase;
  161. ComputeOffsetFunction = ComputeOffsetGoodCase;
  162. }
  163. else
  164. {
  165. //
  166. // When we have chunks we have to do more
  167. // work invloving additional multiples and
  168. // divides. Nonetheless, we try to minimize
  169. // these as far as possible.
  170. //
  171. if ( ConvertDivideToShift( ChunkSize,& ChunkShift ) )
  172. {
  173. //
  174. // We have managed to replace some of the
  175. // multiplies and divides with shifts.
  176. //
  177. ComputeAddressFunction = ComputeAddressPoorCase;
  178. ComputeOffsetFunction = ComputeOffsetPoorCase;
  179. }
  180. else
  181. {
  182. //
  183. // We are unable to optimize this case.
  184. // These calls will really hurt.
  185. //
  186. ComputeAddressFunction = ComputeAddressWorstCase;
  187. ComputeOffsetFunction = ComputeOffsetWorstCase;
  188. }
  189. }
  190. }
  191. //
  192. // Compute all the information that will be
  193. // needed later to describe the allocation
  194. // pages.
  195. //
  196. NumberOfElements =
  197. ((SBIT16) ((PageSize / ChunkSize) * (ChunkSize / AllocationSize)));
  198. SizeOfChunks = (SBIT16)
  199. ((SBIT16) (ChunkSize / AllocationSize));
  200. SizeOfElements = (SBIT16)
  201. ((SBIT16) (((NumberOfElements-1) / OverheadBitsPerWord) + 1));
  202. SizeKey = NoSizeKey;
  203. }
  204. else
  205. { Failure( "Configuration in constructor for BUCKET" ); }
  206. }
  207. /********************************************************************/
  208. /* */
  209. /* Compute the allocation address. */
  210. /* */
  211. /* Compute the allocation address given the page address and */
  212. /* the vector offset in the page. */
  213. /* */
  214. /********************************************************************/
  215. VOID *BUCKET::ComputeAddressBestCase( CHAR *Address,SBIT32 Offset )
  216. { return ((VOID*) (Address + (Offset << AllocationShift))); }
  217. /********************************************************************/
  218. /* */
  219. /* Compute the allocation address. */
  220. /* */
  221. /* Compute the allocation address given the page address and */
  222. /* the vector offset in the page. */
  223. /* */
  224. /********************************************************************/
  225. VOID *BUCKET::ComputeAddressGoodCase( CHAR *Address,SBIT32 Offset )
  226. { return ((VOID*) (Address + (Offset * AllocationSize))); }
  227. /********************************************************************/
  228. /* */
  229. /* Compute the allocation address. */
  230. /* */
  231. /* Compute the allocation address given the page address and */
  232. /* the vector offset in the page. */
  233. /* */
  234. /********************************************************************/
  235. VOID *BUCKET::ComputeAddressPoorCase( CHAR *Address,SBIT32 Offset )
  236. {
  237. REGISTER SBIT32 ChunkNumber = (Offset / SizeOfChunks);
  238. REGISTER SBIT32 ChunkOffset = (ChunkNumber * SizeOfChunks);
  239. REGISTER SBIT32 AllocationNumber = (Offset - ChunkOffset);
  240. return
  241. ((VOID*)
  242. (
  243. Address
  244. +
  245. (ChunkNumber << ChunkShift)
  246. +
  247. (AllocationNumber * AllocationSize)
  248. )
  249. );
  250. }
  251. /********************************************************************/
  252. /* */
  253. /* Compute the allocation address. */
  254. /* */
  255. /* Compute the allocation address given the page address and */
  256. /* the vector offset in the page. */
  257. /* */
  258. /********************************************************************/
  259. VOID *BUCKET::ComputeAddressWorstCase( CHAR *Address,SBIT32 Offset )
  260. {
  261. REGISTER SBIT32 ChunkNumber = (Offset / SizeOfChunks);
  262. REGISTER SBIT32 ChunkOffset = (ChunkNumber * SizeOfChunks);
  263. REGISTER SBIT32 AllocationNumber = (Offset - ChunkOffset);
  264. return
  265. ((VOID*)
  266. (
  267. Address
  268. +
  269. (ChunkNumber * ChunkSize)
  270. +
  271. (AllocationNumber * AllocationSize)
  272. )
  273. );
  274. }
  275. /********************************************************************/
  276. /* */
  277. /* Compute the bit vector offset. */
  278. /* */
  279. /* Compute the bit vector offset given the address of the */
  280. /* memory allocation in the page. */
  281. /* */
  282. /********************************************************************/
  283. SBIT32 BUCKET::ComputeOffsetBestCase( SBIT32 Displacement,BOOLEAN *Found )
  284. {
  285. REGISTER SBIT32 ArrayOffset = (Displacement >> AllocationShift);
  286. (*Found) = (Displacement == (ArrayOffset << AllocationShift));
  287. #ifdef DEBUGGING
  288. if ( ArrayOffset >= NumberOfElements )
  289. { Failure( "Array offset in ComputeOffsetBestCase" ); }
  290. #endif
  291. return ArrayOffset;
  292. }
  293. /********************************************************************/
  294. /* */
  295. /* Compute the bit vector offset. */
  296. /* */
  297. /* Compute the bit vector offset given the address of the */
  298. /* memory allocation in the page. */
  299. /* */
  300. /********************************************************************/
  301. SBIT32 BUCKET::ComputeOffsetGoodCase( SBIT32 Displacement,BOOLEAN *Found )
  302. {
  303. REGISTER SBIT32 ArrayOffset = (Displacement / AllocationSize);
  304. (*Found) = (Displacement == (ArrayOffset * AllocationSize));
  305. #ifdef DEBUGGING
  306. if ( ArrayOffset >= NumberOfElements )
  307. { Failure( "Array offset in ComputeOffsetGoodCase" ); }
  308. #endif
  309. return ArrayOffset;
  310. }
  311. /********************************************************************/
  312. /* */
  313. /* Compute the bit vector offset. */
  314. /* */
  315. /* Compute the bit vector offset given the address of the */
  316. /* memory allocation in the page. */
  317. /* */
  318. /********************************************************************/
  319. SBIT32 BUCKET::ComputeOffsetPoorCase( SBIT32 Displacement,BOOLEAN *Found )
  320. {
  321. REGISTER SBIT32 ArrayOffset;
  322. REGISTER SBIT32 ChunkNumber = (Displacement >> ChunkShift);
  323. REGISTER SBIT32 ChunkAddress = (ChunkNumber << ChunkShift);
  324. REGISTER SBIT32 ChunkOffset = (Displacement - ChunkAddress);
  325. REGISTER SBIT32 AllocationNumber = (ChunkOffset / AllocationSize);
  326. ArrayOffset = ((ChunkNumber * SizeOfChunks) + AllocationNumber);
  327. (*Found) =
  328. (
  329. (Displacement)
  330. ==
  331. (ChunkAddress + (AllocationNumber * AllocationSize))
  332. );
  333. #ifdef DEBUGGING
  334. if ( ArrayOffset >= NumberOfElements )
  335. { Failure( "Array offset in ComputeOffsetPoorCase" ); }
  336. #endif
  337. return ArrayOffset;
  338. }
  339. /********************************************************************/
  340. /* */
  341. /* Compute the bit vector offset. */
  342. /* */
  343. /* Compute the bit vector offset given the address of the */
  344. /* memory allocation in the page. */
  345. /* */
  346. /********************************************************************/
  347. SBIT32 BUCKET::ComputeOffsetWorstCase( SBIT32 Displacement,BOOLEAN *Found )
  348. {
  349. REGISTER SBIT32 ArrayOffset;
  350. REGISTER SBIT32 ChunkNumber = (Displacement / ChunkSize);
  351. REGISTER SBIT32 ChunkAddress = (ChunkNumber * ChunkSize);
  352. REGISTER SBIT32 ChunkOffset = (Displacement - ChunkAddress);
  353. REGISTER SBIT32 AllocationNumber = (ChunkOffset / AllocationSize);
  354. ArrayOffset = ((ChunkNumber * SizeOfChunks) + AllocationNumber);
  355. (*Found) =
  356. (
  357. (Displacement)
  358. ==
  359. (ChunkAddress + (AllocationNumber * AllocationSize))
  360. );
  361. #ifdef DEBUGGING
  362. if ( ArrayOffset >= NumberOfElements )
  363. { Failure( "Array offset in ComputeOffsetWorstCase" ); }
  364. #endif
  365. return ArrayOffset;
  366. }
  367. /********************************************************************/
  368. /* */
  369. /* Delete a memory allocation. */
  370. /* */
  371. /* We need to delete a single memory allocation from a bucket. */
  372. /* We do this by passing the request on to the page. */
  373. /* */
  374. /********************************************************************/
  375. BOOLEAN BUCKET::Delete( VOID *Address,PAGE *Page,SBIT32 Version )
  376. {
  377. AUTO SEARCH_PAGE Details;
  378. //
  379. // When we delete an allocation we need to ensure
  380. // the page has not radically changed since we found
  381. // it. Hence, we compare the current page version
  382. // number with the one we found earlier. If all is
  383. // well we get the details relating to the allocation
  384. // and then delete it.
  385. //
  386. return
  387. (
  388. ((Page -> GetVersion()) == Version)
  389. &&
  390. (Page -> FindPage( Address,& Details,False ) != NULL)
  391. &&
  392. (Page -> Delete( & Details ))
  393. );
  394. }
  395. /********************************************************************/
  396. /* */
  397. /* Delete a page from the bucket list. */
  398. /* */
  399. /* When a page becomes full it is removed from the bucket list */
  400. /* so it will be no longer inspected when looking for free space. */
  401. /* */
  402. /********************************************************************/
  403. VOID BUCKET::DeleteFromBucketList( PAGE *Page )
  404. {
  405. //
  406. // We keep track of the number of active pages on the
  407. // bucket list. This helps us when we need to scan the
  408. // bucket list for some reason later.
  409. //
  410. if ( (-- ActivePages) >= 0 )
  411. {
  412. //
  413. // Delete the page from the bucket list as it is
  414. // no longer needed. There are two cases when this
  415. // happens. When the page is full and when the page
  416. // is about to be deleted.
  417. //
  418. Page -> DeleteFromBucketList( & BucketList );
  419. //
  420. // Compute the highest address on the first page. We
  421. // use this information to figure out whether to
  422. // recycle an allocation or pass it along for deletion
  423. // in the cache.
  424. //
  425. Page = (PAGE::FirstInBucketList( & BucketList ));
  426. if ( ! Page -> EndOfBucketList() )
  427. {
  428. CurrentPage =
  429. (
  430. ((VOID*) (((LONG) Page -> GetAddress()) + (PageSize - 1)))
  431. );
  432. }
  433. else
  434. { CurrentPage = ((VOID*) HighestAddress); }
  435. }
  436. else
  437. { Failure( "Active page count in DeleteFromBucketList" ); }
  438. }
  439. /********************************************************************/
  440. /* */
  441. /* Insert a page into the bucket list. */
  442. /* */
  443. /* When a page is created or when it changes from being full */
  444. /* to having at least one free slot it is added to the bucket */
  445. /* list so that it can be used to allocate space. */
  446. /* */
  447. /********************************************************************/
  448. VOID BUCKET::InsertInBucketList( PAGE *Page )
  449. {
  450. //
  451. // We keep track of the number of active pages on the
  452. // bucket list. This helps us when we need to scan the
  453. // bucket list for some reason later.
  454. //
  455. ActivePages ++;
  456. //
  457. // We insert pages into the list in ascending address
  458. // order. This ensures that we always allocate the
  459. // lowest addresses first. This is done to try to keep
  460. // the working set small and compact.
  461. //
  462. if ( ! BucketList.EndOfList() )
  463. {
  464. REGISTER VOID *Address = (Page -> GetAddress());
  465. REGISTER PAGE *Last = (Page -> LastInBucketList( & BucketList ));
  466. //
  467. // We are about to walk the entire page list
  468. // trying to find where to insert this page.
  469. // Lets see if the page needs to be inserted
  470. // at the end of the list. If so have saved
  471. // ourseleves a lot of work and we can exit
  472. // early.
  473. //
  474. if ( Address < (Last -> GetAddress()) )
  475. {
  476. REGISTER PAGE *Current;
  477. //
  478. // Well it looks like we need to walk along
  479. // the entire page list to find the correct
  480. // place to insert this element.
  481. //
  482. for
  483. (
  484. Current = (Page -> FirstInBucketList( & BucketList ));
  485. ! Current -> EndOfBucketList();
  486. Current = Current -> NextInBucketList()
  487. )
  488. {
  489. //
  490. // While the current address is lower
  491. // than ours we need to keep on walking.
  492. //
  493. if ( Address < (Current -> GetAddress()) )
  494. {
  495. //
  496. // We have found the spot so insert
  497. // the bucket just before the current
  498. // bucket.
  499. //
  500. Current -> InsertBeforeInBucketList( & BucketList,Page );
  501. break;
  502. }
  503. }
  504. }
  505. else
  506. {
  507. //
  508. // The page has the highest address so insert
  509. // it at the end of the list.
  510. //
  511. Last -> InsertAfterInBucketList( & BucketList,Page );
  512. }
  513. }
  514. else
  515. { Page -> InsertInBucketList( & BucketList ); }
  516. //
  517. // Compute the highest address on the first page. We can
  518. // use this information to figure out whether to recycle an
  519. // allocation or pass it along for deletion in the cache.
  520. //
  521. Page = (PAGE::FirstInBucketList( & BucketList ));
  522. CurrentPage =
  523. (
  524. ((VOID*) (((LONG) Page -> GetAddress()) + (PageSize - 1)))
  525. );
  526. }
  527. /********************************************************************/
  528. /* */
  529. /* Multiple memory deallocations. */
  530. /* */
  531. /* When the delete cache becomes full we complete any pending */
  532. /* delete requests. We also flush the delete cache when if */
  533. /* we need to allocate additional memory unless recycling is */
  534. /* enabled in which case we just steal it directly from the */
  535. /* delete cache. */
  536. /* */
  537. /********************************************************************/
  538. BOOLEAN BUCKET::MultipleDelete
  539. (
  540. ADDRESS_AND_PAGE *Array,
  541. SBIT32 *Deleted,
  542. SBIT32 Size
  543. )
  544. {
  545. AUTO SEARCH_PAGE Details;
  546. REGISTER SBIT32 Count;
  547. //
  548. // Zero the count of deleted items.
  549. //
  550. (*Deleted) = 0;
  551. //
  552. // Delete each element one at a time. We would love to
  553. // delete them all at once but we haven't got a clue where
  554. // they have come from so we have to do it one at a time.
  555. //
  556. for ( Count=0;Count < Size;Count ++ )
  557. {
  558. REGISTER ADDRESS_AND_PAGE *Current = & Array[ Count ];
  559. REGISTER PAGE *Page = Current -> Page;
  560. //
  561. // It may see like a waste of time to batch up all
  562. // the deletions. Why not do them as they arrive.
  563. // There are a number of reasons. The deletes can
  564. // be recycled, batchs of deletes is faster than
  565. // single deletes (due to cache effects) and so on.
  566. //
  567. if
  568. (
  569. (Current -> Version == Page -> GetVersion())
  570. &&
  571. (Page -> FindPage( Current -> Address,& Details,False ) != NULL)
  572. &&
  573. (Page -> Delete( & Details ))
  574. )
  575. { (*Deleted) ++; }
  576. }
  577. return ((*Deleted) == Size);
  578. }
  579. /********************************************************************/
  580. /* */
  581. /* Multiple memory allocations. */
  582. /* */
  583. /* We need to make a multiple memory allocation from this */
  584. /* bucket so walk the bucket list allocating any available */
  585. /* space and return it to the caller. */
  586. /* */
  587. /********************************************************************/
  588. BOOLEAN BUCKET::MultipleNew
  589. (
  590. SBIT32 *Actual,
  591. VOID *Array[],
  592. SBIT32 Requested
  593. )
  594. {
  595. //
  596. // Zero the count of allocated elements.
  597. //
  598. (*Actual) = 0;
  599. //
  600. // We walk the sorted list of pages with available
  601. // allocations searching for elements to allocate.
  602. //
  603. do
  604. {
  605. REGISTER PAGE *Page;
  606. REGISTER PAGE *NextPage;
  607. //
  608. // Walk the bucket list looking for any available
  609. // free space.
  610. //
  611. for
  612. (
  613. Page = (PAGE::FirstInBucketList( & BucketList ));
  614. ! Page -> EndOfBucketList();
  615. Page = NextPage
  616. )
  617. {
  618. REGISTER SBIT32 ActualSize = (Page -> GetPageSize());
  619. //
  620. // Lets find the next page now as the current
  621. // bucket may be removed from the bucket list
  622. // by the following allocation call.
  623. //
  624. NextPage = Page -> NextInBucketList();
  625. //
  626. // We allow the page size to be dynamically
  627. // modified to support a variety of wierd
  628. // data layouts for BBT. If the current page
  629. // is not the standard size then skip it.
  630. //
  631. if ( (ActualSize == NoSize) || (ActualSize == PageSize) )
  632. {
  633. //
  634. // We try allocate all the space we need
  635. // from each page in the bucket list. If
  636. // the page has enough space we can exit
  637. // early if not we go round the loop and
  638. // try the next page.
  639. //
  640. if ( Page -> MultipleNew( Actual,Array,Requested ) )
  641. { return True; }
  642. }
  643. }
  644. }
  645. while
  646. (
  647. NewPage -> CreatePage( (CACHE*) this )
  648. !=
  649. ((PAGE*) AllocationFailure)
  650. );
  651. //
  652. // We see if we managed to allocate all the elements
  653. // we wanted. If so we are happy and we can get out
  654. // of here.
  655. //
  656. if ( (*Actual) < Requested )
  657. {
  658. //
  659. // We see if we managed to allocate any elements
  660. // at all. If not we fail the request.
  661. //
  662. if ( (*Actual) > 0 )
  663. {
  664. REGISTER SBIT32 Count;
  665. REGISTER SBIT32 Delta = ((Requested) - (*Actual));
  666. //
  667. // We are very naughty when we allocate multiple
  668. // elements in that we put them in the array in
  669. // reverse order. The logic is that this is just
  670. // what we want when we allocate out of the cache.
  671. // However, if we are unable to allocate all the
  672. // elements we needed then we have to move the
  673. // pointers down to the base of the array.
  674. //
  675. for ( Count=0;Count < (*Actual);Count ++ )
  676. { Array[ Count ] = Array[ (Count + Delta) ]; }
  677. }
  678. else
  679. { return False; }
  680. }
  681. return True;
  682. }
  683. /********************************************************************/
  684. /* */
  685. /* Memory allocation. */
  686. /* */
  687. /* We need to make a new memory allocation from this bucket */
  688. /* so search the page list of available space and return a */
  689. /* free element. */
  690. /* */
  691. /********************************************************************/
  692. VOID *BUCKET::New( BOOLEAN SubDivided,SBIT32 NewSize )
  693. {
  694. do
  695. {
  696. REGISTER PAGE *Page;
  697. //
  698. // Walk the bucket list looking for any available
  699. // free space.
  700. //
  701. for
  702. (
  703. Page = (PAGE::FirstInBucketList( & BucketList ));
  704. ! Page -> EndOfBucketList();
  705. Page = Page -> NextInBucketList()
  706. )
  707. {
  708. REGISTER SBIT32 ActualSize = (Page -> GetPageSize());
  709. //
  710. // We allow the page size to be dynamically
  711. // modified to support a variety of wierd
  712. // data layouts for BBT. If the current page
  713. // is not the correct size then skip it.
  714. //
  715. if
  716. (
  717. (ActualSize == NoSize)
  718. ||
  719. (ActualSize == ((NewSize == NoSize) ? PageSize : NewSize))
  720. )
  721. {
  722. //
  723. // We know that any page that appears in
  724. // the bucket list will have at least one
  725. // free element available. So if we find
  726. // that the bucket list a suitable page
  727. // then we know that we can allocate something.
  728. //
  729. return (Page -> New( SubDivided ));
  730. }
  731. }
  732. }
  733. while
  734. (
  735. NewPage -> CreatePage( ((CACHE*) this),NewSize )
  736. !=
  737. ((PAGE*) AllocationFailure)
  738. );
  739. //
  740. // We were unable to find anything we could allocate
  741. // so fail the request.
  742. //
  743. return ((VOID*) AllocationFailure);
  744. }
  745. /********************************************************************/
  746. /* */
  747. /* Release free space. */
  748. /* */
  749. /* We sometimes do not release free space from a bucket as */
  750. /* returning it to the operating system and getting it again */
  751. /* later is very expensive. Here we flush any free space we */
  752. /* have aquired over the user supplied limit. */
  753. /* */
  754. /********************************************************************/
  755. VOID BUCKET::ReleaseSpace( SBIT32 MaxActivePages )
  756. {
  757. REGISTER SBIT32 Current = ActivePages;
  758. //
  759. // We only bother to try to trim the number of
  760. // active pages if we are over the limit.
  761. //
  762. if ( Current > MaxActivePages )
  763. {
  764. REGISTER PAGE *NextPage;
  765. REGISTER PAGE *Page;
  766. //
  767. // Walk the backwards along the bucket list
  768. // and delete the highest addressed free pages
  769. // if we are over the limit.
  770. //
  771. for
  772. (
  773. Page = (PAGE::LastInBucketList( & BucketList ));
  774. (Current > MaxActivePages)
  775. &&
  776. (! Page -> EndOfBucketList());
  777. Page = NextPage
  778. )
  779. {
  780. //
  781. // We are walking backwards down the bucket
  782. // list looking for empty pages to delete.
  783. // However, if we find a page we can remove
  784. // it will be automatically removed from the
  785. // list so we need to get the next pointer
  786. // before this happens.
  787. //
  788. NextPage = Page -> PreviousInBucketList();
  789. //
  790. // We can only release a page if it is empty
  791. // if not we must skip it.
  792. //
  793. if ( Page -> Empty() )
  794. {
  795. Current --;
  796. DeletePage( Page );
  797. }
  798. }
  799. }
  800. }
  801. /********************************************************************/
  802. /* */
  803. /* Update the bucket information. */
  804. /* */
  805. /* When we create the bucket there is some information that */
  806. /* is not available. Here we update the bucket to make sure */
  807. /* it has all the data we need. */
  808. /* */
  809. /********************************************************************/
  810. VOID BUCKET::UpdateBucket
  811. (
  812. FIND *NewFind,
  813. HEAP *NewHeap,
  814. NEW_PAGE *NewPages,
  815. CACHE *NewParentCache
  816. )
  817. {
  818. REGISTER SBIT16 NewSizeKey = (NewPages -> FindSizeKey( NumberOfElements ));
  819. //
  820. // We compute and verify the size key to make sure
  821. // it is suitable for all the pages that we will
  822. // create after the heap constructor is completed.
  823. //
  824. if ( NewSizeKey != NoSizeKey )
  825. {
  826. //
  827. // Update the size key and the connections.
  828. //
  829. SizeKey = NewSizeKey;
  830. UpdateConnections
  831. (
  832. NewFind,
  833. NewHeap,
  834. NewPages,
  835. NewParentCache
  836. );
  837. }
  838. else
  839. { Failure( "Bucket can't get a size key in UpdateBucket" ); }
  840. }
  841. /********************************************************************/
  842. /* */
  843. /* Class destructor. */
  844. /* */
  845. /* Destory the allocation bucket. */
  846. /* */
  847. /********************************************************************/
  848. BUCKET::~BUCKET( VOID )
  849. { /* void */ }