diff --git a/mps/code/global.c b/mps/code/global.c index ce8885daf04..111404d03f8 100644 --- a/mps/code/global.c +++ b/mps/code/global.c @@ -154,39 +154,8 @@ Bool GlobalsCheck(Globals arenaGlobals) CHECKD_NOSIG(Ring, &arena->threadRing); CHECKD_NOSIG(Ring, &arena->deadRing); - CHECKL(BoolCheck(arena->insideShield)); - CHECKL(arena->shCache == NULL || arena->shCacheLength > 0); - CHECKL(arena->shCacheLimit <= arena->shCacheLength); - CHECKL(arena->shCacheI <= arena->shCacheLimit); - CHECKL(BoolCheck(arena->suspended)); + CHECKD_NOSIG(Shield, &arena->shieldStruct); /* FIXME: Sig */ - /* The mutator is not suspended while outside the shield - (design.mps.shield.inv.outside.running). */ - CHECKL(arena->insideShield || !arena->suspended); - - /* If any segment is not synced, the mutator is suspended - (design.mps.shield.inv.unsynced.suspended). */ - CHECKL(arena->shDepth == 0 || arena->suspended); - - /* The total depth is zero while outside the shield - (design.mps.shield.inv.outside.depth). */ - CHECKL(arena->insideShield || arena->shDepth == 0); - - /* This is too expensive to check all the time since we have an - expanding shield cache that often has 16K elements instead of - 16. */ -#if defined(AVER_AND_CHECK_ALL) - { - Count depth = 0; - for (i = 0; i < arena->shCacheLimit; ++i) { - Seg seg = arena->shCache[i]; - CHECKD(Seg, seg); - depth += SegDepth(seg); - } - CHECKL(depth <= arena->shDepth); - } -#endif - CHECKL(TraceSetCheck(arena->busyTraces)); CHECKL(TraceSetCheck(arena->flippedTraces)); CHECKL(TraceSetSuper(arena->busyTraces, arena->flippedTraces)); @@ -311,13 +280,7 @@ Res GlobalsInit(Globals arenaGlobals) arena->tracedWork = 0.0; arena->tracedTime = 0.0; arena->lastWorldCollect = ClockNow(); - arena->insideShield = FALSE; /* */ - arena->shCache = NULL; - arena->shCacheLength = 0; - arena->shCacheI = (Size)0; - arena->shCacheLimit = (Size)0; - arena->shDepth = (Size)0; - arena->suspended = FALSE; + ShieldInit(&arena->shieldStruct); for (ti = 0; ti < TraceLIMIT; ++ti) { /* */ @@ -455,14 +418,7 @@ void GlobalsPrepareToDestroy(Globals arenaGlobals) arena = GlobalsArena(arenaGlobals); - /* Delete the shield cache, if it exists. */ - if (arena->shCacheLength != 0) { - AVER(arena->shCache != NULL); - ControlFree(arena, arena->shCache, - arena->shCacheLength * sizeof arena->shCache[0]); - arena->shCache = NULL; - arena->shCacheLength = 0; - } + ShieldFinish(&arena->shieldStruct, arena); arenaDenounce(arena); @@ -1027,7 +983,6 @@ Res GlobalsDescribe(Globals arenaGlobals, mps_lib_FILE *stream, Count depth) "rootSerial $U\n", (WriteFU)arenaGlobals->rootSerial, "formatSerial $U\n", (WriteFU)arena->formatSerial, "threadSerial $U\n", (WriteFU)arena->threadSerial, - arena->insideShield ? "inside" : "outside", " shield\n", "busyTraces $B\n", (WriteFB)arena->busyTraces, "flippedTraces $B\n", (WriteFB)arena->flippedTraces, "epoch $U\n", (WriteFU)arena->epoch, @@ -1046,14 +1001,7 @@ Res GlobalsDescribe(Globals arenaGlobals, mps_lib_FILE *stream, Count depth) return res; } - res = WriteF(stream, depth, - "} history\n", - "suspended $S\n", WriteFYesNo(arena->suspended), - "shDepth $U\n", (WriteFU)arena->shDepth, - "shCacheI $U\n", (WriteFU)arena->shCacheI, - "shCacheLength $U\n", (WriteFU)arena->shCacheLength, - /* @@@@ should SegDescribe the cached segs? */ - NULL); + res = ShieldDescribe(&arena->shieldStruct, stream, depth); if (res != ResOK) return res; diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 96f28ffc840..21e9e82182a 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -907,6 +907,10 @@ extern ZoneSet ZoneSetBlacklist(Arena arena); /* Shield Interface -- see */ +extern void ShieldInit(Shield shield); +extern void ShieldFinish(Shield shield, Arena arena); +extern Bool ShieldCheck(Shield shield); +extern Res ShieldDescribe(Shield shield, mps_lib_FILE *stream, Count depth); extern void (ShieldRaise)(Arena arena, Seg seg, AccessSet mode); extern void (ShieldLower)(Arena arena, Seg seg, AccessSet mode); extern void (ShieldEnter)(Arena arena); diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h index 1ee48063c8d..29ad117bbcd 100644 --- a/mps/code/mpmst.h +++ b/mps/code/mpmst.h @@ -677,9 +677,29 @@ typedef struct FreelistStruct { } FreelistStruct; +/* ShieldStruct -- per-arena part of the shield + * + * See design.mps.shield, impl.c.shield. + */ + +#define ShieldSig ((Sig)0x519581E1) /* SIGnature SHEILd */ + +typedef struct ShieldStruct { + Sig sig; + Bool inside; /* TRUE if and only if inside shield */ + Seg *cache; /* Cache of unsynced segs */ + Count length; /* number of elements in shield cache */ + Index i; /* index into cache */ + Index limit; /* High water mark for cache usage */ + Count depth; /* sum of depths of all segs */ + Bool suspended; /* TRUE iff mutator suspended */ +} ShieldStruct; + + /* ArenaStruct -- generic arena * - * See . */ + * See . + */ #define ArenaSig ((Sig)0x519A6E4A) /* SIGnature ARENA */ @@ -737,16 +757,9 @@ typedef struct mps_arena_s { RingStruct threadRing; /* ring of attached threads */ RingStruct deadRing; /* ring of dead threads */ Serial threadSerial; /* serial of next thread */ - - /* shield fields () */ - Bool insideShield; /* TRUE if and only if inside shield */ - Seg *shCache; /* Cache of unsynced segs */ - Count shCacheLength; - Size shCacheI; /* index into cache */ - Size shCacheLimit; /* High water mark for cache usage */ - Size shDepth; /* sum of depths of all segs */ - Bool suspended; /* TRUE iff mutator suspended */ + ShieldStruct shieldStruct; + /* trace fields () */ TraceSet busyTraces; /* set of running traces */ TraceSet flippedTraces; /* set of running and flipped traces */ diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h index 2e0837940a2..f001038bc9f 100644 --- a/mps/code/mpmtypes.h +++ b/mps/code/mpmtypes.h @@ -112,6 +112,7 @@ typedef struct RangeStruct *Range; /* */ typedef struct LandStruct *Land; /* */ typedef struct LandClassStruct *LandClass; /* */ typedef unsigned FindDelete; /* */ +typedef struct ShieldStruct *Shield; /* design.mps.shield */ /* Arena*Method -- see */ diff --git a/mps/code/poolmrg.c b/mps/code/poolmrg.c index 92b1819fa68..554ec2a7319 100644 --- a/mps/code/poolmrg.c +++ b/mps/code/poolmrg.c @@ -821,7 +821,7 @@ static Res MRGDescribe(Pool pool, mps_lib_FILE *stream, Count depth) if (res != ResOK) return res; RING_FOR(node, &mrg->entryRing, nextNode) { - Bool outsideShield = !arena->insideShield; + Bool outsideShield = !arena->shieldStruct.inside; refPart = MRGRefPartOfLink(linkOfRing(node), arena); if (outsideShield) { ShieldEnter(arena); diff --git a/mps/code/shield.c b/mps/code/shield.c index be5c3c80e04..8ba806a701a 100644 --- a/mps/code/shield.c +++ b/mps/code/shield.c @@ -15,6 +15,95 @@ SRCID(shield, "$Id$"); +void ShieldInit(Shield shield) +{ + shield->inside = FALSE; + shield->cache = NULL; + shield->length = 0; + shield->i = 0; + shield->limit = 0; + shield->depth = 0; + shield->suspended = FALSE; + shield->sig = ShieldSig; +} + + +void ShieldFinish(Shield shield, Arena arena) +{ + shield->sig = SigInvalid; + /* Delete the shield cache, if it exists. */ + if (shield->length != 0) { + AVER(shield->cache != NULL); + ControlFree(arena, shield->cache, + shield->length * sizeof shield->cache[0]); + shield->cache = NULL; + shield->length = 0; + } +} + + +Bool ShieldCheck(Shield shield) +{ + CHECKS(Shield, shield); + CHECKL(BoolCheck(shield->inside)); + CHECKL(shield->cache == NULL || shield->length > 0); + CHECKL(shield->limit <= shield->length); + CHECKL(shield->i <= shield->limit); + CHECKL(BoolCheck(shield->suspended)); + + /* The mutator is not suspended while outside the shield + (design.mps.shield.inv.outside.running). */ + CHECKL(shield->inside || !shield->suspended); + + /* If any segment is not synced, the mutator is suspended + (design.mps.shield.inv.unsynced.suspended). */ + CHECKL(shield->depth == 0 || shield->suspended); + + /* The total depth is zero while outside the shield + (design.mps.shield.inv.outside.depth). */ + CHECKL(shield->inside || shield->depth == 0); + + /* This is too expensive to check all the time since we have an + expanding shield cache that often has 16K elements instead of + 16. */ +#if defined(AVER_AND_CHECK_ALL) + { + Count depth = 0; + Index i; + for (i = 0; i < shield->limit; ++i) { + Seg seg = shield->cache[i]; + CHECKD(Seg, seg); + depth += SegDepth(seg); + } + CHECKL(depth <= shield->depth); + } +#endif + + return TRUE; +} + + +Res ShieldDescribe(Shield shield, mps_lib_FILE *stream, Count depth) +{ + Res res; + + res = WriteF(stream, depth, + shield->inside ? "inside" : "outside", " shield\n", + "suspended $S\n", WriteFYesNo(shield->suspended), + "shield depth $U\n", (WriteFU)shield->depth, + "shield i $U\n", (WriteFU)shield->i, + "shield length $U\n", (WriteFU)shield->length, + NULL); + if (res != ResOK) + return res; + + return ResOK; +} + + +#define ArenaShield(arena) (&(arena)->shieldStruct) + + /* SHIELD_AVER -- transgressive argument checking * * .trans.check: A number of shield functions cannot do normal @@ -57,9 +146,9 @@ static Bool SegIsExposed(Seg seg) * See design.mps.shield.inv.prot.shield. */ -static void shieldSync(Arena arena, Seg seg) +static void shieldSync(Shield shield, Seg seg) { - AVERT(Arena, arena); + UNUSED(shield); SHIELD_AVERT_CRITICAL(Seg, seg); if (!SegIsSynced(seg)) { @@ -81,12 +170,15 @@ static void shieldSync(Arena arena, Seg seg) void (ShieldSuspend)(Arena arena) { + Shield shield; + AVERT(Arena, arena); - AVER(arena->insideShield); + shield = ArenaShield(arena); + AVER(shield->inside); - if (!arena->suspended) { + if (!shield->suspended) { ThreadRingSuspend(ArenaThreadRing(arena), ArenaDeadRing(arena)); - arena->suspended = TRUE; + shield->suspended = TRUE; } } @@ -99,9 +191,13 @@ void (ShieldSuspend)(Arena arena) void (ShieldResume)(Arena arena) { + Shield shield; + AVERT(Arena, arena); - AVER(arena->insideShield); - AVER(arena->suspended); + shield = ArenaShield(arena); + AVER(shield->inside); + AVER(shield->suspended); + /* It is only correct to actually resume the mutator here if shDepth is 0 */ /* TODO: Consider actually doing that. */ } @@ -112,11 +208,9 @@ void (ShieldResume)(Arena arena) * This ensures actual prot mode does not include mode. */ -static void shieldProtLower(Arena arena, Seg seg, AccessSet mode) +static void shieldProtLower(Seg seg, AccessSet mode) { /* */ - AVERT_CRITICAL(Arena, arena); - UNUSED(arena); SHIELD_AVERT_CRITICAL(Seg, seg); AVERT_CRITICAL(AccessSet, mode); @@ -129,14 +223,14 @@ static void shieldProtLower(Arena arena, Seg seg, AccessSet mode) /* shieldDecache -- remove a segment from the shield cache */ -static Seg shieldDecache(Arena arena, Index i) +static Seg shieldDecache(Shield shield, Index i) { Seg seg; - AVER(i < arena->shCacheLimit); - seg = arena->shCache[i]; + AVER(i < shield->limit); + seg = shield->cache[i]; AVERT(Seg, seg); AVER(seg->cached); - arena->shCache[i] = NULL; + shield->cache[i] = NULL; seg->cached = FALSE; return seg; } @@ -144,22 +238,22 @@ static Seg shieldDecache(Arena arena, Index i) /* shieldFlushEntry -- flush a single entry from the cache */ -static void shieldFlushEntry(Arena arena, Index i) +static void shieldFlushEntry(Shield shield, Index i) { - Seg seg = shieldDecache(arena, i); + Seg seg = shieldDecache(shield, i); if (!SegIsExposed(seg)) - shieldSync(arena, seg); + shieldSync(shield, seg); } /* shieldCacheReset -- reset shield cache pointers */ -static void shieldCacheReset(Arena arena) +static void shieldCacheReset(Shield shield) { - AVER(arena->shDepth == 0); /* overkill: implies no segs are cached */ - arena->shCacheI = 0; - arena->shCacheLimit = 0; + AVER(shield->depth == 0); /* overkill: implies no segs are cached */ + shield->i = 0; + shield->limit = 0; } @@ -202,23 +296,23 @@ static Compare shieldCacheEntryCompare(void *left, void *right, void *closure) * require design.mps.shield.improve.noseg. */ -static void shieldFlushEntries(Arena arena) +static void shieldFlushEntries(Shield shield) { Addr base = NULL, limit = NULL; AccessSet mode; Index i; - if (arena->shCacheLength == 0) { - AVER(arena->shCache == NULL); + if (shield->length == 0) { + AVER(shield->cache == NULL); return; } - QuickSort((void *)arena->shCache, arena->shCacheLimit, + QuickSort((void *)shield->cache, shield->limit, shieldCacheEntryCompare, UNUSED_POINTER); mode = AccessSetEMPTY; - for (i = 0; i < arena->shCacheLimit; ++i) { - Seg seg = shieldDecache(arena, i); + for (i = 0; i < shield->limit; ++i) { + Seg seg = shieldDecache(shield, i); if (!SegIsSynced(seg)) { AVER(SegSM(seg) != AccessSetEMPTY); /* can't match first iter */ SegSetPM(seg, SegSM(seg)); @@ -240,7 +334,7 @@ static void shieldFlushEntries(Arena arena) ProtSet(base, limit, mode); } - shieldCacheReset(arena); + shieldCacheReset(shield); } @@ -252,8 +346,11 @@ static void shieldFlushEntries(Arena arena) static void shieldCache(Arena arena, Seg seg) { + Shield shield; + /* */ AVERT_CRITICAL(Arena, arena); + shield = ArenaShield(arena); SHIELD_AVERT_CRITICAL(Seg, seg); if (SegIsSynced(seg) || seg->cached) @@ -271,31 +368,31 @@ static void shieldCache(Arena arena, Seg seg) /* Allocate shield cache if necessary. */ /* TODO: This will try to extend the cache on every attempt, even if it failed last time. That might be slow. */ - if (arena->shCacheI >= arena->shCacheLength) { + if (shield->i >= shield->length) { void *p; Res res; Count length; - AVER(arena->shCacheI == arena->shCacheLength); + AVER(shield->i == shield->length); - if (arena->shCacheLength == 0) + if (shield->length == 0) length = ShieldCacheLENGTH; else - length = arena->shCacheLength * 2; + length = shield->length * 2; - res = ControlAlloc(&p, arena, length * sizeof arena->shCache[0]); + res = ControlAlloc(&p, arena, length * sizeof shield->cache[0]); if (res != ResOK) { AVER(ResIsAllocFailure(res)); /* Carry on with the existing cache. */ } else { - if (arena->shCacheLength > 0) { - Size oldSize = arena->shCacheLength * sizeof arena->shCache[0]; - AVER(arena->shCache != NULL); - mps_lib_memcpy(p, arena->shCache, oldSize); - ControlFree(arena, arena->shCache, oldSize); + if (shield->length > 0) { + Size oldSize = shield->length * sizeof shield->cache[0]; + AVER(shield->cache != NULL); + mps_lib_memcpy(p, shield->cache, oldSize); + ControlFree(arena, shield->cache, oldSize); } - arena->shCache = p; - arena->shCacheLength = length; + shield->cache = p; + shield->length = length; } } @@ -303,35 +400,35 @@ static void shieldCache(Arena arena, Seg seg) yet suspended and the code raises the shield on a covered segment, protect it now, because that's probably better than suspending the mutator. */ - if (arena->shCacheLength == 0 || !arena->suspended) { - shieldSync(arena, seg); + if (shield->length == 0 || !shield->suspended) { + shieldSync(shield, seg); return; } - AVER_CRITICAL(arena->shCacheLimit <= arena->shCacheLength); - AVER_CRITICAL(arena->shCacheI <= arena->shCacheLimit); + AVER_CRITICAL(shield->limit <= shield->length); + AVER_CRITICAL(shield->i <= shield->limit); - if (arena->shCacheI >= arena->shCacheLength) - arena->shCacheI = 0; - AVER_CRITICAL(arena->shCacheI < arena->shCacheLength); + if (shield->i >= shield->length) + shield->i = 0; + AVER_CRITICAL(shield->i < shield->length); - AVER_CRITICAL(arena->shCacheLength > 0); + AVER_CRITICAL(shield->length > 0); /* If the limit is less than the length, then the cache array has yet to be filled, and shCacheI is an uninitialized entry. Otherwise it's the tail end from last time around, and needs to be flushed. */ - if (arena->shCacheLimit >= arena->shCacheLength) { - AVER_CRITICAL(arena->shCacheLimit == arena->shCacheLength); - shieldFlushEntry(arena, arena->shCacheI); + if (shield->limit >= shield->length) { + AVER_CRITICAL(shield->limit == shield->length); + shieldFlushEntry(shield, shield->i); } - arena->shCache[arena->shCacheI] = seg; - ++arena->shCacheI; + shield->cache[shield->i] = seg; + ++shield->i; seg->cached = TRUE; - if (arena->shCacheI >= arena->shCacheLimit) - arena->shCacheLimit = arena->shCacheI; + if (shield->i >= shield->limit) + shield->limit = shield->i; } @@ -343,6 +440,7 @@ static void shieldCache(Arena arena, Seg seg) void (ShieldRaise)(Arena arena, Seg seg, AccessSet mode) { + SHIELD_AVERT(Arena, arena); SHIELD_AVERT(Seg, seg); @@ -376,7 +474,7 @@ void (ShieldLower)(Arena arena, Seg seg, AccessSet mode) /* TODO: Do we need to promptly call shieldProtLower here? It loses the opportunity to coalesce the protection call. It would violate design.mps.shield.prop.inside.access. */ - shieldProtLower(arena, seg, mode); + shieldProtLower(seg, mode); /* Check cache and segment consistency. */ AVERT(Arena, arena); @@ -388,14 +486,17 @@ void (ShieldLower)(Arena arena, Seg seg, AccessSet mode) void (ShieldEnter)(Arena arena) { + Shield shield; + AVERT(Arena, arena); - AVER(!arena->insideShield); - AVER(arena->shDepth == 0); - AVER(!arena->suspended); + shield = ArenaShield(arena); + AVER(!shield->inside); + AVER(shield->depth == 0); + AVER(!shield->suspended); - shieldCacheReset(arena); + shieldCacheReset(shield); - arena->insideShield = TRUE; + shield->inside = TRUE; } @@ -414,15 +515,17 @@ void (ShieldEnter)(Arena arena) #if defined(SHIELD_DEBUG) static void shieldDebugCheck(Arena arena) { + Shield shield; Seg seg; Count cached = 0; AVERT(Arena, arena); - AVER(arena->insideShield || arena->shCacheLimit == 0); + shield = ShieldArena(arena); + AVER(shield->inside || shield->limit == 0); if (SegFirst(&seg, arena)) do { - if (arena->shCacheLimit == 0) { + if (shield->limit == 0) { AVER(!seg->cached); AVER(SegIsSynced(seg)); /* You can directly set protections here to see if it makes a @@ -434,7 +537,7 @@ static void shieldDebugCheck(Arena arena) } } while(SegNext(&seg, arena, seg)); - AVER(cached == arena->shCacheLimit); + AVER(cached == shield->limit); } #endif @@ -455,12 +558,16 @@ static void shieldDebugCheck(Arena arena) void (ShieldFlush)(Arena arena) { + Shield shield; + + AVERT(Arena, arena); + shield = ArenaShield(arena); #ifdef SHIELD_DEBUG shieldDebugCheck(arena); #endif - shieldFlushEntries(arena); + shieldFlushEntries(shield); /* Cache is empty so .inv.outside.depth holds */ - AVER(arena->shDepth == 0); + AVER(shield->depth == 0); #ifdef SHIELD_DEBUG shieldDebugCheck(arena); #endif @@ -471,20 +578,23 @@ void (ShieldFlush)(Arena arena) void (ShieldLeave)(Arena arena) { + Shield shield; + AVERT(Arena, arena); - AVER(arena->insideShield); - AVER(arena->shDepth == 0); /* no pending covers */ + shield = ArenaShield(arena); + AVER(shield->inside); + AVER(shield->depth == 0); /* no pending covers */ ShieldFlush(arena); /* Ensuring the mutator is running at this point guarantees .inv.outside.running */ - if (arena->suspended) { + if (shield->suspended) { ThreadRingResume(ArenaThreadRing(arena), ArenaDeadRing(arena)); - arena->suspended = FALSE; + shield->suspended = FALSE; } - arena->insideShield = FALSE; + shield->inside = FALSE; } @@ -497,15 +607,18 @@ void (ShieldLeave)(Arena arena) void (ShieldExpose)(Arena arena, Seg seg) { + Shield shield; AccessSet mode = AccessREAD | AccessWRITE; + /* */ AVERT_CRITICAL(Arena, arena); - AVER_CRITICAL(arena->insideShield); + shield = ArenaShield(arena); + AVER_CRITICAL(shield->inside); SegSetDepth(seg, SegDepth(seg) + 1); AVER_CRITICAL(SegDepth(seg) > 0); /* overflow */ - ++arena->shDepth; - AVER_CRITICAL(arena->shDepth > 0); /* overflow */ + ++shield->depth; + AVER_CRITICAL(shield->depth > 0); /* overflow */ if (BS_INTER(SegPM(seg), mode) != AccessSetEMPTY) ShieldSuspend(arena); @@ -513,7 +626,7 @@ void (ShieldExpose)(Arena arena, Seg seg) /* Ensure design.mps.shield.inv.expose.prot. */ /* TODO: Mass exposure -- see design.mps.shield.improv.mass-expose. */ - shieldProtLower(arena, seg, mode); + shieldProtLower(seg, mode); } @@ -521,15 +634,18 @@ void (ShieldExpose)(Arena arena, Seg seg) void (ShieldCover)(Arena arena, Seg seg) { + Shield shield; + /* */ AVERT_CRITICAL(Arena, arena); + shield = ArenaShield(arena); AVERT_CRITICAL(Seg, seg); AVER_CRITICAL(SegPM(seg) == AccessSetEMPTY); AVER_CRITICAL(SegDepth(seg) > 0); SegSetDepth(seg, SegDepth(seg) - 1); - AVER_CRITICAL(arena->shDepth > 0); - --arena->shDepth; + AVER_CRITICAL(shield->depth > 0); + --shield->depth; /* Ensure design.mps.shield.inv.unsynced.depth. */ shieldCache(arena, seg);