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.

942 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,PrivateFind,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 VOID *Address = Current -> Address;
  560. REGISTER PAGE *Page = Current -> Page;
  561. //
  562. // It may see like a waste of time to batch up all
  563. // the deletions. Why not do them as they arrive.
  564. // There are a number of reasons. The deletes can
  565. // be recycled, batchs of deletes is faster than
  566. // single deletes (due to cache effects) and so on.
  567. //
  568. if
  569. (
  570. (Current -> Version == Page -> GetVersion())
  571. &&
  572. (Page -> FindPage( Address,& Details,PrivateFind,False ) != NULL)
  573. &&
  574. (Page -> Delete( & Details ))
  575. )
  576. { (*Deleted) ++; }
  577. }
  578. return ((*Deleted) == Size);
  579. }
  580. /********************************************************************/
  581. /* */
  582. /* Multiple memory allocations. */
  583. /* */
  584. /* We need to make a multiple memory allocation from this */
  585. /* bucket so walk the bucket list allocating any available */
  586. /* space and return it to the caller. */
  587. /* */
  588. /********************************************************************/
  589. BOOLEAN BUCKET::MultipleNew
  590. (
  591. SBIT32 *Actual,
  592. VOID *Array[],
  593. SBIT32 Requested
  594. )
  595. {
  596. //
  597. // Zero the count of allocated elements.
  598. //
  599. (*Actual) = 0;
  600. //
  601. // We walk the sorted list of pages with available
  602. // allocations searching for elements to allocate.
  603. //
  604. do
  605. {
  606. REGISTER PAGE *Page;
  607. REGISTER PAGE *NextPage;
  608. //
  609. // Walk the bucket list looking for any available
  610. // free space.
  611. //
  612. for
  613. (
  614. Page = (PAGE::FirstInBucketList( & BucketList ));
  615. ! Page -> EndOfBucketList();
  616. Page = NextPage
  617. )
  618. {
  619. REGISTER SBIT32 ActualSize = (Page -> GetPageSize());
  620. //
  621. // Lets find the next page now as the current
  622. // bucket may be removed from the bucket list
  623. // by the following allocation call.
  624. //
  625. NextPage = Page -> NextInBucketList();
  626. //
  627. // We allow the page size to be dynamically
  628. // modified to support a variety of wierd
  629. // data layouts for BBT. If the current page
  630. // is not the standard size then skip it.
  631. //
  632. if ( (ActualSize == NoSize) || (ActualSize == PageSize) )
  633. {
  634. //
  635. // We try allocate all the space we need
  636. // from each page in the bucket list. If
  637. // the page has enough space we can exit
  638. // early if not we go round the loop and
  639. // try the next page.
  640. //
  641. if ( Page -> MultipleNew( Actual,Array,Requested ) )
  642. { return True; }
  643. }
  644. }
  645. }
  646. while
  647. (
  648. NewPage -> CreatePage( (CACHE*) this )
  649. !=
  650. ((PAGE*) AllocationFailure)
  651. );
  652. //
  653. // We see if we managed to allocate all the elements
  654. // we wanted. If so we are happy and we can get out
  655. // of here.
  656. //
  657. if ( (*Actual) < Requested )
  658. {
  659. //
  660. // We see if we managed to allocate any elements
  661. // at all. If not we fail the request.
  662. //
  663. if ( (*Actual) > 0 )
  664. {
  665. REGISTER SBIT32 Count;
  666. REGISTER SBIT32 Delta = ((Requested) - (*Actual));
  667. //
  668. // We are very naughty when we allocate multiple
  669. // elements in that we put them in the array in
  670. // reverse order. The logic is that this is just
  671. // what we want when we allocate out of the cache.
  672. // However, if we are unable to allocate all the
  673. // elements we needed then we have to move the
  674. // pointers down to the base of the array.
  675. //
  676. for ( Count=0;Count < (*Actual);Count ++ )
  677. { Array[ Count ] = Array[ (Count + Delta) ]; }
  678. }
  679. else
  680. { return False; }
  681. }
  682. return True;
  683. }
  684. /********************************************************************/
  685. /* */
  686. /* Memory allocation. */
  687. /* */
  688. /* We need to make a new memory allocation from this bucket */
  689. /* so search the page list of available space and return a */
  690. /* free element. */
  691. /* */
  692. /********************************************************************/
  693. VOID *BUCKET::New( BOOLEAN SubDivided,SBIT32 NewSize )
  694. {
  695. do
  696. {
  697. REGISTER PAGE *Page;
  698. //
  699. // Walk the bucket list looking for any available
  700. // free space.
  701. //
  702. for
  703. (
  704. Page = (PAGE::FirstInBucketList( & BucketList ));
  705. ! Page -> EndOfBucketList();
  706. Page = Page -> NextInBucketList()
  707. )
  708. {
  709. REGISTER SBIT32 ActualSize = (Page -> GetPageSize());
  710. //
  711. // We allow the page size to be dynamically
  712. // modified to support a variety of wierd
  713. // data layouts for BBT. If the current page
  714. // is not the correct size then skip it.
  715. //
  716. if
  717. (
  718. (ActualSize == NoSize)
  719. ||
  720. (ActualSize == ((NewSize == NoSize) ? PageSize : NewSize))
  721. )
  722. {
  723. //
  724. // We know that any page that appears in
  725. // the bucket list will have at least one
  726. // free element available. So if we find
  727. // that the bucket list a suitable page
  728. // then we know that we can allocate something.
  729. //
  730. return (Page -> New( SubDivided ));
  731. }
  732. }
  733. }
  734. while
  735. (
  736. NewPage -> CreatePage( ((CACHE*) this),NewSize )
  737. !=
  738. ((PAGE*) AllocationFailure)
  739. );
  740. //
  741. // We were unable to find anything we could allocate
  742. // so fail the request.
  743. //
  744. return ((VOID*) AllocationFailure);
  745. }
  746. /********************************************************************/
  747. /* */
  748. /* Release free space. */
  749. /* */
  750. /* We sometimes do not release free space from a bucket as */
  751. /* returning it to the operating system and getting it again */
  752. /* later is very expensive. Here we flush any free space we */
  753. /* have aquired over the user supplied limit. */
  754. /* */
  755. /********************************************************************/
  756. VOID BUCKET::ReleaseSpace( SBIT32 MaxActivePages )
  757. {
  758. REGISTER SBIT32 Current = ActivePages;
  759. //
  760. // We only bother to try to trim the number of
  761. // active pages if we are over the limit.
  762. //
  763. if ( Current > MaxActivePages )
  764. {
  765. REGISTER PAGE *NextPage;
  766. REGISTER PAGE *Page;
  767. //
  768. // Walk the backwards along the bucket list
  769. // and delete the highest addressed free pages
  770. // if we are over the limit.
  771. //
  772. for
  773. (
  774. Page = (PAGE::LastInBucketList( & BucketList ));
  775. (Current > MaxActivePages)
  776. &&
  777. (! Page -> EndOfBucketList());
  778. Page = NextPage
  779. )
  780. {
  781. //
  782. // We are walking backwards down the bucket
  783. // list looking for empty pages to delete.
  784. // However, if we find a page we can remove
  785. // it will be automatically removed from the
  786. // list so we need to get the next pointer
  787. // before this happens.
  788. //
  789. NextPage = Page -> PreviousInBucketList();
  790. //
  791. // We can only release a page if it is empty
  792. // if not we must skip it.
  793. //
  794. if ( Page -> Empty() )
  795. {
  796. Current --;
  797. DeletePage( Page );
  798. }
  799. }
  800. }
  801. }
  802. /********************************************************************/
  803. /* */
  804. /* Update the bucket information. */
  805. /* */
  806. /* When we create the bucket there is some information that */
  807. /* is not available. Here we update the bucket to make sure */
  808. /* it has all the data we need. */
  809. /* */
  810. /********************************************************************/
  811. VOID BUCKET::UpdateBucket
  812. (
  813. HEAP *NewHeap,
  814. NEW_PAGE *NewPages,
  815. CACHE *NewParentCache,
  816. FIND *NewPrivateFind,
  817. FIND *NewPublicFind
  818. )
  819. {
  820. REGISTER SBIT16 NewSizeKey = (NewPages -> FindSizeKey( NumberOfElements ));
  821. //
  822. // We compute and verify the size key to make sure
  823. // it is suitable for all the pages that we will
  824. // create after the heap constructor is completed.
  825. //
  826. if ( NewSizeKey != NoSizeKey )
  827. {
  828. //
  829. // Update the size key and the connections.
  830. //
  831. SizeKey = NewSizeKey;
  832. UpdateConnections
  833. (
  834. NewHeap,
  835. NewPages,
  836. NewParentCache,
  837. NewPrivateFind,
  838. NewPublicFind
  839. );
  840. }
  841. else
  842. { Failure( "Bucket can't get a size key in UpdateBucket" ); }
  843. }
  844. /********************************************************************/
  845. /* */
  846. /* Class destructor. */
  847. /* */
  848. /* Destory the allocation bucket. */
  849. /* */
  850. /********************************************************************/
  851. BUCKET::~BUCKET( VOID )
  852. { /* void */ }