diff options
| author | Gareth Rees | 2013-05-20 20:47:41 +0100 |
|---|---|---|
| committer | Gareth Rees | 2013-05-20 20:47:41 +0100 |
| commit | 48e439d624610276b516c353d2f2e9b61c36126a (patch) | |
| tree | 7ade91096541bf6b2d609f04ed756ecd6f9fc949 /mps/code | |
| parent | 1912c062b5e07393d728f31c692c07841d6d1313 (diff) | |
| download | emacs-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.c | 302 |
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 | ||
| 19 | SRCID(poolmv2, "$Id$"); | 20 | SRCID(poolmv2, "$Id$"); |
| 20 | 21 | ||
| @@ -27,6 +28,7 @@ SRCID(poolmv2, "$Id$"); | |||
| 27 | /* Private prototypes */ | 28 | /* Private prototypes */ |
| 28 | 29 | ||
| 29 | typedef struct MVTStruct *MVT; | 30 | typedef struct MVTStruct *MVT; |
| 31 | |||
| 30 | static Res MVTInit(Pool pool, va_list arg); | 32 | static Res MVTInit(Pool pool, va_list arg); |
| 31 | static Bool MVTCheck(MVT mvt); | 33 | static Bool MVTCheck(MVT mvt); |
| 32 | static void MVTFinish(Pool pool); | 34 | static 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 | ||
| 42 | static void MVTSegFree(MVT mvt, Seg seg); | 44 | static void MVTSegFree(MVT mvt, Seg seg); |
| 43 | static Bool MVTReturnBlockSegs(MVT mvt, CBSBlock block, Arena arena); | 45 | static Bool MVTReturnRangeSegs(MVT mvt, Range range, Arena arena); |
| 44 | static void MVTNoteNew(CBS cbs, CBSBlock block, Size oldSize, Size newSize); | 46 | static Res MVTInsert(MVT mvt, Addr base, Addr limit); |
| 45 | static void MVTNoteDelete(CBS cbs, CBSBlock block, Size oldSize, Size newSize); | 47 | static Res MVTDelete(MVT mvt, Addr base, Addr limit); |
| 46 | static void ABQRefillIfNecessary(MVT mvt, Size size); | 48 | static void ABQRefillIfNecessary(MVT mvt, Size size); |
| 47 | static Bool ABQRefillCallback(CBS cbs, CBSBlock block, void *closureP); | 49 | static Bool ABQRefillCallback(CBS cbs, Addr base, Addr limit, void *closureP); |
| 48 | static Res MVTContingencySearch(CBSBlock *blockReturn, CBS cbs, Size min); | 50 | static Res MVTContingencySearch(Addr *baseReturn, Addr *limitReturn, CBS cbs, Size min); |
| 49 | static Bool MVTContingencyCallback(CBS cbs, CBSBlock block, void *closureP); | 51 | static Bool MVTContingencyCallback(CBS cbs, Addr base, Addr limit, void *closureP); |
| 50 | static Bool MVTCheckFit(CBSBlock block, Size min, Arena arena); | 52 | static Bool MVTCheckFit(Addr base, Addr limit, Size min, Arena arena); |
| 51 | static ABQ MVTABQ(MVT mvt); | 53 | static ABQ MVTABQ(MVT mvt); |
| 52 | static CBS MVTCBS(MVT mvt); | 54 | static CBS MVTCBS(MVT mvt); |
| 53 | static MVT CBSMVT(CBS cbs); | 55 | static MVT CBSMVT(CBS cbs); |
| @@ -56,7 +58,6 @@ static SegPref MVTSegPref(MVT mvt); | |||
| 56 | 58 | ||
| 57 | /* Types */ | 59 | /* Types */ |
| 58 | 60 | ||
| 59 | |||
| 60 | typedef struct MVTStruct | 61 | typedef 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 | } |
| 474 | found: | 476 | found: |
| 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 | */ | ||
| 557 | static 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 | */ | ||
| 582 | static 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 | */ | ||
| 616 | static 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 | */ | ||
| 648 | static 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 | */ |
| 896 | static Bool MVTReturnBlockSegs(MVT mvt, CBSBlock block, Arena arena) | 1027 | static 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 | */ | ||
| 932 | static 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 | |||
| 967 | static 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 | */ |
| 1003 | static Bool ABQRefillCallback(CBS cbs, CBSBlock block, void *closureP) | 1080 | static 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 | ||
| 1036 | typedef struct MVTContigencyStruct | 1119 | typedef 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 | ||
| 1049 | static Res MVTContingencySearch(CBSBlock *blockReturn, CBS cbs, Size min) | 1134 | static 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 | */ |
| 1077 | static Bool MVTContingencyCallback(CBS cbs, CBSBlock block, void *closureP) | 1163 | static 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 | */ |
| 1114 | static Bool MVTCheckFit(CBSBlock block, Size min, Arena arena) | 1204 | static 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 | ||