Beispiel #1
0
static void bufferNoSetRankSet(Buffer buffer, RankSet rankset)
{
  AVERT(Buffer, buffer);
  AVERT(RankSet, rankset);
  NOTREACHED; /* .norank */
}
Beispiel #2
0
static Res MVFFInit(Pool pool, ArgList args)
{
  Size extendBy = MVFF_EXTEND_BY_DEFAULT;
  Size avgSize = MVFF_AVG_SIZE_DEFAULT;
  Size align = MVFF_ALIGN_DEFAULT;
  Bool slotHigh = MVFF_SLOT_HIGH_DEFAULT;
  Bool arenaHigh = MVFF_ARENA_HIGH_DEFAULT;
  Bool firstFit = MVFF_FIRST_FIT_DEFAULT;
  MVFF mvff;
  Arena arena;
  Res res;
  void *p;
  ArgStruct arg;

  AVERT(Pool, pool);
  arena = PoolArena(pool);

  /* .arg: class-specific additional arguments; see */
  /* <design/poolmvff/#method.init> */
  /* .arg.check: we do the same checks here and in MVFFCheck */
  /* except for arenaHigh, which is stored only in the segPref. */
  
  if (ArgPick(&arg, args, MPS_KEY_EXTEND_BY))
    extendBy = arg.val.size;
  
  if (ArgPick(&arg, args, MPS_KEY_MEAN_SIZE))
    avgSize = arg.val.size;
  
  if (ArgPick(&arg, args, MPS_KEY_ALIGN))
    align = arg.val.align;

  if (ArgPick(&arg, args, MPS_KEY_MVFF_SLOT_HIGH))
    slotHigh = arg.val.b;
  
  if (ArgPick(&arg, args, MPS_KEY_MVFF_ARENA_HIGH))
    arenaHigh = arg.val.b;
  
  if (ArgPick(&arg, args, MPS_KEY_MVFF_FIRST_FIT))
    firstFit = arg.val.b;

  AVER(extendBy > 0);           /* .arg.check */
  AVER(avgSize > 0);            /* .arg.check */
  AVER(avgSize <= extendBy);    /* .arg.check */
  AVER(SizeIsAligned(align, MPS_PF_ALIGN));
  AVERT(Bool, slotHigh);
  AVERT(Bool, arenaHigh);
  AVERT(Bool, firstFit);

  mvff = Pool2MVFF(pool);

  mvff->extendBy = extendBy;
  if (extendBy < ArenaAlign(arena))
    mvff->minSegSize = ArenaAlign(arena);
  else
    mvff->minSegSize = extendBy;
  mvff->avgSize = avgSize;
  pool->alignment = align;
  mvff->slotHigh = slotHigh;
  mvff->firstFit = firstFit;

  res = ControlAlloc(&p, arena, sizeof(SegPrefStruct), FALSE);
  if (res != ResOK)
    return res;

  mvff->segPref = (SegPref)p;
  SegPrefInit(mvff->segPref);
  SegPrefExpress(mvff->segPref, arenaHigh ? SegPrefHigh : SegPrefLow, NULL);

  mvff->total = 0;
  mvff->free = 0;

  res = FreelistInit(FreelistOfMVFF(mvff), align);
  if (res != ResOK)
    goto failInit;

  res = CBSInit(CBSOfMVFF(mvff), arena, (void *)mvff, align,
                /* fastFind */ TRUE, /* zoned */ FALSE, args);
  if (res != ResOK)
    goto failInit;

  mvff->sig = MVFFSig;
  AVERT(MVFF, mvff);
  EVENT8(PoolInitMVFF, pool, arena, extendBy, avgSize, align,
         BOOL(slotHigh), BOOL(arenaHigh), BOOL(firstFit));
  return ResOK;

failInit:
  ControlFree(arena, p, sizeof(SegPrefStruct));
  return res;
}
Beispiel #3
0
Addr VMBase(VM vm)
{
  AVERT(VM, vm);

  return vm->base;
}
Beispiel #4
0
Count SplayDebugCount(SplayTree splay)
{
  AVERT(SplayTree, splay);
  return TreeDebugCount(SplayTreeRoot(splay), splay->compare, splay->nodeKey);
}
Beispiel #5
0
static Compare SplaySplitRev(SplayStateStruct *stateReturn,
                             SplayTree splay, TreeKey key,
                             TreeCompareFunction compare)
{
  Tree middle, leftLast, rightFirst;
  Compare cmp;

  AVERT(SplayTree, splay);
  AVER(FUNCHECK(compare));
  AVER(!SplayTreeIsEmpty(splay));
  
  leftLast = TreeEMPTY;
  rightFirst = TreeEMPTY;
  middle = SplayTreeRoot(splay);
  for (;;) {
    cmp = compare(middle, key);
    switch(cmp) {
    default:
      NOTREACHED;
      /* defensive fall-through */
    case CompareEQUAL:
      goto stop;

    case CompareLESS:
      if (!TreeHasLeft(middle))
        goto stop;
      middle = SplayZigRev(middle, &rightFirst);
      cmp = compare(middle, key);
      switch(cmp) {
      default:
        NOTREACHED;
        /* defensive fall-through */
      case CompareEQUAL:
        goto stop;
      case CompareLESS:
        if (!TreeHasLeft(middle))
          goto stop;
        middle = SplayZigZigRev(middle, &rightFirst);
        splay->updateNode(splay, TreeRight(rightFirst));
        break;
      case CompareGREATER:
        if (!TreeHasRight(middle))
          goto stop;
        middle = SplayZagRev(middle, &leftLast);
        break;
      }
      break;

    case CompareGREATER:
      if (!TreeHasRight(middle))
        goto stop;
      middle = SplayZagRev(middle, &leftLast);
      cmp = compare(middle, key);
      switch(cmp) {
      default:
        NOTREACHED;
        /* defensive fall-through */
      case CompareEQUAL:
        goto stop;
      case CompareGREATER:
        if (!TreeHasRight(middle))
          goto stop;
        middle = SplayZagZagRev(middle, &leftLast);
        splay->updateNode(splay, TreeLeft(leftLast));
        break;
      case CompareLESS:
        if (!TreeHasLeft(middle))
          goto stop;
        middle = SplayZigRev(middle, &rightFirst);
        break;
      }
      break;
    }
  }

stop:
  stateReturn->middle = middle;
  stateReturn->leftLast = leftLast;
  stateReturn->rightFirst = rightFirst;
  return cmp;
}
Align VMAlign(VM vm)
{
  AVERT(VM, vm);
  return vm->align;
}
Beispiel #7
0
static Bool MessageOnQueue(Message message)
{
  AVERT(Message, message);

  return !RingIsSingle(&message->queueRing);
}
static Bool SplaySplay(SplayNode *nodeReturn, SplayTree tree,
                       void *key, SplayCompareMethod compareMethod) {
    /* The sides structure avoids a boundary case in SplayLink* */
    SplayNodeStruct sides; /* rightTop and leftTop */
    SplayNode top, leftLast, rightFirst;
    Bool found;
    Compare compareTop;

    AVERT(SplayTree, tree);
    AVER(nodeReturn != NULL);
    AVER(FUNCHECK(compareMethod));

    top = SplayTreeRoot(tree); /* will be copied back at end */

    if (top == NULL) {
        *nodeReturn = NULL;
        return FALSE;
    }

    /* short-circuit case where node is already top */
    compareTop = (*compareMethod)(key, top);
    if (compareTop == CompareEQUAL) {
        *nodeReturn = top;
        return TRUE;
    }

    SplayNodeInit(&sides); /* left and right trees now NULL */
    leftLast = &sides;
    rightFirst = &sides;

    while(TRUE) {
        /* compareTop is already initialised above. */
        switch(compareTop) {

        case CompareLESS: {
            SplayNode topLeft = SplayNodeLeftChild(top);
            if (topLeft == NULL) {
                found = FALSE;
                goto assemble;
            } else {
                Compare compareTopLeft = (*compareMethod)(key, topLeft);

                switch(compareTopLeft) {

                case CompareEQUAL: {                 /* zig */
                    SplayLinkRight(&top, &rightFirst);
                    found = TRUE;
                    goto assemble;
                    } /* break; */

                case CompareLESS: {                  /* zig-zig */
                    if (SplayNodeLeftChild(topLeft) == NULL)
                        goto terminalZig;
                    SplayRotateRight(&top, tree);
                    SplayLinkRight(&top, &rightFirst);
                }
                break;

                case CompareGREATER: {               /* zig-zag */
                    if (SplayNodeRightChild(topLeft) == NULL)
                        goto terminalZig;
                    SplayLinkRight(&top, &rightFirst);
                    SplayLinkLeft(&top, &leftLast);
                }
                break;

                default: {
                    NOTREACHED;
                }
                break;
                }
            }
        }
        break;

        case CompareGREATER: {
            SplayNode topRight = SplayNodeRightChild(top);
            if (topRight == NULL) {
                found = FALSE;
                goto assemble;
            } else {
                Compare compareTopRight = (*compareMethod)(key, topRight);

                switch(compareTopRight) {

                case CompareEQUAL: {                 /* zag */
                    SplayLinkLeft(&top, &leftLast);
                    found = TRUE;
                    goto assemble;
                    } /* break; */

                case CompareGREATER: {               /* zag-zag */
                    if (SplayNodeRightChild(topRight) == NULL)
                        goto terminalZag;
                    SplayRotateLeft(&top, tree);
                    SplayLinkLeft(&top, &leftLast);
                }
                break;

                case CompareLESS: {                  /* zag-zig */
                    if (SplayNodeLeftChild(topRight) == NULL)
                        goto terminalZag;
                    SplayLinkLeft(&top, &leftLast);
                    SplayLinkRight(&top, &rightFirst);
                }
                break;

                default: {
                    NOTREACHED;
                }
                break;
                }
            }
        }
        break;

        case CompareEQUAL: {
            found = TRUE;
            goto assemble;
            } /* break; */

        default: {
            NOTREACHED;
        }
        break;
        }
        compareTop = (*compareMethod)(key, top);
    } /* end while(TRUE) */

terminalZig:
    SplayLinkRight(&top, &rightFirst);
    found = FALSE;
    goto assemble;

terminalZag:
    SplayLinkLeft(&top, &leftLast);
    found = FALSE;
    goto assemble;

assemble:
    SplayAssemble(tree, top,
                  SplayNodeRightChild(&sides), leftLast,
                  SplayNodeLeftChild(&sides), rightFirst);

    SplayTreeSetRoot(tree, top);
    *nodeReturn = top;

    return found;
}
void SplayTreeFinish(SplayTree tree)
{
    AVERT(SplayTree, tree);
    SplayTreeSetRoot(tree, NULL);
    tree->compare = NULL;
}
Beispiel #10
0
static Bool BTFindResRangeHigh(Index *baseReturn, Index *limitReturn,
                               BT bt,
                               Index searchBase, Index searchLimit,
                               Count minLength,
                               Count maxLength)
{
  Bool foundRes;         /* true if a reset bit is found */
  Index resLimit;        /* limit of a candidate reset range */
  Index resIndex;        /* index of highest reset bit found */
  Index unseenLimit;     /* limit of testing so far */
  Index minBase;         /* base of minimal acceptable range */
  Index resBase;         /* base of search for a candidate range */

  AVER(baseReturn != NULL);
  AVER(limitReturn != NULL);
  AVERT(BT, bt);
  AVER(searchBase < searchLimit);
  AVER(minLength > 0);
  AVER(minLength <= maxLength);
  AVER(maxLength <= searchLimit - searchBase);

  foundRes = FALSE;     /* don't know first reset bit */
  minBase = 0;          /* avoid spurious compiler warning */
  resLimit = searchLimit;    /* haven't seen anything yet */
  unseenLimit = searchLimit; /* haven't seen anything yet */
  resBase = searchBase + minLength -1;

  while (resLimit > resBase) {
    Index setIndex;  /* index of first set bit found */
    Bool foundSet = FALSE; /* true if a set bit is found */

    /* Find the first reset bit if it's not already known */
    if (!foundRes) {
      /* Look for the limit of a range */
      BTFindResHigh(&foundRes, &resIndex, bt, resBase, unseenLimit);
      if (!foundRes) {
        /* failure */
        return FALSE;
      }
      resLimit = resIndex + 1;
      unseenLimit = resIndex;
      minBase = resLimit - minLength;
    }

    /* Look to see if there is any set bit in the minimum range */
    BTFindSet(&foundSet, &setIndex, bt, minBase, unseenLimit);
    if (!foundSet) {
      /* Found minimum range. Extend it. */
      Index setBase;   /* base of search for set bit */
      Index setLimit;  /* limit search for set bit */
      Index baseIndex; /* base of reset range found */
      foundSet = FALSE;
      setLimit = minBase;
      if ((searchBase + maxLength) > resLimit)
        setBase = searchBase;
      else
        setBase  = resLimit - maxLength;
      if (setLimit > setBase)
        BTFindSetHigh(&foundSet, &setIndex, bt, setBase, setLimit);
      if (foundSet)
        baseIndex = setIndex+1;
      else
        baseIndex = setBase;
     
      AVER(resLimit - baseIndex >= minLength);
      AVER(resLimit - baseIndex <= maxLength);
      *baseReturn = baseIndex;
      *limitReturn = resLimit;
      return TRUE;
     
    } else {
      /* Range was too small. Try again */
      unseenLimit = minBase;
      resLimit = setIndex;
      if (resLimit != minBase) {
        /* Already found the start of next candidate range. This wraps
         * round if minLength > resLimit (all the variables are
         * unsigned so this behaviour is defined), but that means that
         * resLimit <= resBase and so the loop will exit. */
        AVER(resLimit >= minLength || resLimit <= resBase);
        minBase = resLimit - minLength;
      } else {
        foundRes = FALSE;
      }
    }
  }

  /* failure */
  return FALSE;
}
static void SplayAssemble(SplayTree tree, SplayNode top,
                          SplayNode leftTop, SplayNode leftLast,
                          SplayNode rightTop, SplayNode rightFirst) {
    AVERT(SplayTree, tree);
    AVERT(SplayNode, top);
    AVER(leftTop == NULL ||
         (SplayNodeCheck(leftTop) && SplayNodeCheck(leftLast)));
    AVER(rightTop == NULL ||
         (SplayNodeCheck(rightTop) && SplayNodeCheck(rightFirst)));

    if (leftTop != NULL) {
        SplayNodeSetRightChild(leftLast, SplayNodeLeftChild(top));
        SplayNodeSetLeftChild(top, leftTop);

        if (tree->updateNode != NULL) {
            /* Update client property using pointer reversal (Ugh!). */
            SplayNode node, parent, rightChild;

            /* Reverse the pointers between leftTop and leftLast */
            /* leftLast is not reversed. */
            node = leftTop;
            parent = NULL;
            while(node != leftLast) {
                rightChild = SplayNodeRightChild(node);
                SplayNodeSetRightChild(node, parent); /* pointer reversal */
                parent = node;
                node = rightChild;
            }

            /* Now restore the pointers, updating the client property. */
            /* node is leftLast, parent is the last parent (or NULL). */
            SplayNodeUpdate(tree, node);
            while(node != leftTop) {
                rightChild = node;
                node = parent;
                parent = SplayNodeRightChild(node);
                SplayNodeSetRightChild(node, rightChild); /* un-reverse pointer */
                SplayNodeUpdate(tree, node);
            }
        }
    }
    /* otherwise leave top->left alone */

    if (rightTop != NULL) {
        SplayNodeSetLeftChild(rightFirst, SplayNodeRightChild(top));
        SplayNodeSetRightChild(top, rightTop);

        if (tree->updateNode != NULL) {
            /* Update client property using pointer reversal (Ugh!). */
            SplayNode node, parent, leftChild;

            /* Reverse the pointers between rightTop and rightFirst */
            /* ightFirst is not reversed. */
            node = rightTop;
            parent = NULL;
            while(node != rightFirst) {
                leftChild = SplayNodeLeftChild(node);
                SplayNodeSetLeftChild(node, parent); /* pointer reversal */
                parent = node;
                node = leftChild;
            }

            /* Now restore the pointers, updating the client property. */
            /* node is rightFirst, parent is the last parent (or NULL). */
            SplayNodeUpdate(tree, node);
            while(node != rightTop) {
                leftChild = node;
                node = parent;
                parent = SplayNodeLeftChild(node);
                SplayNodeSetLeftChild(node, leftChild); /* un-reverse pointer */
                SplayNodeUpdate(tree, node);
            }
        }
    }
    /* otherwise leave top->right alone */

    if (tree->updateNode != NULL)
        SplayNodeUpdate(tree, top);
}
Beispiel #12
0
static Bool BTFindResRange(Index *baseReturn, Index *limitReturn,
                           BT bt,
                           Index searchBase, Index searchLimit,
                           Count minLength, Count maxLength)
{
  Bool foundRes;         /* true if a reset bit is found */
  Index resBase;         /* base of a candidate reset range */
  Index unseenBase;      /* base of testing so far */
  Index minLimit;        /* limit of minimal acceptable range */
  Index resLimit;        /* limit of search for a candidate range */

  AVER(baseReturn != NULL);
  AVER(limitReturn != NULL);
  AVERT(BT, bt);
  AVER(searchBase < searchLimit);
  AVER(minLength > 0);
  AVER(minLength <= maxLength);
  AVER(maxLength <= searchLimit - searchBase);

  foundRes = FALSE;     /* don't know first reset bit */
  minLimit = 0;         /* avoid spurious compiler warning */
  resBase = searchBase; /* haven't seen anything yet */
  unseenBase = searchBase;  /* haven't seen anything yet */
  resLimit = searchLimit - minLength + 1;

  while (resBase < resLimit) {
    Index setIndex;  /* index of last set bit found */
    Bool foundSet = FALSE; /* true if a set bit is found */

    /* Find the first reset bit if it's not already known */
    if (!foundRes) {
      BTFindRes(&foundRes, &resBase, bt, unseenBase, resLimit);
      if (!foundRes) {
        /* failure */
        return FALSE;
      }
      unseenBase = resBase + 1;
      minLimit = resBase + minLength;
    }

    /* Look to see if there is any set bit in the minimum range */
    BTFindSetHigh(&foundSet, &setIndex, bt, unseenBase, minLimit);
    if (!foundSet) {
      /* Found minimum range. Extend it. */
      Index setBase;   /* base of search for set bit */
      Index setLimit;  /* limit search for set bit */
      foundSet = FALSE;
      setBase = minLimit;
      setLimit = resBase + maxLength;
      if (setLimit > searchLimit)
        setLimit = searchLimit;
      if (setLimit > setBase)
        BTFindSet(&foundSet, &setIndex, bt, setBase, setLimit);
      if (!foundSet)
        setIndex = setLimit;
       
      AVER(setIndex - resBase >= minLength);
      AVER(setIndex - resBase <= maxLength);
      *baseReturn = resBase;
      *limitReturn = setIndex;
      return TRUE;
       
    } else {
      /* Range was too small. Try again */
      unseenBase = minLimit;
      resBase = setIndex + 1;
      if (resBase != minLimit) {
        /* Already found the start of next candidate range */
        minLimit = resBase + minLength;
        /* minLimit might just have gone out of bounds, but in that
         * case resBase >= resLimit and so the loop will exit. */
        AVER(minLimit <= searchLimit || resBase >= resLimit);
      } else {
        foundRes = FALSE;
      }
    }
  }

  /* failure */
  return FALSE;
}
Beispiel #13
0
static Res ArenaRootsWalk(Globals arenaGlobals, mps_roots_stepper_t f,
                          void *p, size_t s)
{
  Arena arena;
  rootsStepClosureStruct rscStruct;
  rootsStepClosure rsc = &rscStruct;
  Trace trace;
  ScanState ss;
  Rank rank;
  Res res;
  Seg seg;

  AVERT(Globals, arenaGlobals);
  AVER(FUNCHECK(f));
  /* p and s are arbitrary client-provided closure data. */
  arena = GlobalsArena(arenaGlobals);

  /* Scan all the roots with a minimal trace.  Invoke the scanner with a */
  /* rootsStepClosure, which is a subclass of ScanState and contains the */
  /* client-provided closure.  Supply a special fix method in order to */
  /* call the client closure.  This fix method must perform no tracing */
  /* operations of its own. */

  res = TraceCreate(&trace, arena, TraceStartWhyWALK);
  /* Have to fail if no trace available.  Unlikely due to .assume.parked. */
  if (res != ResOK)
    return res;

  /* ArenaRootsWalk only passes references to GCable pools to the client. */
  /* NOTE: I'm not sure why this is. RB 2012-07-24 */
  if (SegFirst(&seg, arena)) {
    do {
      if (PoolHasAttr(SegPool(seg), AttrGC)) {
        res = TraceAddWhite(trace, seg);
        AVER(res == ResOK);
      }
    } while (SegNext(&seg, arena, seg));
  }

  /* Make the roots grey so that they are scanned */
  res = RootsIterate(arenaGlobals, rootWalkGrey, trace);
  /* Make this trace look like any other trace. */
  arena->flippedTraces = TraceSetAdd(arena->flippedTraces, trace);

  rootsStepClosureInit(rsc, arenaGlobals, trace, RootsWalkFix, f, p, s);
  ss = rootsStepClosure2ScanState(rsc);

  for(rank = RankAMBIG; rank < RankLIMIT; ++rank) {
    ss->rank = rank;
    AVERT(ScanState, ss);
    res = RootsIterate(arenaGlobals, rootWalk, (void *)ss);
    if (res != ResOK)
      break;
  }

  /* Turn segments black again. */
  if (SegFirst(&seg, arena)) {
    do {
      if (PoolHasAttr(SegPool(seg), AttrGC)) {
        SegSetGrey(seg, TraceSetDel(SegGrey(seg), trace));
        SegSetWhite(seg, TraceSetDel(SegWhite(seg), trace));
      }
    } while (SegNext(&seg, arena, seg));
  }

  rootsStepClosureFinish(rsc);
  /* Make this trace look like any other finished trace. */
  trace->state = TraceFINISHED;
  TraceDestroy(trace);
  AVER(!ArenaEmergency(arena)); /* There was no allocation. */

  return res;
}
Beispiel #14
0
static void bufferNoReassignSeg(Buffer buffer, Seg seg)
{
  AVERT(Buffer, buffer);
  AVERT(Seg, seg);
  NOTREACHED; /* .noseg */
}
Size VMReserved(VM vm)
{
  AVERT(VM, vm);
  return vm->reserved;
}
Beispiel #16
0
DEFINE_CLASS(Inst, Inst, klass)
{
  InstClassInitInternal(klass);
  klass->instStruct.klass = CLASS(InstClass);
  AVERT(InstClass, klass);
}
Size VMMapped(VM vm)
{
  AVERT(VM, vm);
  return vm->mapped;
}
Beispiel #18
0
void FreelistFinish(Freelist fl)
{
  AVERT(Freelist, fl);
  fl->sig = SigInvalid;
  fl->list = NULL;
}
Res VMCreate(VM *vmReturn, Size size)
{
  void *addr;
  Align align;
  int zero_fd;
  VM vm;
  Res res;

  AVER(vmReturn != NULL);

  align = (Align)sysconf(_SC_PAGESIZE);
  AVER(SizeIsP2(align));
  size = SizeAlignUp(size, align);
  if((size == 0) || (size > (Size)(size_t)-1))
    return ResRESOURCE;

  zero_fd = open("/dev/zero", O_RDONLY);
  if(zero_fd == -1)
    return ResFAIL;

  /* Map in a page to store the descriptor on. */
  addr = mmap((void *)0, (size_t)SizeAlignUp(sizeof(VMStruct), align),
              PROT_READ | PROT_WRITE, MAP_PRIVATE,
              zero_fd, (off_t)0);
  if(addr == MAP_FAILED) {
    AVER(errno == ENOMEM || errno == EAGAIN); /* .assume.mmap.err */
    res = (errno == ENOMEM || errno == EAGAIN) ? ResMEMORY : ResFAIL;
    goto failVMMap;
  }
  vm = (VM)addr;

  vm->zero_fd = zero_fd;
  vm->align = align;

  /* .map.reserve: MAP_AUTORESRV is necessary to avoid reserving swap. */
  addr = mmap((void *)0, (size_t)size, PROT_NONE, MAP_SHARED | MAP_AUTORESRV,
	      zero_fd, (off_t)0);
  if(addr == MAP_FAILED) {
    AVER(errno == ENOMEM); /* .assume.mmap.err */
    res = (errno == ENOMEM) ? ResRESOURCE : ResFAIL;
    goto failReserve;
  }

  vm->base = (Addr)addr;
  vm->limit = AddrAdd(vm->base, size);
  vm->reserved = size;
  vm->mapped = (Size)0;

  vm->sig = VMSig;

  AVERT(VM, vm);

  EVENT_PAA(VMCreate, vm, vm->base, vm->limit);

  *vmReturn = vm;
  return ResOK;

failReserve:
  (void)munmap((void *)vm, (size_t)SizeAlignUp(sizeof(VMStruct), align));
failVMMap:
  (void)close(zero_fd);
  return res;
}
Beispiel #20
0
/* FreelistBlockNext -- return the next block in the list, or NULL if
 * there are no more blocks.
 */
static FreelistBlock FreelistBlockNext(FreelistBlock block)
{
  AVERT(FreelistBlock, block);
  return FreelistTagReset(block->small.next);
}
Beispiel #21
0
void SplayTrivUpdate(SplayTree splay, Tree tree)
{
  AVERT(SplayTree, splay);
  AVERT(Tree, tree);
}
Beispiel #22
0
static void FreelistBlockSetNext(FreelistBlock block, FreelistBlock next)
{
  AVERT(FreelistBlock, block);
  block->small.next = FreelistTagCopy(next, block->small.next);
}
Beispiel #23
0
static Compare SplaySplitDown(SplayStateStruct *stateReturn,
                              SplayTree splay, TreeKey key,
                              TreeCompareFunction compare)
{
  TreeStruct sentinel;
  Tree middle, leftLast, rightFirst, leftPrev, rightNext;
  Compare cmp;

  AVERT(SplayTree, splay);
  AVER(FUNCHECK(compare));
  AVER(!SplayTreeIsEmpty(splay));
  AVER(!SplayHasUpdate(splay));
  
  TreeInit(&sentinel);
  leftLast = &sentinel;
  rightFirst = &sentinel;
  middle = SplayTreeRoot(splay);
  for (;;) {
    cmp = compare(middle, key);
    switch(cmp) {
    default:
      NOTREACHED;
      /* defensive fall-through */
    case CompareEQUAL:
      goto stop;

    case CompareLESS:
      if (!TreeHasLeft(middle))
        goto stop;
      middle = SplayZig(middle, &rightFirst, &rightNext);
      cmp = compare(middle, key);
      switch(cmp) {
      default:
        NOTREACHED;
        /* defensive fall-through */
      case CompareEQUAL:
        goto stop;
      case CompareLESS:
        if (!TreeHasLeft(middle))
          goto stop;
        middle = SplayZigZig(middle, &rightFirst, rightNext);
        break;
      case CompareGREATER:
        if (!TreeHasRight(middle))
          goto stop;
        middle = SplayZag(middle, &leftLast, &leftPrev);
        break;
      }
      break;

    case CompareGREATER:
      if (!TreeHasRight(middle))
        goto stop;
      middle = SplayZag(middle, &leftLast, &leftPrev);
      cmp = compare(middle, key);
      switch(cmp) {
      default:
        NOTREACHED;
        /* defensive fall-through */
      case CompareEQUAL:
        goto stop;
      case CompareGREATER:
        if (!TreeHasRight(middle))
          goto stop;
        middle = SplayZagZag(middle, &leftLast, leftPrev);
        break;
      case CompareLESS:
        if (!TreeHasLeft(middle))
          goto stop;
        middle = SplayZig(middle, &rightFirst, &rightNext);
        break;
      }
      break;
    }
  }

stop:
  stateReturn->middle = middle;
  stateReturn->left = TreeRight(&sentinel);
  stateReturn->leftLast = leftLast == &sentinel ? TreeEMPTY : leftLast;
  stateReturn->right = TreeLeft(&sentinel);
  stateReturn->rightFirst = rightFirst == &sentinel ? TreeEMPTY : rightFirst;
  return cmp;
}
Beispiel #24
0
/* AMSTBufferFill -- the pool class buffer fill method
 *
 * Calls next method - but possibly splits or merges the chosen
 * segment.
 *
 * .merge: A merge is performed when the next method returns the
 * entire segment, this segment had previously been split from the
 * segment below, and the segment below is appropriately similar
 * (i.e. not already attached to a buffer and similarly coloured)
 *
 * .split: If we're not merging, a split is performed if the next method
 * returns the entire segment, and yet lower half of the segment would
 * meet the request.
 */
static Res AMSTBufferFill(Addr *baseReturn, Addr *limitReturn,
                          Pool pool, Buffer buffer, Size size)
{
  Addr base, limit;
  Arena arena;
  AMS ams;
  AMST amst;
  Bool b;
  Seg seg;
  AMSTSeg amstseg;
  Res res;

  AVERT(Pool, pool);
  AVER(baseReturn != NULL);
  AVER(limitReturn != NULL);
  /* other parameters are checked by next method */
  arena = PoolArena(pool);
  ams = PoolAMS(pool);
  amst = PoolAMST(pool);

  /* call next method */
  res = NextMethod(Pool, AMSTPool, bufferFill)(&base, &limit, pool, buffer, size);
  if (res != ResOK)
    return res;

  b = SegOfAddr(&seg, arena, base);
  AVER(b);
  amstseg = Seg2AMSTSeg(seg);

  if (SegLimit(seg) == limit && SegBase(seg) == base) {
    if (amstseg->prev != NULL) {
      Seg segLo = AMSTSeg2Seg(amstseg->prev);
      if (!SegHasBuffer(segLo) &&
          SegGrey(segLo) == SegGrey(seg) &&
          SegWhite(segLo) == SegWhite(seg)) {
        /* .merge */
        Seg mergedSeg;
        Res mres;

        AMSUnallocateRange(ams, seg, base, limit);
        mres = SegMerge(&mergedSeg, segLo, seg);
        if (ResOK == mres) { /* successful merge */
          AMSAllocateRange(ams, mergedSeg, base, limit);
          /* leave range as-is */
        } else {            /* failed to merge */
          AVER(amst->failSegs); /* deliberate fails only */
          AMSAllocateRange(ams, seg, base, limit);
        }
      }

    } else {
      Size half = SegSize(seg) / 2;
      if (half >= size && SizeIsArenaGrains(half, arena)) {
        /* .split */
        Addr mid = AddrAdd(base, half);
        Seg segLo, segHi;
        Res sres;
        AMSUnallocateRange(ams, seg, mid, limit);
        sres = SegSplit(&segLo, &segHi, seg, mid);
        if (ResOK == sres) { /* successful split */
          limit = mid;  /* range is lower segment */
        } else {            /* failed to split */
          AVER(amst->failSegs); /* deliberate fails only */
          AMSAllocateRange(ams, seg, mid, limit);
        }

      }
    }
  }

  *baseReturn = base;
  *limitReturn = limit;
  return ResOK;
}
Beispiel #25
0
/* MVFFFreeSegs -- Free segments from given range
 *
 * Given a free range, attempts to find entire segments within
 * it, and returns them to the arena, updating total size counter.
 *
 * This is usually called immediately after MVFFAddToFreeList.
 * It is not combined with MVFFAddToFreeList because the latter
 * is also called when new segments are added under MVFFAlloc.
 */
static void MVFFFreeSegs(MVFF mvff, Addr base, Addr limit)
{
  Seg seg = NULL;       /* suppress "may be used uninitialized" */
  Arena arena;
  Bool b;
  Addr segLimit;  /* limit of the current segment when iterating */
  Addr segBase;   /* base of the current segment when iterating */
  Res res;

  AVERT(MVFF, mvff);
  AVER(base < limit);
  /* Could profitably AVER that the given range is free, */
  /* but the CBS doesn't provide that facility. */

  if (AddrOffset(base, limit) < mvff->minSegSize)
    return; /* not large enough for entire segments */

  arena = PoolArena(MVFF2Pool(mvff));
  b = SegOfAddr(&seg, arena, base);
  AVER(b);

  segBase = SegBase(seg);
  segLimit = SegLimit(seg);

  while(segLimit <= limit) { /* segment ends in range */
    if (segBase >= base) { /* segment starts in range */
      RangeStruct range, oldRange;
      RangeInit(&range, segBase, segLimit);

      res = CBSDelete(&oldRange, CBSOfMVFF(mvff), &range);
      if (res == ResOK) {
        mvff->free -= RangeSize(&range);
      } else if (ResIsAllocFailure(res)) {
        /* CBS ran out of memory for splay nodes, which must mean that
         * there were fragments on both sides: see
         * <design/cbs/#function.cbs.delete.fail>. Handle this by
         * deleting the whole of oldRange (which requires no
         * allocation) and re-inserting the fragments. */
        RangeStruct oldRange2;
        res = CBSDelete(&oldRange2, CBSOfMVFF(mvff), &oldRange);
        AVER(res == ResOK);
        AVER(RangesEqual(&oldRange2, &oldRange));
        mvff->free -= RangeSize(&oldRange);
        AVER(RangeBase(&oldRange) != segBase);
        {
          Addr leftBase = RangeBase(&oldRange);
          Addr leftLimit = segBase;
          res = MVFFAddToFreeList(&leftBase, &leftLimit, mvff);
        }
        AVER(RangeLimit(&oldRange) != segLimit);
        {
          Addr rightBase = segLimit;
          Addr rightLimit = RangeLimit(&oldRange);
          res = MVFFAddToFreeList(&rightBase, &rightLimit, mvff);
        }
      } else if (res == ResFAIL) {
        /* Not found in the CBS: must be found in the Freelist. */
        res = FreelistDelete(&oldRange, FreelistOfMVFF(mvff), &range);
        AVER(res == ResOK);
        mvff->free -= RangeSize(&range);
      }

      AVER(res == ResOK);
      AVER(RangesNest(&oldRange, &range));

      /* Can't free the segment earlier, because if it was on the
       * Freelist rather than the CBS then it likely contains data
       * that needs to be read in order to update the Freelist. */
      SegFree(seg);
      mvff->total -= RangeSize(&range);
    }

    /* Avoid calling SegNext if the next segment would fail */
    /* the loop test, mainly because there might not be a */
    /* next segment. */
    if (segLimit == limit) /* segment ends at end of range */
      break;

    b = SegFindAboveAddr(&seg, arena, segBase);
    AVER(b);
    segBase = SegBase(seg);
    segLimit = SegLimit(seg);
  }

  return;
}
Beispiel #26
0
Res ChunkInit(Chunk chunk, Arena arena, Addr base, Addr limit, Size reserved,
              BootBlock boot)
{
  Size size;
  Count pages;
  Shift pageShift;
  Size pageTableSize;
  Addr allocBase;
  void *p;
  Res res;

  /* chunk is supposed to be uninitialized, so don't check it. */
  AVERT(Arena, arena);
  AVER(base != NULL);
  AVER(AddrIsAligned(base, ArenaGrainSize(arena)));
  AVER(base < limit);
  AVER(AddrIsAligned(limit, ArenaGrainSize(arena)));
  AVERT(BootBlock, boot);

  chunk->serial = (arena->chunkSerial)++;
  chunk->arena = arena;
  RingInit(&chunk->arenaRing);

  chunk->pageSize = ArenaGrainSize(arena);
  chunk->pageShift = pageShift = SizeLog2(chunk->pageSize);
  chunk->base = base;
  chunk->limit = limit;
  chunk->reserved = reserved;
  size = ChunkSize(chunk);

  /* .overhead.pages: Chunk overhead for the page allocation table. */
  chunk->pages = pages = size >> pageShift;
  res = BootAlloc(&p, boot, (size_t)BTSize(pages), MPS_PF_ALIGN);
  if (res != ResOK)
    goto failAllocTable;
  chunk->allocTable = p;

  pageTableSize = SizeAlignUp(pages * sizeof(PageUnion), chunk->pageSize);
  chunk->pageTablePages = pageTableSize >> pageShift;

  res = Method(Arena, arena, chunkInit)(chunk, boot);
  if (res != ResOK)
    goto failClassInit;

  /* @@@@ Is BootAllocated always right? */
  /* Last thing we BootAlloc'd is pageTable.  We requested pageSize */
  /* alignment, and pageTableSize is itself pageSize aligned, so */
  /* BootAllocated should also be pageSize aligned. */
  AVER(AddrIsAligned(BootAllocated(boot), chunk->pageSize));
  chunk->allocBase = (Index)(BootAllocated(boot) >> pageShift);

  /* Init allocTable after class init, because it might be mapped there. */
  BTResRange(chunk->allocTable, 0, pages);

  /* Check that there is some usable address space remaining in the chunk. */
  allocBase = PageIndexBase(chunk, chunk->allocBase);
  AVER(allocBase < chunk->limit);

  /* Add the chunk's free address space to the arena's freeLand, so that
     we can allocate from it. */
  if (arena->hasFreeLand) {
    res = ArenaFreeLandInsert(arena, allocBase, chunk->limit);
    if (res != ResOK)
      goto failLandInsert;
  }

  TreeInit(&chunk->chunkTree);

  chunk->sig = ChunkSig;
  AVERT(Chunk, chunk);

  ArenaChunkInsert(arena, chunk);

  return ResOK;

failLandInsert:
  Method(Arena, arena, chunkFinish)(chunk);
  /* .no-clean: No clean-ups needed past this point for boot, as we will
     discard the chunk. */
failClassInit:
failAllocTable:
  return res;
}
Beispiel #27
0
Res VMCreate(VM *vmReturn, Size size, void *params)
{
  Align align;
  VM vm;
  int pagesize;
  void *addr;
  Res res;

  AVER(vmReturn != NULL);
  AVER(params != NULL);

  /* Find out the page size from the OS */
  pagesize = getpagesize();
  /* check the actual returned pagesize will fit in an object of */
  /* type Align. */
  AVER(pagesize > 0);
  AVER((unsigned long)pagesize <= (unsigned long)(Align)-1);
  align = (Align)pagesize;
  AVER(SizeIsP2(align));
  size = SizeAlignUp(size, align);
  if((size == 0) || (size > (Size)(size_t)-1))
    return ResRESOURCE;

  /* Map in a page to store the descriptor on. */
  addr = mmap(0, (size_t)SizeAlignUp(sizeof(VMStruct), align),
              PROT_READ | PROT_WRITE,
              MAP_ANON | MAP_PRIVATE,
              -1, 0);
  /* On Darwin the MAP_FAILED return value is not documented, but does
   * work.  MAP_FAILED _is_ documented by POSIX.
   */
  if(addr == MAP_FAILED) {
    int e = errno;
    AVER(e == ENOMEM); /* .assume.mmap.err */
    return ResMEMORY;
  }
  vm = (VM)addr;

  vm->align = align;

  /* See .assume.not-last. */
  addr = mmap(0, (size_t)size,
              PROT_NONE, MAP_ANON | MAP_PRIVATE,
              -1, 0);
  if(addr == MAP_FAILED) {
    int e = errno;
    AVER(e == ENOMEM); /* .assume.mmap.err */
    res = ResRESOURCE;
    goto failReserve;
  }

  vm->base = (Addr)addr;
  vm->limit = AddrAdd(vm->base, size);
  vm->reserved = size;
  vm->mapped = (Size)0;

  vm->sig = VMSig;

  AVERT(VM, vm);

  EVENT3(VMCreate, vm, vm->base, vm->limit);

  *vmReturn = vm;
  return ResOK;

failReserve:
  (void)munmap((void *)vm, (size_t)SizeAlignUp(sizeof(VMStruct), align));
  return res;
}
Bool RingIsSingle(Ring ring)
{
  AVERT(Ring, ring);
  return (ring->next == ring);
}
Beispiel #29
0
Addr VMLimit(VM vm)
{
  AVERT(VM, vm);

  return vm->limit;
}
Beispiel #30
0
static RankSet bufferTrivRankSet(Buffer buffer)
{
  AVERT(Buffer, buffer);
  /* vanilla buffers can only have empty rank set */
  return RankSetEMPTY;
}