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:
parent
ff0b6d1379
commit
e09dbaab0f
6 changed files with 226 additions and 144 deletions
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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 */
|
||||||
|
|
|
||||||
|
|
@ -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> */
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue