1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-18 20:00:36 -08:00

Promoting shield to first class structure.

Copied from Perforce
 Change: 190219
 ServerID: perforce.ravenbrook.com
This commit is contained in:
Richard Brooksby 2016-03-20 00:32:43 +00:00
parent ff0b6d1379
commit e09dbaab0f
6 changed files with 226 additions and 144 deletions

View file

@ -154,39 +154,8 @@ Bool GlobalsCheck(Globals arenaGlobals)
CHECKD_NOSIG(Ring, &arena->threadRing); CHECKD_NOSIG(Ring, &arena->threadRing);
CHECKD_NOSIG(Ring, &arena->deadRing); CHECKD_NOSIG(Ring, &arena->deadRing);
CHECKL(BoolCheck(arena->insideShield)); CHECKD_NOSIG(Shield, &arena->shieldStruct); /* FIXME: Sig */
CHECKL(arena->shCache == NULL || arena->shCacheLength > 0);
CHECKL(arena->shCacheLimit <= arena->shCacheLength);
CHECKL(arena->shCacheI <= arena->shCacheLimit);
CHECKL(BoolCheck(arena->suspended));
/* 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->busyTraces));
CHECKL(TraceSetCheck(arena->flippedTraces)); CHECKL(TraceSetCheck(arena->flippedTraces));
CHECKL(TraceSetSuper(arena->busyTraces, arena->flippedTraces)); CHECKL(TraceSetSuper(arena->busyTraces, arena->flippedTraces));
@ -311,13 +280,7 @@ Res GlobalsInit(Globals arenaGlobals)
arena->tracedWork = 0.0; arena->tracedWork = 0.0;
arena->tracedTime = 0.0; arena->tracedTime = 0.0;
arena->lastWorldCollect = ClockNow(); arena->lastWorldCollect = ClockNow();
arena->insideShield = FALSE; /* <code/shield.c> */ ShieldInit(&arena->shieldStruct);
arena->shCache = NULL;
arena->shCacheLength = 0;
arena->shCacheI = (Size)0;
arena->shCacheLimit = (Size)0;
arena->shDepth = (Size)0;
arena->suspended = FALSE;
for (ti = 0; ti < TraceLIMIT; ++ti) { for (ti = 0; ti < TraceLIMIT; ++ti) {
/* <design/arena/#trace.invalid> */ /* <design/arena/#trace.invalid> */
@ -455,14 +418,7 @@ void GlobalsPrepareToDestroy(Globals arenaGlobals)
arena = GlobalsArena(arenaGlobals); arena = GlobalsArena(arenaGlobals);
/* Delete the shield cache, if it exists. */ ShieldFinish(&arena->shieldStruct, arena);
if (arena->shCacheLength != 0) {
AVER(arena->shCache != NULL);
ControlFree(arena, arena->shCache,
arena->shCacheLength * sizeof arena->shCache[0]);
arena->shCache = NULL;
arena->shCacheLength = 0;
}
arenaDenounce(arena); arenaDenounce(arena);
@ -1027,7 +983,6 @@ Res GlobalsDescribe(Globals arenaGlobals, mps_lib_FILE *stream, Count depth)
"rootSerial $U\n", (WriteFU)arenaGlobals->rootSerial, "rootSerial $U\n", (WriteFU)arenaGlobals->rootSerial,
"formatSerial $U\n", (WriteFU)arena->formatSerial, "formatSerial $U\n", (WriteFU)arena->formatSerial,
"threadSerial $U\n", (WriteFU)arena->threadSerial, "threadSerial $U\n", (WriteFU)arena->threadSerial,
arena->insideShield ? "inside" : "outside", " shield\n",
"busyTraces $B\n", (WriteFB)arena->busyTraces, "busyTraces $B\n", (WriteFB)arena->busyTraces,
"flippedTraces $B\n", (WriteFB)arena->flippedTraces, "flippedTraces $B\n", (WriteFB)arena->flippedTraces,
"epoch $U\n", (WriteFU)arena->epoch, "epoch $U\n", (WriteFU)arena->epoch,
@ -1046,14 +1001,7 @@ Res GlobalsDescribe(Globals arenaGlobals, mps_lib_FILE *stream, Count depth)
return res; return res;
} }
res = WriteF(stream, depth, res = ShieldDescribe(&arena->shieldStruct, 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);
if (res != ResOK) if (res != ResOK)
return res; return res;

View file

@ -907,6 +907,10 @@ extern ZoneSet ZoneSetBlacklist(Arena arena);
/* Shield Interface -- see <code/shield.c> */ /* Shield Interface -- see <code/shield.c> */
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 (ShieldRaise)(Arena arena, Seg seg, AccessSet mode);
extern void (ShieldLower)(Arena arena, Seg seg, AccessSet mode); extern void (ShieldLower)(Arena arena, Seg seg, AccessSet mode);
extern void (ShieldEnter)(Arena arena); extern void (ShieldEnter)(Arena arena);

View file

@ -677,9 +677,29 @@ typedef struct FreelistStruct {
} 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 /* ArenaStruct -- generic arena
* *
* See <code/arena.c>. */ * See <code/arena.c>.
*/
#define ArenaSig ((Sig)0x519A6E4A) /* SIGnature ARENA */ #define ArenaSig ((Sig)0x519A6E4A) /* SIGnature ARENA */
@ -737,16 +757,9 @@ typedef struct mps_arena_s {
RingStruct threadRing; /* ring of attached threads */ RingStruct threadRing; /* ring of attached threads */
RingStruct deadRing; /* ring of dead threads */ RingStruct deadRing; /* ring of dead threads */
Serial threadSerial; /* serial of next thread */ Serial threadSerial; /* serial of next thread */
/* shield fields (<code/shield.c>) */
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 (<code/trace.c>) */ /* trace fields (<code/trace.c>) */
TraceSet busyTraces; /* set of running traces */ TraceSet busyTraces; /* set of running traces */
TraceSet flippedTraces; /* set of running and flipped traces */ TraceSet flippedTraces; /* set of running and flipped traces */

View file

@ -112,6 +112,7 @@ typedef struct RangeStruct *Range; /* <design/range/> */
typedef struct LandStruct *Land; /* <design/land/> */ typedef struct LandStruct *Land; /* <design/land/> */
typedef struct LandClassStruct *LandClass; /* <design/land/> */ typedef struct LandClassStruct *LandClass; /* <design/land/> */
typedef unsigned FindDelete; /* <design/land/> */ typedef unsigned FindDelete; /* <design/land/> */
typedef struct ShieldStruct *Shield; /* design.mps.shield */
/* Arena*Method -- see <code/mpmst.h#ArenaClassStruct> */ /* Arena*Method -- see <code/mpmst.h#ArenaClassStruct> */

View file

@ -821,7 +821,7 @@ static Res MRGDescribe(Pool pool, mps_lib_FILE *stream, Count depth)
if (res != ResOK) if (res != ResOK)
return res; return res;
RING_FOR(node, &mrg->entryRing, nextNode) { RING_FOR(node, &mrg->entryRing, nextNode) {
Bool outsideShield = !arena->insideShield; Bool outsideShield = !arena->shieldStruct.inside;
refPart = MRGRefPartOfLink(linkOfRing(node), arena); refPart = MRGRefPartOfLink(linkOfRing(node), arena);
if (outsideShield) { if (outsideShield) {
ShieldEnter(arena); ShieldEnter(arena);

View file

@ -15,6 +15,95 @@
SRCID(shield, "$Id$"); 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 /* SHIELD_AVER -- transgressive argument checking
* *
* .trans.check: A number of shield functions cannot do normal * .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. * 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); SHIELD_AVERT_CRITICAL(Seg, seg);
if (!SegIsSynced(seg)) { if (!SegIsSynced(seg)) {
@ -81,12 +170,15 @@ static void shieldSync(Arena arena, Seg seg)
void (ShieldSuspend)(Arena arena) void (ShieldSuspend)(Arena arena)
{ {
Shield shield;
AVERT(Arena, arena); AVERT(Arena, arena);
AVER(arena->insideShield); shield = ArenaShield(arena);
AVER(shield->inside);
if (!arena->suspended) { if (!shield->suspended) {
ThreadRingSuspend(ArenaThreadRing(arena), ArenaDeadRing(arena)); ThreadRingSuspend(ArenaThreadRing(arena), ArenaDeadRing(arena));
arena->suspended = TRUE; shield->suspended = TRUE;
} }
} }
@ -99,9 +191,13 @@ void (ShieldSuspend)(Arena arena)
void (ShieldResume)(Arena arena) void (ShieldResume)(Arena arena)
{ {
Shield shield;
AVERT(Arena, arena); AVERT(Arena, arena);
AVER(arena->insideShield); shield = ArenaShield(arena);
AVER(arena->suspended); AVER(shield->inside);
AVER(shield->suspended);
/* It is only correct to actually resume the mutator here if shDepth is 0 */ /* It is only correct to actually resume the mutator here if shDepth is 0 */
/* TODO: Consider actually doing that. */ /* TODO: Consider actually doing that. */
} }
@ -112,11 +208,9 @@ void (ShieldResume)(Arena arena)
* This ensures actual prot mode does not include mode. * 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)
{ {
/* <design/trace/#fix.noaver> */ /* <design/trace/#fix.noaver> */
AVERT_CRITICAL(Arena, arena);
UNUSED(arena);
SHIELD_AVERT_CRITICAL(Seg, seg); SHIELD_AVERT_CRITICAL(Seg, seg);
AVERT_CRITICAL(AccessSet, mode); 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 */ /* shieldDecache -- remove a segment from the shield cache */
static Seg shieldDecache(Arena arena, Index i) static Seg shieldDecache(Shield shield, Index i)
{ {
Seg seg; Seg seg;
AVER(i < arena->shCacheLimit); AVER(i < shield->limit);
seg = arena->shCache[i]; seg = shield->cache[i];
AVERT(Seg, seg); AVERT(Seg, seg);
AVER(seg->cached); AVER(seg->cached);
arena->shCache[i] = NULL; shield->cache[i] = NULL;
seg->cached = FALSE; seg->cached = FALSE;
return seg; return seg;
} }
@ -144,22 +238,22 @@ static Seg shieldDecache(Arena arena, Index i)
/* shieldFlushEntry -- flush a single entry from the cache */ /* 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)) if (!SegIsExposed(seg))
shieldSync(arena, seg); shieldSync(shield, seg);
} }
/* shieldCacheReset -- reset shield cache pointers */ /* 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 */ AVER(shield->depth == 0); /* overkill: implies no segs are cached */
arena->shCacheI = 0; shield->i = 0;
arena->shCacheLimit = 0; shield->limit = 0;
} }
@ -202,23 +296,23 @@ static Compare shieldCacheEntryCompare(void *left, void *right, void *closure)
* require design.mps.shield.improve.noseg. * require design.mps.shield.improve.noseg.
*/ */
static void shieldFlushEntries(Arena arena) static void shieldFlushEntries(Shield shield)
{ {
Addr base = NULL, limit = NULL; Addr base = NULL, limit = NULL;
AccessSet mode; AccessSet mode;
Index i; Index i;
if (arena->shCacheLength == 0) { if (shield->length == 0) {
AVER(arena->shCache == NULL); AVER(shield->cache == NULL);
return; return;
} }
QuickSort((void *)arena->shCache, arena->shCacheLimit, QuickSort((void *)shield->cache, shield->limit,
shieldCacheEntryCompare, UNUSED_POINTER); shieldCacheEntryCompare, UNUSED_POINTER);
mode = AccessSetEMPTY; mode = AccessSetEMPTY;
for (i = 0; i < arena->shCacheLimit; ++i) { for (i = 0; i < shield->limit; ++i) {
Seg seg = shieldDecache(arena, i); Seg seg = shieldDecache(shield, i);
if (!SegIsSynced(seg)) { if (!SegIsSynced(seg)) {
AVER(SegSM(seg) != AccessSetEMPTY); /* can't match first iter */ AVER(SegSM(seg) != AccessSetEMPTY); /* can't match first iter */
SegSetPM(seg, SegSM(seg)); SegSetPM(seg, SegSM(seg));
@ -240,7 +334,7 @@ static void shieldFlushEntries(Arena arena)
ProtSet(base, limit, mode); ProtSet(base, limit, mode);
} }
shieldCacheReset(arena); shieldCacheReset(shield);
} }
@ -252,8 +346,11 @@ static void shieldFlushEntries(Arena arena)
static void shieldCache(Arena arena, Seg seg) static void shieldCache(Arena arena, Seg seg)
{ {
Shield shield;
/* <design/trace/#fix.noaver> */ /* <design/trace/#fix.noaver> */
AVERT_CRITICAL(Arena, arena); AVERT_CRITICAL(Arena, arena);
shield = ArenaShield(arena);
SHIELD_AVERT_CRITICAL(Seg, seg); SHIELD_AVERT_CRITICAL(Seg, seg);
if (SegIsSynced(seg) || seg->cached) if (SegIsSynced(seg) || seg->cached)
@ -271,31 +368,31 @@ static void shieldCache(Arena arena, Seg seg)
/* Allocate shield cache if necessary. */ /* Allocate shield cache if necessary. */
/* TODO: This will try to extend the cache on every attempt, even /* TODO: This will try to extend the cache on every attempt, even
if it failed last time. That might be slow. */ if it failed last time. That might be slow. */
if (arena->shCacheI >= arena->shCacheLength) { if (shield->i >= shield->length) {
void *p; void *p;
Res res; Res res;
Count length; Count length;
AVER(arena->shCacheI == arena->shCacheLength); AVER(shield->i == shield->length);
if (arena->shCacheLength == 0) if (shield->length == 0)
length = ShieldCacheLENGTH; length = ShieldCacheLENGTH;
else 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) { if (res != ResOK) {
AVER(ResIsAllocFailure(res)); AVER(ResIsAllocFailure(res));
/* Carry on with the existing cache. */ /* Carry on with the existing cache. */
} else { } else {
if (arena->shCacheLength > 0) { if (shield->length > 0) {
Size oldSize = arena->shCacheLength * sizeof arena->shCache[0]; Size oldSize = shield->length * sizeof shield->cache[0];
AVER(arena->shCache != NULL); AVER(shield->cache != NULL);
mps_lib_memcpy(p, arena->shCache, oldSize); mps_lib_memcpy(p, shield->cache, oldSize);
ControlFree(arena, arena->shCache, oldSize); ControlFree(arena, shield->cache, oldSize);
} }
arena->shCache = p; shield->cache = p;
arena->shCacheLength = length; 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 yet suspended and the code raises the shield on a covered
segment, protect it now, because that's probably better than segment, protect it now, because that's probably better than
suspending the mutator. */ suspending the mutator. */
if (arena->shCacheLength == 0 || !arena->suspended) { if (shield->length == 0 || !shield->suspended) {
shieldSync(arena, seg); shieldSync(shield, seg);
return; return;
} }
AVER_CRITICAL(arena->shCacheLimit <= arena->shCacheLength); AVER_CRITICAL(shield->limit <= shield->length);
AVER_CRITICAL(arena->shCacheI <= arena->shCacheLimit); AVER_CRITICAL(shield->i <= shield->limit);
if (arena->shCacheI >= arena->shCacheLength) if (shield->i >= shield->length)
arena->shCacheI = 0; shield->i = 0;
AVER_CRITICAL(arena->shCacheI < arena->shCacheLength); 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 /* If the limit is less than the length, then the cache array has
yet to be filled, and shCacheI is an uninitialized entry. yet to be filled, and shCacheI is an uninitialized entry.
Otherwise it's the tail end from last time around, and needs to Otherwise it's the tail end from last time around, and needs to
be flushed. */ be flushed. */
if (arena->shCacheLimit >= arena->shCacheLength) { if (shield->limit >= shield->length) {
AVER_CRITICAL(arena->shCacheLimit == arena->shCacheLength); AVER_CRITICAL(shield->limit == shield->length);
shieldFlushEntry(arena, arena->shCacheI); shieldFlushEntry(shield, shield->i);
} }
arena->shCache[arena->shCacheI] = seg; shield->cache[shield->i] = seg;
++arena->shCacheI; ++shield->i;
seg->cached = TRUE; seg->cached = TRUE;
if (arena->shCacheI >= arena->shCacheLimit) if (shield->i >= shield->limit)
arena->shCacheLimit = arena->shCacheI; shield->limit = shield->i;
} }
@ -343,6 +440,7 @@ static void shieldCache(Arena arena, Seg seg)
void (ShieldRaise)(Arena arena, Seg seg, AccessSet mode) void (ShieldRaise)(Arena arena, Seg seg, AccessSet mode)
{ {
SHIELD_AVERT(Arena, arena); SHIELD_AVERT(Arena, arena);
SHIELD_AVERT(Seg, seg); 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 /* TODO: Do we need to promptly call shieldProtLower here? It
loses the opportunity to coalesce the protection call. It would loses the opportunity to coalesce the protection call. It would
violate design.mps.shield.prop.inside.access. */ violate design.mps.shield.prop.inside.access. */
shieldProtLower(arena, seg, mode); shieldProtLower(seg, mode);
/* Check cache and segment consistency. */ /* Check cache and segment consistency. */
AVERT(Arena, arena); AVERT(Arena, arena);
@ -388,14 +486,17 @@ void (ShieldLower)(Arena arena, Seg seg, AccessSet mode)
void (ShieldEnter)(Arena arena) void (ShieldEnter)(Arena arena)
{ {
Shield shield;
AVERT(Arena, arena); AVERT(Arena, arena);
AVER(!arena->insideShield); shield = ArenaShield(arena);
AVER(arena->shDepth == 0); AVER(!shield->inside);
AVER(!arena->suspended); 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) #if defined(SHIELD_DEBUG)
static void shieldDebugCheck(Arena arena) static void shieldDebugCheck(Arena arena)
{ {
Shield shield;
Seg seg; Seg seg;
Count cached = 0; Count cached = 0;
AVERT(Arena, arena); AVERT(Arena, arena);
AVER(arena->insideShield || arena->shCacheLimit == 0); shield = ShieldArena(arena);
AVER(shield->inside || shield->limit == 0);
if (SegFirst(&seg, arena)) if (SegFirst(&seg, arena))
do { do {
if (arena->shCacheLimit == 0) { if (shield->limit == 0) {
AVER(!seg->cached); AVER(!seg->cached);
AVER(SegIsSynced(seg)); AVER(SegIsSynced(seg));
/* You can directly set protections here to see if it makes a /* 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)); } while(SegNext(&seg, arena, seg));
AVER(cached == arena->shCacheLimit); AVER(cached == shield->limit);
} }
#endif #endif
@ -455,12 +558,16 @@ static void shieldDebugCheck(Arena arena)
void (ShieldFlush)(Arena arena) void (ShieldFlush)(Arena arena)
{ {
Shield shield;
AVERT(Arena, arena);
shield = ArenaShield(arena);
#ifdef SHIELD_DEBUG #ifdef SHIELD_DEBUG
shieldDebugCheck(arena); shieldDebugCheck(arena);
#endif #endif
shieldFlushEntries(arena); shieldFlushEntries(shield);
/* Cache is empty so .inv.outside.depth holds */ /* Cache is empty so .inv.outside.depth holds */
AVER(arena->shDepth == 0); AVER(shield->depth == 0);
#ifdef SHIELD_DEBUG #ifdef SHIELD_DEBUG
shieldDebugCheck(arena); shieldDebugCheck(arena);
#endif #endif
@ -471,20 +578,23 @@ void (ShieldFlush)(Arena arena)
void (ShieldLeave)(Arena arena) void (ShieldLeave)(Arena arena)
{ {
Shield shield;
AVERT(Arena, arena); AVERT(Arena, arena);
AVER(arena->insideShield); shield = ArenaShield(arena);
AVER(arena->shDepth == 0); /* no pending covers */ AVER(shield->inside);
AVER(shield->depth == 0); /* no pending covers */
ShieldFlush(arena); ShieldFlush(arena);
/* Ensuring the mutator is running at this point guarantees /* Ensuring the mutator is running at this point guarantees
.inv.outside.running */ .inv.outside.running */
if (arena->suspended) { if (shield->suspended) {
ThreadRingResume(ArenaThreadRing(arena), ArenaDeadRing(arena)); 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) void (ShieldExpose)(Arena arena, Seg seg)
{ {
Shield shield;
AccessSet mode = AccessREAD | AccessWRITE; AccessSet mode = AccessREAD | AccessWRITE;
/* <design/trace/#fix.noaver> */ /* <design/trace/#fix.noaver> */
AVERT_CRITICAL(Arena, arena); AVERT_CRITICAL(Arena, arena);
AVER_CRITICAL(arena->insideShield); shield = ArenaShield(arena);
AVER_CRITICAL(shield->inside);
SegSetDepth(seg, SegDepth(seg) + 1); SegSetDepth(seg, SegDepth(seg) + 1);
AVER_CRITICAL(SegDepth(seg) > 0); /* overflow */ AVER_CRITICAL(SegDepth(seg) > 0); /* overflow */
++arena->shDepth; ++shield->depth;
AVER_CRITICAL(arena->shDepth > 0); /* overflow */ AVER_CRITICAL(shield->depth > 0); /* overflow */
if (BS_INTER(SegPM(seg), mode) != AccessSetEMPTY) if (BS_INTER(SegPM(seg), mode) != AccessSetEMPTY)
ShieldSuspend(arena); ShieldSuspend(arena);
@ -513,7 +626,7 @@ void (ShieldExpose)(Arena arena, Seg seg)
/* Ensure design.mps.shield.inv.expose.prot. */ /* Ensure design.mps.shield.inv.expose.prot. */
/* TODO: Mass exposure -- see /* TODO: Mass exposure -- see
design.mps.shield.improv.mass-expose. */ 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) void (ShieldCover)(Arena arena, Seg seg)
{ {
Shield shield;
/* <design/trace/#fix.noaver> */ /* <design/trace/#fix.noaver> */
AVERT_CRITICAL(Arena, arena); AVERT_CRITICAL(Arena, arena);
shield = ArenaShield(arena);
AVERT_CRITICAL(Seg, seg); AVERT_CRITICAL(Seg, seg);
AVER_CRITICAL(SegPM(seg) == AccessSetEMPTY); AVER_CRITICAL(SegPM(seg) == AccessSetEMPTY);
AVER_CRITICAL(SegDepth(seg) > 0); AVER_CRITICAL(SegDepth(seg) > 0);
SegSetDepth(seg, SegDepth(seg) - 1); SegSetDepth(seg, SegDepth(seg) - 1);
AVER_CRITICAL(arena->shDepth > 0); AVER_CRITICAL(shield->depth > 0);
--arena->shDepth; --shield->depth;
/* Ensure design.mps.shield.inv.unsynced.depth. */ /* Ensure design.mps.shield.inv.unsynced.depth. */
shieldCache(arena, seg); shieldCache(arena, seg);