/* AMSTStressBufferedSeg -- Stress test for a buffered seg * * Test splitting or merging a buffered seg. * * .bmerge: A merge is performed when the segment had previously * been split and the segment above meets the constraints (i.e. empty, * not already attached to a buffer and similar colour) * * .bsplit: Whether or not a merge happpened, a split is performed if * the limit of the buffered region is also the limit of an arena * grain, and yet does not correspond to the segment limit, provided * that the part of the segment above the buffer is all free. */ static void AMSTStressBufferedSeg(Seg seg, Buffer buffer) { AMSTSeg amstseg; AMST amst; Arena arena; Addr limit; Buffer segBuf; AVERT(Seg, seg); AVERT(Buffer, buffer); AVER(SegBuffer(&segBuf, seg) && segBuf == buffer); amstseg = Seg2AMSTSeg(seg); AVERT(AMSTSeg, amstseg); limit = BufferLimit(buffer); arena = PoolArena(SegPool(seg)); amst = PoolAMST(SegPool(seg)); AVERT(AMST, amst); if (amstseg->next != NULL) { Seg segHi = AMSTSeg2Seg(amstseg->next); if (AMSSegIsFree(segHi) && SegGrey(segHi) == SegGrey(seg)) { /* .bmerge */ Seg mergedSeg; Res res; res = SegMerge(&mergedSeg, seg, segHi); if (ResOK == res) { amst->bmerges++; printf("J"); } else { /* deliberate fails only */ AVER(amst->failSegs); } } } if (SegLimit(seg) != limit && AddrIsArenaGrain(limit, arena) && AMSSegRegionIsFree(seg, limit, SegLimit(seg))) { /* .bsplit */ Seg segLo, segHi; Res res; res = SegSplit(&segLo, &segHi, seg, limit); if (ResOK == res) { amst->bsplits++; printf("C"); } else { /* deliberate fails only */ AVER(amst->failSegs); } } }
/* 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 */ /* Must remove from free list first, in case free list */ /* is using inline data structures. */ res = CBSDelete(CBSOfMVFF(mvff), segBase, segLimit); AVER(res == ResOK); mvff->free -= AddrOffset(segBase, segLimit); mvff->total -= AddrOffset(segBase, segLimit); SegFree(seg); } /* 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 = SegNext(&seg, arena, segBase); AVER(b); segBase = SegBase(seg); segLimit = SegLimit(seg); } return; }
static void segBufAttach(Buffer buffer, Addr base, Addr limit, Addr init, Size size) { SegBuf segbuf = MustBeA(SegBuf, buffer); Seg seg = NULL; /* suppress "may be used uninitialized" */ Arena arena; Bool found; /* Other parameters are consistency checked in BufferAttach */ UNUSED(init); UNUSED(size); arena = BufferArena(buffer); found = SegOfAddr(&seg, arena, base); AVER(found); AVER(segbuf->seg == NULL); AVER(!SegHasBuffer(seg)); AVER(SegBase(seg) <= base); AVER(limit <= SegLimit(seg)); /* attach the buffer to the segment */ SegSetBuffer(seg, buffer); segbuf->seg = seg; AVERT(SegBuf, segbuf); }
static int ReadWrite( int (*r)(word,dword,char*), addr48_ptr *addr, char *data, int req ) { int len; word segment; dword offset; offset = addr->offset; segment = addr->segment; _DBG2(("Read Write %4.4x:%8.8lx",segment,offset)); if( SegLimit( segment ) >= offset + req - 1 ) { _DBG2(("Read Write Ok for %d", req)); if( !r( segment, offset, data ) ) { segment = AltSegment( segment ); } if( SegLimit( segment ) < offset + req - 1 ) { _DBG3(("Gosh, we're in trouble dudes")); if( SegLimit( segment ) == 0 ) { _DBG3(("Gosh, we're in SERIOUS trouble dudes")); } } else { len = req; while( --len >= 0 ) { if( !r( segment, offset++, data++ ) ) { _DBG3(("failed for %4.4x:%8.8lx", segment, offset-1)); } } _DBG2(("Read Write Done")); return( req ); } } len = 0; _DBG2(("Read Write One byte at a time for %d", req)); while( --req >= 0 ) { if( SegLimit( segment ) < offset ) break; if( !r( segment, offset, data ) ) { segment = AltSegment( segment ); } if( !r( segment, offset++, data++ ) ) { _DBG3(("failed for %4.4x:%8.8lx", segment, offset-1)); } ++len; } _DBG2(("Read Write Done")); return( len ); }
static Res MVFFAlloc(Addr *aReturn, Pool pool, Size size, Bool withReservoirPermit, DebugInfo info) { Res res; MVFF mvff; Addr base, limit; Bool foundBlock; AVERT(Pool, pool); mvff = Pool2MVFF(pool); AVERT(MVFF, mvff); AVER(aReturn != NULL); AVER(size > 0); AVER(BoolCheck(withReservoirPermit)); UNUSED(info); size = SizeAlignUp(size, PoolAlignment(pool)); foundBlock = MVFFFindFirstFree(&base, &limit, mvff, size); if (!foundBlock) { Seg seg; res = MVFFAddSeg(&seg, mvff, size, withReservoirPermit); if (res != ResOK) return res; foundBlock = MVFFFindFirstFree(&base, &limit, mvff, size); /* We know that the found range must intersect the new segment. */ /* In particular, it doesn't necessarily lie entirely within it. */ /* The next three AVERs test for intersection of two intervals. */ AVER(base >= SegBase(seg) || limit <= SegLimit(seg)); AVER(base < SegLimit(seg)); AVER(SegBase(seg) < limit); /* We also know that the found range is no larger than the segment. */ AVER(SegSize(seg) >= AddrOffset(base, limit)); } AVER(foundBlock); AVER(AddrOffset(base, limit) == size); *aReturn = base; return ResOK; }
static void shieldSync(Shield shield, Seg seg) { SHIELD_AVERT_CRITICAL(Seg, seg); if (!SegIsSynced(seg)) { shieldSetPM(shield, seg, SegSM(seg)); ProtSet(SegBase(seg), SegLimit(seg), SegPM(seg)); } }
void BufferReassignSeg(Buffer buffer, Seg seg) { AVERT(Buffer, buffer); AVERT(Seg, seg); AVER(!BufferIsReset(buffer)); AVER(BufferBase(buffer) >= SegBase(seg)); AVER(BufferLimit(buffer) <= SegLimit(seg)); AVER(BufferPool(buffer) == SegPool(seg)); Method(Buffer, buffer, reassignSeg)(buffer, seg); }
Res PoolAddrObject(Addr *pReturn, Pool pool, Seg seg, Addr addr) { AVER(pReturn != NULL); AVERT(Pool, pool); AVERT(Seg, seg); AVER(pool == SegPool(seg)); AVER(SegBase(seg) <= addr); AVER(addr < SegLimit(seg)); return Method(Pool, pool, addrObject)(pReturn, pool, seg, addr); }
int init_once(RP rp) { switch (done_init) { case 2: /* fatal error */ return 2; case 0: /* must init */ Device_Help = rp->pk.init.devhlp; /* read cmd line params */ read_args(rp->pk.init.args); done_init = 1; /* allocate memory */ buf1 = AllocBuf(32l * sizeof(struct tty)); buf2 = AllocBuf(32l * sizeof(struct tty)); if (!buf1 || !buf2) { /* fatal */ rp->pk.initexit.cs = 0; rp->pk.initexit.ds = 0; done_init = 2; return 2; } DosPutMessage(1, sizeof(version_msg) - 1, version_msg); DosPutMessage(1, sizeof(once_msg) - 1, once_msg); if (dbgflag) { DosPutMessage(1, sizeof(dbg_msg) - 1, dbg_msg); int3(); } /* fall thru */ case 1: /* ok */ #define GETSEL(ptr) ((USHORT)(((ULONG)((void far*)ptr)>>16)&0xffff)) SegLimit(GETSEL(DiscardProc),&rp->pk.initexit.cs); SegLimit(GETSEL(&DiscardData),&rp->pk.initexit.ds); } return 1; }
static void shieldProtLower(Shield shield, Seg seg, AccessSet mode) { /* <design/trace/#fix.noaver> */ SHIELD_AVERT_CRITICAL(Seg, seg); AVERT_CRITICAL(AccessSet, mode); if (BS_INTER(SegPM(seg), mode) != AccessSetEMPTY) { shieldSetPM(shield, seg, BS_DIFF(SegPM(seg), mode)); ProtSet(SegBase(seg), SegLimit(seg), SegPM(seg)); } }
static void shieldSync(Arena arena, Seg seg) { AVERT(Arena, arena); AVERT(Seg, seg); if (SegPM(seg) != SegSM(seg)) { ProtSet(SegBase(seg), SegLimit(seg), SegSM(seg)); SegSetPM(seg, SegSM(seg)); /* inv.prot.shield */ } }
Res PoolAccess(Pool pool, Seg seg, Addr addr, AccessSet mode, MutatorFaultContext context) { AVERT(Pool, pool); AVERT(Seg, seg); AVER(SegBase(seg) <= addr); AVER(addr < SegLimit(seg)); AVERT(AccessSet, mode); /* Can't check MutatorFaultContext as there is no check method */ return Method(Pool, pool, access)(pool, seg, addr, mode, context); }
/* This ensures actual prot mode does not include mode */ static void protLower(Arena arena, Seg seg, AccessSet mode) { /* <design/trace/#fix.noaver> */ AVERT_CRITICAL(Arena, arena); UNUSED(arena); AVERT_CRITICAL(Seg, seg); if (SegPM(seg) & mode) { SegSetPM(seg, SegPM(seg) & ~mode); ProtSet(SegBase(seg), SegLimit(seg), SegPM(seg)); } }
static word LookUp( word sdtseg, word seg, word global ) { dword sdtoff; dword sdtlim; dword linear; word otherseg; sdtlim = SegLimit( sdtseg ); linear = GetLinear( seg, 0 ); for( sdtoff = 0; sdtoff < sdtlim; sdtoff += 8 ) { if( sdtoff == ( seg & 0xfff8 ) ) continue; otherseg = sdtoff + ( global ? 0 : 4 ); if( !WriteOk( otherseg ) ) continue; if( GetLinear( otherseg, 0 ) != linear ) continue; _DBG3(("lookup %4.4x", otherseg)); return( otherseg ); } return( 0 ); }
static void shieldFlushEntries(Shield shield) { Addr base = NULL, limit; AccessSet mode; Index i; if (shield->length == 0) { AVER(shield->queue == NULL); return; } QuickSort((void *)shield->queue, shield->limit, shieldQueueEntryCompare, UNUSED_POINTER, &shield->sortStruct); mode = AccessSetEMPTY; limit = NULL; for (i = 0; i < shield->limit; ++i) { Seg seg = shieldDequeue(shield, i); if (!SegIsSynced(seg)) { shieldSetPM(shield, seg, SegSM(seg)); if (SegSM(seg) != mode || SegBase(seg) != limit) { if (base != NULL) { AVER(base < limit); ProtSet(base, limit, mode); } base = SegBase(seg); mode = SegSM(seg); } limit = SegLimit(seg); } } if (base != NULL) { AVER(base < limit); ProtSet(base, limit, mode); } shieldQueueReset(shield); }
/* 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; }
/* 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; }