aboutsummaryrefslogtreecommitdiffstats
path: root/mps/code
diff options
context:
space:
mode:
authorGareth Rees2013-05-20 20:47:41 +0100
committerGareth Rees2013-05-20 20:47:41 +0100
commit48e439d624610276b516c353d2f2e9b61c36126a (patch)
tree7ade91096541bf6b2d609f04ed756ecd6f9fc949 /mps/code
parent1912c062b5e07393d728f31c692c07841d6d1313 (diff)
downloademacs-48e439d624610276b516c353d2f2e9b61c36126a.tar.gz
emacs-48e439d624610276b516c353d2f2e9b61c36126a.zip
Use the new cbs, abq and range interfaces to avoid re-entrancy problems in callbacks.
Copied from Perforce Change: 182017 ServerID: perforce.ravenbrook.com
Diffstat (limited to 'mps/code')
-rw-r--r--mps/code/poolmv2.c302
1 files changed, 195 insertions, 107 deletions
diff --git a/mps/code/poolmv2.c b/mps/code/poolmv2.c
index c99a0f0b225..a87dab377ed 100644
--- a/mps/code/poolmv2.c
+++ b/mps/code/poolmv2.c
@@ -15,6 +15,7 @@
15#include "abq.h" 15#include "abq.h"
16#include "cbs.h" 16#include "cbs.h"
17#include "meter.h" 17#include "meter.h"
18#include "range.h"
18 19
19SRCID(poolmv2, "$Id$"); 20SRCID(poolmv2, "$Id$");
20 21
@@ -27,6 +28,7 @@ SRCID(poolmv2, "$Id$");
27/* Private prototypes */ 28/* Private prototypes */
28 29
29typedef struct MVTStruct *MVT; 30typedef struct MVTStruct *MVT;
31
30static Res MVTInit(Pool pool, va_list arg); 32static Res MVTInit(Pool pool, va_list arg);
31static Bool MVTCheck(MVT mvt); 33static Bool MVTCheck(MVT mvt);
32static void MVTFinish(Pool pool); 34static void MVTFinish(Pool pool);
@@ -40,14 +42,14 @@ static Res MVTSegAlloc(Seg *segReturn, MVT mvt, Size size, Pool pool,
40 Bool withReservoirPermit); 42 Bool withReservoirPermit);
41 43
42static void MVTSegFree(MVT mvt, Seg seg); 44static void MVTSegFree(MVT mvt, Seg seg);
43static Bool MVTReturnBlockSegs(MVT mvt, CBSBlock block, Arena arena); 45static Bool MVTReturnRangeSegs(MVT mvt, Range range, Arena arena);
44static void MVTNoteNew(CBS cbs, CBSBlock block, Size oldSize, Size newSize); 46static Res MVTInsert(MVT mvt, Addr base, Addr limit);
45static void MVTNoteDelete(CBS cbs, CBSBlock block, Size oldSize, Size newSize); 47static Res MVTDelete(MVT mvt, Addr base, Addr limit);
46static void ABQRefillIfNecessary(MVT mvt, Size size); 48static void ABQRefillIfNecessary(MVT mvt, Size size);
47static Bool ABQRefillCallback(CBS cbs, CBSBlock block, void *closureP); 49static Bool ABQRefillCallback(CBS cbs, Addr base, Addr limit, void *closureP);
48static Res MVTContingencySearch(CBSBlock *blockReturn, CBS cbs, Size min); 50static Res MVTContingencySearch(Addr *baseReturn, Addr *limitReturn, CBS cbs, Size min);
49static Bool MVTContingencyCallback(CBS cbs, CBSBlock block, void *closureP); 51static Bool MVTContingencyCallback(CBS cbs, Addr base, Addr limit, void *closureP);
50static Bool MVTCheckFit(CBSBlock block, Size min, Arena arena); 52static Bool MVTCheckFit(Addr base, Addr limit, Size min, Arena arena);
51static ABQ MVTABQ(MVT mvt); 53static ABQ MVTABQ(MVT mvt);
52static CBS MVTCBS(MVT mvt); 54static CBS MVTCBS(MVT mvt);
53static MVT CBSMVT(CBS cbs); 55static MVT CBSMVT(CBS cbs);
@@ -56,7 +58,6 @@ static SegPref MVTSegPref(MVT mvt);
56 58
57/* Types */ 59/* Types */
58 60
59
60typedef struct MVTStruct 61typedef struct MVTStruct
61{ 62{
62 PoolStruct poolStruct; 63 PoolStruct poolStruct;
@@ -236,12 +237,11 @@ static Res MVTInit(Pool pool, va_list arg)
236 if (abqDepth < 3) 237 if (abqDepth < 3)
237 abqDepth = 3; 238 abqDepth = 3;
238 239
239 res = CBSInit(arena, MVTCBS(mvt), (void *)mvt, &MVTNoteNew, &MVTNoteDelete, 240 res = CBSInit(arena, MVTCBS(mvt), (void *)mvt, MPS_PF_ALIGN, FALSE);
240 NULL, NULL, reuseSize, MPS_PF_ALIGN, FALSE);
241 if (res != ResOK) 241 if (res != ResOK)
242 goto failCBS; 242 goto failCBS;
243 243
244 res = ABQInit(arena, MVTABQ(mvt), (void *)mvt, abqDepth); 244 res = ABQInit(arena, MVTABQ(mvt), (void *)mvt, abqDepth, sizeof(RangeStruct));
245 if (res != ResOK) 245 if (res != ResOK)
246 goto failABQ; 246 goto failABQ;
247 247
@@ -405,7 +405,7 @@ static Res MVTBufferFill(Addr *baseReturn, Addr *limitReturn,
405 Addr base, limit; 405 Addr base, limit;
406 Arena arena; 406 Arena arena;
407 Size alignedSize, fillSize; 407 Size alignedSize, fillSize;
408 CBSBlock block; 408 RangeStruct range;
409 409
410 AVER(baseReturn != NULL); 410 AVER(baseReturn != NULL);
411 AVER(limitReturn != NULL); 411 AVER(limitReturn != NULL);
@@ -460,21 +460,21 @@ static Res MVTBufferFill(Addr *baseReturn, Addr *limitReturn,
460 460
461 /* Attempt to retrieve a free block from the ABQ */ 461 /* Attempt to retrieve a free block from the ABQ */
462 ABQRefillIfNecessary(mvt, minSize); 462 ABQRefillIfNecessary(mvt, minSize);
463 res = ABQPeek(MVTABQ(mvt), &block); 463 res = ABQPeek(MVTABQ(mvt), (Addr)&range);
464 if (res != ResOK) { 464 if (res != ResOK) {
465 METER_ACC(mvt->underflows, minSize); 465 METER_ACC(mvt->underflows, minSize);
466 /* <design/poolmvt/#arch.contingency.fragmentation-limit> */ 466 /* <design/poolmvt/#arch.contingency.fragmentation-limit> */
467 if (mvt->available >= mvt->availLimit) { 467 if (mvt->available >= mvt->availLimit) {
468 METER_ACC(mvt->fragLimitContingencies, minSize); 468 METER_ACC(mvt->fragLimitContingencies, minSize);
469 res = MVTContingencySearch(&block, MVTCBS(mvt), minSize); 469 res = MVTContingencySearch(&base, &limit, MVTCBS(mvt), minSize);
470 } 470 }
471 } else { 471 } else {
472 base = RangeBase(&range);
473 limit = RangeLimit(&range);
472 METER_ACC(mvt->finds, minSize); 474 METER_ACC(mvt->finds, minSize);
473 } 475 }
474found: 476found:
475 if (res == ResOK) { 477 if (res == ResOK) {
476 base = CBSBlockBase(block);
477 limit = CBSBlockLimit(block);
478 { 478 {
479 Bool b = SegOfAddr(&seg, arena, base); 479 Bool b = SegOfAddr(&seg, arena, base);
480 AVER(b); 480 AVER(b);
@@ -506,7 +506,7 @@ found:
506 } 506 }
507 } 507 }
508 { 508 {
509 Res r = CBSDelete(MVTCBS(mvt), base, limit); 509 Res r = MVTDelete(mvt, base, limit);
510 AVER(r == ResOK); 510 AVER(r == ResOK);
511 UNUSED(r); /* <code/mpm.c#check.unused> */ 511 UNUSED(r); /* <code/mpm.c#check.unused> */
512 } 512 }
@@ -524,7 +524,7 @@ found:
524 524
525 /* Try contingency */ 525 /* Try contingency */
526 METER_ACC(mvt->emergencyContingencies, minSize); 526 METER_ACC(mvt->emergencyContingencies, minSize);
527 res = MVTContingencySearch(&block, MVTCBS(mvt), minSize); 527 res = MVTContingencySearch(&base, &limit, MVTCBS(mvt), minSize);
528 if (res == ResOK) 528 if (res == ResOK)
529 goto found; 529 goto found;
530 530
@@ -550,6 +550,137 @@ done:
550} 550}
551 551
552 552
553/* MVTDeleteOverlapping -- CBSIterate callback used by MVTInsert and
554 * MVTDelete. It receives a Range in its closureP argument, and return
555 * the DELETE disposition for ranges in the CBS that overlap with it.
556 */
557static Res MVTDeleteOverlapping(ABQDisposition *dispositionReturn,
558 Addr element, void *closureP)
559{
560 Range oldRange, newRange;
561
562 AVER(dispositionReturn != NULL);
563 AVER(element != NULL);
564 AVER(closureP != NULL);
565
566 oldRange = (Range)element;
567 newRange = (Range)closureP;
568
569 if (RangeOverlap(oldRange, newRange)) {
570 *dispositionReturn = ABQDispositionDELETE;
571 } else {
572 *dispositionReturn = ABQDispositionKEEP;
573 }
574
575 return ResOK;
576}
577
578
579/* MVTReserve -- add a range to the available range queue, and if the
580 * queue is full, return segments to the arena.
581 */
582static Res MVTReserve(MVT mvt, Range range)
583{
584 Res res;
585 AVERT(MVT, mvt);
586 AVERT(Range, range);
587 AVER(RangeSize(range) >= mvt->reuseSize);
588
589 res = ABQPush(MVTABQ(mvt), (Addr)range);
590
591 /* See <design/poolmvt/#impl.c.free.merge> */
592 if (res != ResOK) {
593 Bool success;
594 Arena arena = PoolArena(MVT2Pool(mvt));
595 RangeStruct oldRange;
596 res = ABQPeek(MVTABQ(mvt), (Addr)&oldRange);
597 AVER(res == ResOK);
598 success = MVTReturnRangeSegs(mvt, &oldRange, arena);
599 AVER(success);
600 res = ABQPush(MVTABQ(mvt), (Addr)&range);
601 if (res != ResOK) {
602 unless(MVTReturnRangeSegs(mvt, range, arena)) {
603 mvt->abqOverflow = TRUE;
604 METER_ACC(mvt->overflows, RangeSize(range));
605 }
606 }
607 }
608
609 return res;
610}
611
612
613/* MVTInsert -- insert an address range into the CBS and update the
614 * ABQ accordingly.
615 */
616static Res MVTInsert(MVT mvt, Addr base, Addr limit)
617{
618 Res res;
619 Addr newBase, newLimit;
620 RangeStruct range;
621
622 AVERT(MVT, mvt);
623 AVER(base < limit);
624
625 res = CBSInsert(&newBase, &newLimit, MVTCBS(mvt), base, limit);
626 if (res != ResOK)
627 return res;
628
629 /* The CBS might have coalesced the inserted range on both sides,
630 * either of which might be on the ABQ. But if the returned range is
631 * smaller than the reuse size, then it cannot have coalesced with
632 * any ranges that were in the ABQ, so we can skip the deletion
633 * step.
634 */
635 RangeInit(&range, base, limit);
636 if (RangeSize(&range) >= mvt->reuseSize) {
637 ABQIterate(MVTABQ(mvt), MVTDeleteOverlapping, &range);
638 MVTReserve(mvt, &range);
639 }
640
641 return ResOK;
642}
643
644
645/* MVTDelete -- delete an address range from the CBS and update the
646 * ABQ accordingly.
647 */
648static Res MVTDelete(MVT mvt, Addr base, Addr limit)
649{
650 Addr newBase, newLimit;
651 RangeStruct range, rangeLeft, rangeRight;
652 Res res;
653
654 AVERT(MVT, mvt);
655 AVER(base < limit);
656
657 RangeInit(&range, base, limit);
658
659 /* If the address range is smaller than the reuse size, then it can't
660 * be on the ABQ, so there's no need to delete it.
661 */
662 if (RangeSize(&range) >= mvt->reuseSize)
663 ABQIterate(MVTABQ(mvt), MVTDeleteOverlapping, &range);
664
665 res = CBSDelete(&newBase, &newLimit, MVTCBS(mvt), base, limit);
666 if (res != ResOK)
667 return res;
668
669 /* There might be fragments at the left or the right of the deleted
670 * range, and either might be big enough to go on the ABQ.
671 */
672 RangeInit(&rangeLeft, newBase, base);
673 if (RangeSize(&rangeLeft) >= mvt->reuseSize)
674 MVTReserve(mvt, &rangeLeft);
675
676 RangeInit(&rangeRight, limit, newLimit);
677 if (RangeSize(&rangeRight) >= mvt->reuseSize)
678 MVTReserve(mvt, &rangeRight);
679
680 return ResOK;
681}
682
683
553/* MVTBufferEmpty -- return an unusable portion of a buffer to the MVT 684/* MVTBufferEmpty -- return an unusable portion of a buffer to the MVT
554 * pool 685 * pool
555 * 686 *
@@ -586,7 +717,7 @@ static void MVTBufferEmpty(Pool pool, Buffer buffer,
586 717
587 /* <design/poolmvt/#arch.ap.no-fit.splinter> */ 718 /* <design/poolmvt/#arch.ap.no-fit.splinter> */
588 if (size < mvt->minSize) { 719 if (size < mvt->minSize) {
589 res = CBSInsert(MVTCBS(mvt), base, limit); 720 res = MVTInsert(mvt, base, limit);
590 AVER(res == ResOK); 721 AVER(res == ResOK);
591 METER_ACC(mvt->sawdust, size); 722 METER_ACC(mvt->sawdust, size);
592 return; 723 return;
@@ -599,13 +730,13 @@ static void MVTBufferEmpty(Pool pool, Buffer buffer,
599 730
600 /* Old better, drop new */ 731 /* Old better, drop new */
601 if (size < oldSize) { 732 if (size < oldSize) {
602 res = CBSInsert(MVTCBS(mvt), base, limit); 733 res = MVTInsert(mvt, base, limit);
603 AVER(res == ResOK); 734 AVER(res == ResOK);
604 METER_ACC(mvt->splintersDropped, size); 735 METER_ACC(mvt->splintersDropped, size);
605 return; 736 return;
606 } else { 737 } else {
607 /* New better, drop old */ 738 /* New better, drop old */
608 res = CBSInsert(MVTCBS(mvt), mvt->splinterBase, mvt->splinterLimit); 739 res = MVTInsert(mvt, mvt->splinterBase, mvt->splinterLimit);
609 AVER(res == ResOK); 740 AVER(res == ResOK);
610 METER_ACC(mvt->splintersDropped, oldSize); 741 METER_ACC(mvt->splintersDropped, oldSize);
611 } 742 }
@@ -671,7 +802,7 @@ static void MVTFree(Pool pool, Addr base, Size size)
671 } 802 }
672 803
673 { 804 {
674 Res res = CBSInsert(MVTCBS(mvt), base, limit); 805 Res res = MVTInsert(mvt, base, limit);
675 AVER(res == ResOK); 806 AVER(res == ResOK);
676 UNUSED(res); /* <code/mpm.c#check.unused> */ 807 UNUSED(res); /* <code/mpm.c#check.unused> */
677 } 808 }
@@ -714,7 +845,7 @@ static Res MVTDescribe(Pool pool, mps_lib_FILE *stream)
714 res = CBSDescribe(MVTCBS(mvt), stream); 845 res = CBSDescribe(MVTCBS(mvt), stream);
715 if(res != ResOK) return res; 846 if(res != ResOK) return res;
716 847
717 res = ABQDescribe(MVTABQ(mvt), stream); 848 res = ABQDescribe(MVTABQ(mvt), (ABQDescribeElement)RangeDescribe, stream);
718 if(res != ResOK) return res; 849 if(res != ResOK) return res;
719 850
720 res = METER_WRITE(mvt->segAllocs, stream); 851 res = METER_WRITE(mvt->segAllocs, stream);
@@ -890,16 +1021,16 @@ static void MVTSegFree(MVT mvt, Seg seg)
890} 1021}
891 1022
892 1023
893/* MVTReturnBlockSegs -- return (interior) segments of a block to the 1024/* MVTReturnRangeSegs -- return (interior) segments of a block to the
894 * arena 1025 * arena
895 */ 1026 */
896static Bool MVTReturnBlockSegs(MVT mvt, CBSBlock block, Arena arena) 1027static Bool MVTReturnRangeSegs(MVT mvt, Range range, Arena arena)
897{ 1028{
898 Addr base, limit; 1029 Addr base, limit;
899 Bool success = FALSE; 1030 Bool success = FALSE;
900 1031
901 base = CBSBlockBase(block); 1032 base = RangeBase(range);
902 limit = CBSBlockLimit(block); 1033 limit = RangeLimit(range);
903 1034
904 while (base < limit) { 1035 while (base < limit) {
905 Seg seg; 1036 Seg seg;
@@ -913,7 +1044,7 @@ static Bool MVTReturnBlockSegs(MVT mvt, CBSBlock block, Arena arena)
913 segBase = SegBase(seg); 1044 segBase = SegBase(seg);
914 segLimit = SegLimit(seg); 1045 segLimit = SegLimit(seg);
915 if (base <= segBase && limit >= segLimit) { 1046 if (base <= segBase && limit >= segLimit) {
916 Res r = CBSDelete(MVTCBS(mvt), segBase, segLimit); 1047 Res r = MVTDelete(mvt, segBase, segLimit);
917 1048
918 AVER(r == ResOK); 1049 AVER(r == ResOK);
919 UNUSED(r); /* <code/mpm.c#check.unused> */ 1050 UNUSED(r); /* <code/mpm.c#check.unused> */
@@ -927,60 +1058,6 @@ static Bool MVTReturnBlockSegs(MVT mvt, CBSBlock block, Arena arena)
927} 1058}
928 1059
929 1060
930/* MVTNoteNew -- callback invoked when a block on the CBS >= reuseSize
931 */
932static void MVTNoteNew(CBS cbs, CBSBlock block, Size oldSize, Size newSize)
933{
934 Res res;
935 MVT mvt;
936
937 AVERT(CBS, cbs);
938 mvt = CBSMVT(cbs);
939 AVERT(MVT, mvt);
940 AVERT(CBSBlock, block);
941 AVER(CBSBlockSize(block) >= mvt->reuseSize);
942 UNUSED(oldSize);
943 UNUSED(newSize);
944
945 res = ABQPush(MVTABQ(mvt), block);
946 /* See <design/poolmvt/#impl.c.free.merge> */
947 if (res != ResOK) {
948 Arena arena = PoolArena(MVT2Pool(mvt));
949 CBSBlock oldBlock;
950 res = ABQPeek(MVTABQ(mvt), &oldBlock);
951 AVER(res == ResOK);
952 /* --- This should always succeed */
953 (void)MVTReturnBlockSegs(mvt, oldBlock, arena);
954 res = ABQPush(MVTABQ(CBSMVT(cbs)), block);
955 if (res != ResOK) {
956 unless(MVTReturnBlockSegs(mvt, block, arena)) {
957 mvt->abqOverflow = TRUE;
958 METER_ACC(mvt->overflows, CBSBlockSize(block));
959 }
960 }
961 }
962}
963
964
965/* MVTNoteDelete -- callback invoked when a block on the CBS <= reuseSize */
966
967static void MVTNoteDelete(CBS cbs, CBSBlock block, Size oldSize, Size newSize)
968{
969 Res res;
970
971 AVERT(CBS, cbs);
972 AVERT(MVT, CBSMVT(cbs));
973 AVERT(CBSBlock, block);
974 AVER(CBSBlockSize(block) < CBSMVT(cbs)->reuseSize);
975 UNUSED(oldSize);
976 UNUSED(newSize);
977
978 res = ABQDelete(MVTABQ(CBSMVT(cbs)), block);
979 AVER(res == ResOK || CBSMVT(cbs)->abqOverflow);
980 UNUSED(res); /* <code/mpm.c#check.unused> */
981}
982
983
984/* ABQRefillIfNecessary -- refill the ABQ from the CBS if it had 1061/* ABQRefillIfNecessary -- refill the ABQ from the CBS if it had
985 * overflown and is now empty 1062 * overflown and is now empty
986 */ 1063 */
@@ -992,7 +1069,7 @@ static void ABQRefillIfNecessary(MVT mvt, Size size)
992 if (mvt->abqOverflow && ABQIsEmpty(MVTABQ(mvt))) { 1069 if (mvt->abqOverflow && ABQIsEmpty(MVTABQ(mvt))) {
993 mvt->abqOverflow = FALSE; 1070 mvt->abqOverflow = FALSE;
994 METER_ACC(mvt->refills, size); 1071 METER_ACC(mvt->refills, size);
995 CBSIterateLarge(MVTCBS(mvt), &ABQRefillCallback, NULL); 1072 CBSIterate(MVTCBS(mvt), &ABQRefillCallback, NULL);
996 } 1073 }
997} 1074}
998 1075
@@ -1000,28 +1077,34 @@ static void ABQRefillIfNecessary(MVT mvt, Size size)
1000/* ABQRefillCallback -- called from CBSIterate at the behest of 1077/* ABQRefillCallback -- called from CBSIterate at the behest of
1001 * ABQRefillIfNecessary 1078 * ABQRefillIfNecessary
1002 */ 1079 */
1003static Bool ABQRefillCallback(CBS cbs, CBSBlock block, void *closureP) 1080static Bool ABQRefillCallback(CBS cbs, Addr base, Addr limit, void *closureP)
1004{ 1081{
1005 Res res; 1082 Res res;
1006 MVT mvt; 1083 MVT mvt;
1007 1084 Size size;
1085 RangeStruct range;
1086
1008 AVERT(CBS, cbs); 1087 AVERT(CBS, cbs);
1009 mvt = CBSMVT(cbs); 1088 mvt = CBSMVT(cbs);
1010 AVERT(MVT, mvt); 1089 AVERT(MVT, mvt);
1011 AVERT(ABQ, MVTABQ(mvt)); 1090 AVERT(ABQ, MVTABQ(mvt));
1012 AVERT(CBSBlock, block); 1091 AVER(base < limit);
1013 AVER(CBSBlockSize(block) >= mvt->reuseSize);
1014 UNUSED(closureP); 1092 UNUSED(closureP);
1015 1093
1094 size = AddrOffset(base, limit);
1095 if (size < mvt->reuseSize)
1096 return TRUE;
1097
1016 METER_ACC(mvt->refillPushes, ABQDepth(MVTABQ(mvt))); 1098 METER_ACC(mvt->refillPushes, ABQDepth(MVTABQ(mvt)));
1017 res = ABQPush(MVTABQ(mvt), block); 1099 RangeInit(&range, base, limit);
1100 res = ABQPush(MVTABQ(mvt), (Addr)&range);
1018 if (res != ResOK) { 1101 if (res != ResOK) {
1019 if (MVTReturnBlockSegs(mvt, block, PoolArena(MVT2Pool(mvt)))) { 1102 if (MVTReturnRangeSegs(mvt, &range, PoolArena(MVT2Pool(mvt)))) {
1020 METER_ACC(mvt->refillReturns, CBSBlockSize(block)); 1103 METER_ACC(mvt->refillReturns, size);
1021 return TRUE; 1104 return TRUE;
1022 } else { 1105 } else {
1023 mvt->abqOverflow = TRUE; 1106 mvt->abqOverflow = TRUE;
1024 METER_ACC(mvt->refillOverflows, CBSBlockSize(block)); 1107 METER_ACC(mvt->refillOverflows, size);
1025 return FALSE; 1108 return FALSE;
1026 } 1109 }
1027 } 1110 }
@@ -1035,7 +1118,9 @@ typedef struct MVTContigencyStruct *MVTContigency;
1035 1118
1036typedef struct MVTContigencyStruct 1119typedef struct MVTContigencyStruct
1037{ 1120{
1038 CBSBlock blockReturn; 1121 Bool found;
1122 Addr base;
1123 Addr limit;
1039 Arena arena; 1124 Arena arena;
1040 Size min; 1125 Size min;
1041 /* meters */ 1126 /* meters */
@@ -1046,24 +1131,25 @@ typedef struct MVTContigencyStruct
1046 1131
1047/* MVTContingencySearch -- search the CBS for a block of size min */ 1132/* MVTContingencySearch -- search the CBS for a block of size min */
1048 1133
1049static Res MVTContingencySearch(CBSBlock *blockReturn, CBS cbs, Size min) 1134static Res MVTContingencySearch(Addr *baseReturn, Addr *limitReturn, CBS cbs, Size min)
1050{ 1135{
1051 MVTContigencyStruct cls; 1136 MVTContigencyStruct cls;
1052 1137
1053 cls.blockReturn = NULL; 1138 cls.found = FALSE;
1054 cls.arena = PoolArena(MVT2Pool(CBSMVT(cbs))); 1139 cls.arena = PoolArena(MVT2Pool(CBSMVT(cbs)));
1055 cls.min = min; 1140 cls.min = min;
1056 cls.steps = 0; 1141 cls.steps = 0;
1057 cls.hardSteps = 0; 1142 cls.hardSteps = 0;
1058 1143
1059 CBSIterate(cbs, &MVTContingencyCallback, (void *)&cls); 1144 CBSIterate(cbs, MVTContingencyCallback, (void *)&cls);
1060 if (cls.blockReturn != NULL) { 1145 if (cls.found) {
1061 AVER(CBSBlockSize(cls.blockReturn) >= min); 1146 AVER(AddrOffset(cls.base, cls.limit) >= min);
1062 METER_ACC(CBSMVT(cbs)->contingencySearches, cls.steps); 1147 METER_ACC(CBSMVT(cbs)->contingencySearches, cls.steps);
1063 if (cls.hardSteps) { 1148 if (cls.hardSteps) {
1064 METER_ACC(CBSMVT(cbs)->contingencyHardSearches, cls.hardSteps); 1149 METER_ACC(CBSMVT(cbs)->contingencyHardSearches, cls.hardSteps);
1065 } 1150 }
1066 *blockReturn = cls.blockReturn; 1151 *baseReturn = cls.base;
1152 *limitReturn = cls.limit;
1067 return ResOK; 1153 return ResOK;
1068 } 1154 }
1069 1155
@@ -1074,17 +1160,17 @@ static Res MVTContingencySearch(CBSBlock *blockReturn, CBS cbs, Size min)
1074/* MVTContingencyCallback -- called from CBSIterate at the behest of 1160/* MVTContingencyCallback -- called from CBSIterate at the behest of
1075 * MVTContingencySearch 1161 * MVTContingencySearch
1076 */ 1162 */
1077static Bool MVTContingencyCallback(CBS cbs, CBSBlock block, void *closureP) 1163static Bool MVTContingencyCallback(CBS cbs, Addr base, Addr limit, void *closureP)
1078{ 1164{
1079 MVTContigency cl; 1165 MVTContigency cl;
1080 Size size; 1166 Size size;
1081 1167
1082 AVERT(CBS, cbs); 1168 AVERT(CBS, cbs);
1083 AVERT(CBSBlock, block); 1169 AVER(base < limit);
1084 AVER(closureP != NULL); 1170 AVER(closureP != NULL);
1085 1171
1086 cl = (MVTContigency)closureP; 1172 cl = (MVTContigency)closureP;
1087 size = CBSBlockSize(block); 1173 size = AddrOffset(base, limit);
1088 1174
1089 cl->steps++; 1175 cl->steps++;
1090 if (size < cl->min) 1176 if (size < cl->min)
@@ -1092,14 +1178,18 @@ static Bool MVTContingencyCallback(CBS cbs, CBSBlock block, void *closureP)
1092 1178
1093 /* verify that min will fit when seg-aligned */ 1179 /* verify that min will fit when seg-aligned */
1094 if (size >= 2 * cl->min) { 1180 if (size >= 2 * cl->min) {
1095 cl->blockReturn = block; 1181 cl->base = base;
1182 cl->limit = limit;
1183 cl->found = TRUE;
1096 return FALSE; 1184 return FALSE;
1097 } 1185 }
1098 1186
1099 /* do it the hard way */ 1187 /* do it the hard way */
1100 cl->hardSteps++; 1188 cl->hardSteps++;
1101 if (MVTCheckFit(block, cl->min, cl->arena)) { 1189 if (MVTCheckFit(base, limit, cl->min, cl->arena)) {
1102 cl->blockReturn = block; 1190 cl->base = base;
1191 cl->limit = limit;
1192 cl->found = TRUE;
1103 return FALSE; 1193 return FALSE;
1104 } 1194 }
1105 1195
@@ -1111,10 +1201,8 @@ static Bool MVTContingencyCallback(CBS cbs, CBSBlock block, void *closureP)
1111/* MVTCheckFit -- verify that segment-aligned block of size min can 1201/* MVTCheckFit -- verify that segment-aligned block of size min can
1112 * fit in a candidate CBSblock 1202 * fit in a candidate CBSblock
1113 */ 1203 */
1114static Bool MVTCheckFit(CBSBlock block, Size min, Arena arena) 1204static Bool MVTCheckFit(Addr base, Addr limit, Size min, Arena arena)
1115{ 1205{
1116 Addr base = CBSBlockBase(block);
1117 Addr limit = CBSBlockLimit(block);
1118 Seg seg; 1206 Seg seg;
1119 Addr segLimit; 1207 Addr segLimit;
1120 1208