mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-01-07 20:30:32 -08:00
Catch up merge from master sources.
Copied from Perforce Change: 189088 ServerID: perforce.ravenbrook.com
This commit is contained in:
commit
080d135eec
31 changed files with 348 additions and 192 deletions
|
|
@ -87,6 +87,14 @@ static mps_res_t stress(mps_arena_t arena, mps_pool_debug_option_s *options,
|
|||
check_allocated_size(pool, ap, allocated);
|
||||
}
|
||||
|
||||
/* Check introspection functions */
|
||||
for (i = 0; i < NELEMS(ps); ++i) {
|
||||
mps_pool_t addr_pool = NULL;
|
||||
Insist(mps_arena_has_addr(arena, ps[i]));
|
||||
Insist(mps_addr_pool(&addr_pool, arena, ps[i]));
|
||||
Insist(addr_pool == pool);
|
||||
}
|
||||
|
||||
mps_pool_check_fenceposts(pool);
|
||||
|
||||
for (k=0; k<testLOOPS; ++k) {
|
||||
|
|
|
|||
|
|
@ -1004,7 +1004,7 @@ static Res arenaAllocFromLand(Tract *tractReturn, ZoneSet zones, Bool high,
|
|||
{
|
||||
Arena arena;
|
||||
RangeStruct range, oldRange;
|
||||
Chunk chunk;
|
||||
Chunk chunk = NULL; /* suppress uninit warning */
|
||||
Bool found, b;
|
||||
Index baseIndex;
|
||||
Count pages;
|
||||
|
|
@ -1455,10 +1455,10 @@ static void ArenaTrivCompact(Arena arena, Trace trace)
|
|||
|
||||
Bool ArenaHasAddr(Arena arena, Addr addr)
|
||||
{
|
||||
Seg seg;
|
||||
Tract tract;
|
||||
|
||||
AVERT(Arena, arena);
|
||||
return SegOfAddr(&seg, arena, addr);
|
||||
return TractOfAddr(&tract, arena, addr);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -992,7 +992,7 @@ static Size arenaUnmapSpare(Arena arena, Size size, Chunk filter)
|
|||
while (RingNext(node) != &vmArena->spareRing && purged < size) {
|
||||
Ring next = RingNext(node);
|
||||
Page page = PageOfSpareRing(next);
|
||||
Chunk chunk;
|
||||
Chunk chunk = NULL; /* suppress uninit warning */
|
||||
Bool b;
|
||||
/* Use the fact that the page table resides in the chunk to find the
|
||||
chunk that owns the page. */
|
||||
|
|
|
|||
|
|
@ -24,6 +24,9 @@
|
|||
#include "mps.h"
|
||||
#include "mpsavm.h"
|
||||
#include "mpscamc.h"
|
||||
#include "mpscams.h"
|
||||
#include "mpscawl.h"
|
||||
#include "mpsclo.h"
|
||||
#include "mpslib.h"
|
||||
#include "mpstd.h"
|
||||
#include "testlib.h"
|
||||
|
|
@ -37,6 +40,7 @@
|
|||
#define finalizationRATE 6
|
||||
#define gcINTERVAL ((size_t)150 * 1024)
|
||||
#define collectionCOUNT 3
|
||||
#define messageCOUNT 3
|
||||
|
||||
/* 3 words: wrapper | vector-len | first-slot */
|
||||
#define vectorSIZE (3*sizeof(mps_word_t))
|
||||
|
|
@ -95,35 +99,37 @@ enum {
|
|||
};
|
||||
|
||||
|
||||
static void *test(void *arg, size_t s)
|
||||
static void test(mps_arena_t arena, mps_pool_class_t pool_class)
|
||||
{
|
||||
unsigned i; /* index */
|
||||
size_t i; /* index */
|
||||
mps_ap_t ap;
|
||||
mps_fmt_t fmt;
|
||||
mps_chain_t chain;
|
||||
mps_pool_t amc;
|
||||
mps_pool_t pool;
|
||||
mps_res_t e;
|
||||
mps_root_t mps_root[2];
|
||||
mps_addr_t nullref = NULL;
|
||||
int state[rootCOUNT];
|
||||
mps_arena_t arena;
|
||||
void *p = NULL;
|
||||
mps_message_t message;
|
||||
size_t messages = 0;
|
||||
void *p;
|
||||
|
||||
arena = (mps_arena_t)arg;
|
||||
(void)s;
|
||||
printf("---- finalcv: pool class %s ----\n", pool_class->name);
|
||||
|
||||
die(mps_fmt_create_A(&fmt, arena, dylan_fmt_A()), "fmt_create\n");
|
||||
die(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create");
|
||||
die(mps_pool_create(&amc, arena, mps_class_amc(), fmt, chain),
|
||||
"pool_create amc\n");
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
MPS_ARGS_ADD(args, MPS_KEY_CHAIN, chain);
|
||||
MPS_ARGS_ADD(args, MPS_KEY_FORMAT, fmt);
|
||||
die(mps_pool_create_k(&pool, arena, pool_class, args), "pool_create\n");
|
||||
} MPS_ARGS_END(args);
|
||||
die(mps_root_create_table(&mps_root[0], arena, mps_rank_exact(), (mps_rm_t)0,
|
||||
root, (size_t)rootCOUNT),
|
||||
"root_create\n");
|
||||
die(mps_root_create_table(&mps_root[1], arena, mps_rank_exact(), (mps_rm_t)0,
|
||||
&p, (size_t)1),
|
||||
"root_create\n");
|
||||
die(mps_ap_create(&ap, amc, mps_rank_exact()), "ap_create\n");
|
||||
die(mps_ap_create(&ap, pool, mps_rank_exact()), "ap_create\n");
|
||||
|
||||
/* Make registered-for-finalization objects. */
|
||||
/* <design/poolmrg/#test.promise.ut.alloc> */
|
||||
|
|
@ -142,12 +148,10 @@ static void *test(void *arg, size_t s)
|
|||
}
|
||||
p = NULL;
|
||||
|
||||
die(ArenaDescribe(arena, mps_lib_get_stdout(), 0), "ArenaDescribe");
|
||||
|
||||
mps_message_type_enable(arena, mps_message_type_finalization());
|
||||
|
||||
/* <design/poolmrg/#test.promise.ut.churn> */
|
||||
while (mps_collections(arena) < collectionCOUNT) {
|
||||
while (messages < messageCOUNT && mps_collections(arena) < collectionCOUNT) {
|
||||
|
||||
/* Perhaps cause (minor) collection */
|
||||
churn(ap);
|
||||
|
|
@ -197,36 +201,34 @@ static void *test(void *arg, size_t s)
|
|||
if (rnd() % 2 == 0)
|
||||
root[objind] = objaddr;
|
||||
mps_message_discard(arena, message);
|
||||
++ messages;
|
||||
}
|
||||
}
|
||||
|
||||
/* @@@@ <design/poolmrg/#test.promise.ut.nofinal.check> missing */
|
||||
|
||||
mps_arena_park(arena);
|
||||
mps_ap_destroy(ap);
|
||||
mps_root_destroy(mps_root[1]);
|
||||
mps_root_destroy(mps_root[0]);
|
||||
mps_pool_destroy(amc);
|
||||
mps_pool_destroy(pool);
|
||||
mps_chain_destroy(chain);
|
||||
mps_fmt_destroy(fmt);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
mps_arena_t arena;
|
||||
mps_thr_t thread;
|
||||
void *r;
|
||||
|
||||
testlib_init(argc, argv);
|
||||
|
||||
die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE),
|
||||
"arena_create\n");
|
||||
die(mps_thread_reg(&thread, arena), "thread_reg\n");
|
||||
mps_tramp(&r, test, arena, 0);
|
||||
mps_thread_dereg(thread);
|
||||
|
||||
test(arena, mps_class_amc());
|
||||
test(arena, mps_class_amcz());
|
||||
test(arena, mps_class_awl());
|
||||
test(arena, mps_class_ams());
|
||||
test(arena, mps_class_lo());
|
||||
|
||||
mps_arena_destroy(arena);
|
||||
|
||||
printf("%s: Conclusion: Failed to find any defects.\n", argv[0]);
|
||||
|
|
|
|||
|
|
@ -153,6 +153,7 @@ Bool GlobalsCheck(Globals arenaGlobals)
|
|||
}
|
||||
|
||||
CHECKD_NOSIG(Ring, &arena->threadRing);
|
||||
CHECKD_NOSIG(Ring, &arena->deadRing);
|
||||
|
||||
CHECKL(BoolCheck(arena->insideShield));
|
||||
CHECKL(arena->shCacheLimit <= ShieldCacheSIZE);
|
||||
|
|
@ -277,6 +278,7 @@ Res GlobalsInit(Globals arenaGlobals)
|
|||
arenaGlobals->rememberedSummaryIndex = 0;
|
||||
|
||||
RingInit(&arena->threadRing);
|
||||
RingInit(&arena->deadRing);
|
||||
arena->threadSerial = (Serial)0;
|
||||
RingInit(&arena->formatRing);
|
||||
arena->formatSerial = (Serial)0;
|
||||
|
|
@ -405,6 +407,7 @@ void GlobalsFinish(Globals arenaGlobals)
|
|||
RingFinish(&arena->chainRing);
|
||||
RingFinish(&arena->messageRing);
|
||||
RingFinish(&arena->threadRing);
|
||||
RingFinish(&arena->deadRing);
|
||||
for(rank = RankMIN; rank < RankLIMIT; ++rank)
|
||||
RingFinish(&arena->greyRing[rank]);
|
||||
RingFinish(&arenaGlobals->rootRing);
|
||||
|
|
@ -495,6 +498,7 @@ void GlobalsPrepareToDestroy(Globals arenaGlobals)
|
|||
AVER(RingIsSingle(&arena->chainRing));
|
||||
AVER(RingIsSingle(&arena->messageRing));
|
||||
AVER(RingIsSingle(&arena->threadRing));
|
||||
AVER(RingIsSingle(&arena->deadRing));
|
||||
AVER(RingIsSingle(&arenaGlobals->rootRing));
|
||||
for(rank = RankMIN; rank < RankLIMIT; ++rank)
|
||||
AVER(RingIsSingle(&arena->greyRing[rank]));
|
||||
|
|
@ -858,17 +862,19 @@ Bool ArenaStep(Globals globals, double interval, double multiplier)
|
|||
Res ArenaFinalize(Arena arena, Ref obj)
|
||||
{
|
||||
Res res;
|
||||
Pool refpool;
|
||||
|
||||
AVERT(Arena, arena);
|
||||
AVER(ArenaHasAddr(arena, (Addr)obj));
|
||||
AVER(PoolOfAddr(&refpool, arena, (Addr)obj));
|
||||
AVER(PoolHasAttr(refpool, AttrGC));
|
||||
|
||||
if (!arena->isFinalPool) {
|
||||
Pool pool;
|
||||
Pool finalpool;
|
||||
|
||||
res = PoolCreate(&pool, arena, PoolClassMRG(), argsNone);
|
||||
res = PoolCreate(&finalpool, arena, PoolClassMRG(), argsNone);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
arena->finalPool = pool;
|
||||
arena->finalPool = finalpool;
|
||||
arena->isFinalPool = TRUE;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -521,6 +521,7 @@ extern Ring GlobalsRememberedSummaryRing(Globals);
|
|||
#define GlobalsArena(glob) PARENT(ArenaStruct, globals, glob)
|
||||
|
||||
#define ArenaThreadRing(arena) (&(arena)->threadRing)
|
||||
#define ArenaDeadRing(arena) (&(arena)->deadRing)
|
||||
#define ArenaEpoch(arena) ((arena)->epoch) /* .epoch.ts */
|
||||
#define ArenaTrace(arena, ti) (&(arena)->trace[ti])
|
||||
#define ArenaZoneShift(arena) ((arena)->zoneShift)
|
||||
|
|
|
|||
|
|
@ -755,6 +755,7 @@ typedef struct mps_arena_s {
|
|||
|
||||
/* thread fields (<code/thread.c>) */
|
||||
RingStruct threadRing; /* ring of attached threads */
|
||||
RingStruct deadRing; /* ring of dead threads */
|
||||
Serial threadSerial; /* serial of next thread */
|
||||
|
||||
/* shield fields (<code/shield.c>) */
|
||||
|
|
|
|||
|
|
@ -233,6 +233,7 @@ static void ap_create_v_test(mps_pool_t pool, ...)
|
|||
/* addr_pool_test
|
||||
*
|
||||
* intended to test:
|
||||
* mps_arena_has_addr
|
||||
* mps_addr_pool
|
||||
* mps_addr_fmt
|
||||
*/
|
||||
|
|
@ -270,6 +271,7 @@ static void addr_pool_test(mps_arena_t arena,
|
|||
addr = obj1;
|
||||
pool = poolDistinguished;
|
||||
fmt = fmtDistinguished;
|
||||
cdie(mps_arena_has_addr(arena, addr), "mps_arena_has_addr 0a");
|
||||
b = mps_addr_pool(&pool, arena, addr);
|
||||
/* printf("b %d; pool %p; sig %lx\n", b, (void *)pool,
|
||||
b ? ((mps_word_t*)pool)[0] : (mps_word_t)0); */
|
||||
|
|
@ -283,6 +285,7 @@ static void addr_pool_test(mps_arena_t arena,
|
|||
addr = obj2;
|
||||
pool = poolDistinguished;
|
||||
fmt = fmtDistinguished;
|
||||
cdie(mps_arena_has_addr(arena, addr), "mps_arena_has_addr 0b");
|
||||
b = mps_addr_pool(&pool, arena, addr);
|
||||
/* printf("b %d; pool %p; sig %lx\n", b, (void *)pool,
|
||||
b ? ((mps_word_t*)pool)[0] : (mps_word_t)0); */
|
||||
|
|
@ -296,6 +299,7 @@ static void addr_pool_test(mps_arena_t arena,
|
|||
addr = &pool; /* point at stack, not in any chunk */
|
||||
pool = poolDistinguished;
|
||||
fmt = fmtDistinguished;
|
||||
cdie(mps_arena_has_addr(arena, addr) == FALSE, "mps_arena_has_addr 5");
|
||||
b = mps_addr_pool(&pool, arena, addr);
|
||||
cdie(b == FALSE && pool == poolDistinguished, "mps_addr_pool 5");
|
||||
b = mps_addr_fmt(&fmt, arena, addr);
|
||||
|
|
|
|||
|
|
@ -745,7 +745,12 @@ Res MRGRegister(Pool pool, Ref ref)
|
|||
}
|
||||
|
||||
|
||||
/* MRGDeregister -- deregister (once) an object for finalization */
|
||||
/* MRGDeregister -- deregister (once) an object for finalization
|
||||
*
|
||||
* TODO: Definalization loops over all finalizable objects in the heap,
|
||||
* and so using it could accidentally be disastrous for performance.
|
||||
* See job003953 and back out changelist 187123 if this is fixed.
|
||||
*/
|
||||
|
||||
Res MRGDeregister(Pool pool, Ref obj)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ void (ShieldSuspend)(Arena arena)
|
|||
AVER(arena->insideShield);
|
||||
|
||||
if (!arena->suspended) {
|
||||
ThreadRingSuspend(ArenaThreadRing(arena));
|
||||
ThreadRingSuspend(ArenaThreadRing(arena), ArenaDeadRing(arena));
|
||||
arena->suspended = TRUE;
|
||||
}
|
||||
}
|
||||
|
|
@ -266,7 +266,7 @@ void (ShieldLeave)(Arena arena)
|
|||
/* Ensuring the mutator is running at this point
|
||||
* guarantees inv.outside.running */
|
||||
if (arena->suspended) {
|
||||
ThreadRingResume(ArenaThreadRing(arena));
|
||||
ThreadRingResume(ArenaThreadRing(arena), ArenaDeadRing(arena));
|
||||
arena->suspended = FALSE;
|
||||
}
|
||||
arena->insideShield = FALSE;
|
||||
|
|
|
|||
|
|
@ -47,13 +47,14 @@ extern void ThreadDeregister(Thread thread, Arena arena);
|
|||
|
||||
/* ThreadRingSuspend/Resume
|
||||
*
|
||||
* These functions suspend/resume the threads on the ring.
|
||||
* If the current thread is among them, it is not suspended,
|
||||
* nor is any attempt to resume it made.
|
||||
* These functions suspend/resume the threads on the ring. If the
|
||||
* current thread is among them, it is not suspended, nor is any
|
||||
* attempt to resume it made. Threads that can't be suspended/resumed
|
||||
* because they are dead are moved to deadRing.
|
||||
*/
|
||||
|
||||
extern void ThreadRingSuspend(Ring threadRing);
|
||||
extern void ThreadRingResume(Ring threadRing);
|
||||
extern void ThreadRingSuspend(Ring threadRing, Ring deadRing);
|
||||
extern void ThreadRingResume(Ring threadRing, Ring deadRing);
|
||||
|
||||
|
||||
/* ThreadRingThread
|
||||
|
|
|
|||
|
|
@ -86,14 +86,16 @@ void ThreadDeregister(Thread thread, Arena arena)
|
|||
}
|
||||
|
||||
|
||||
void ThreadRingSuspend(Ring threadRing)
|
||||
void ThreadRingSuspend(Ring threadRing, Ring deadRing)
|
||||
{
|
||||
AVERT(Ring, threadRing);
|
||||
AVERT(Ring, deadRing);
|
||||
}
|
||||
|
||||
void ThreadRingResume(Ring threadRing)
|
||||
void ThreadRingResume(Ring threadRing, Ring deadRing)
|
||||
{
|
||||
AVERT(Ring, threadRing);
|
||||
AVERT(Ring, deadRing);
|
||||
}
|
||||
|
||||
Thread ThreadRingThread(Ring threadRing)
|
||||
|
|
|
|||
|
|
@ -12,10 +12,10 @@
|
|||
*
|
||||
* ASSUMPTIONS
|
||||
*
|
||||
* .error.resume: PThreadextResume is assumed to succeed unless the thread
|
||||
* has been destroyed.
|
||||
* .error.suspend: PThreadextSuspend is assumed to succeed unless the thread
|
||||
* has been destroyed. In this case, the suspend context is set to NULL;
|
||||
* .error.resume: PThreadextResume is assumed to succeed unless the
|
||||
* thread has been terminated.
|
||||
* .error.suspend: PThreadextSuspend is assumed to succeed unless the
|
||||
* thread has been terminated.
|
||||
*
|
||||
* .stack.full-descend: assumes full descending stack.
|
||||
* i.e. stack pointer points to the last allocated location;
|
||||
|
|
@ -48,9 +48,10 @@ typedef struct mps_thr_s { /* PThreads thread structure */
|
|||
Serial serial; /* from arena->threadSerial */
|
||||
Arena arena; /* owning arena */
|
||||
RingStruct arenaRing; /* threads attached to arena */
|
||||
Bool alive; /* thread believed to be alive? */
|
||||
PThreadextStruct thrextStruct; /* PThreads extension */
|
||||
pthread_t id; /* Pthread object of thread */
|
||||
MutatorFaultContext mfc; /* Context if thread is suspended */
|
||||
MutatorFaultContext mfc; /* Context if suspended, NULL if not */
|
||||
} ThreadStruct;
|
||||
|
||||
|
||||
|
|
@ -62,6 +63,7 @@ Bool ThreadCheck(Thread thread)
|
|||
CHECKU(Arena, thread->arena);
|
||||
CHECKL(thread->serial < thread->arena->threadSerial);
|
||||
CHECKD_NOSIG(Ring, &thread->arenaRing);
|
||||
CHECKL(BoolCheck(thread->alive));
|
||||
CHECKD(PThreadext, &thread->thrextStruct);
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -98,6 +100,7 @@ Res ThreadRegister(Thread *threadReturn, Arena arena)
|
|||
thread->serial = arena->threadSerial;
|
||||
++arena->threadSerial;
|
||||
thread->arena = arena;
|
||||
thread->alive = TRUE;
|
||||
thread->mfc = NULL;
|
||||
|
||||
PThreadextInit(&thread->thrextStruct, thread->id);
|
||||
|
|
@ -130,69 +133,83 @@ void ThreadDeregister(Thread thread, Arena arena)
|
|||
}
|
||||
|
||||
|
||||
/* mapThreadRing -- map over threads on ring calling a function on each one
|
||||
* except the current thread
|
||||
/* mapThreadRing -- map over threads on ring calling a function on
|
||||
* each one except the current thread.
|
||||
*
|
||||
* Threads that are found to be dead (that is, if func returns FALSE)
|
||||
* are moved to deadRing, in order to implement
|
||||
* design.thread-manager.sol.thread.term.attempt.
|
||||
*/
|
||||
|
||||
static void mapThreadRing(Ring threadRing, void (*func)(Thread))
|
||||
static void mapThreadRing(Ring threadRing, Ring deadRing, Bool (*func)(Thread))
|
||||
{
|
||||
Ring node, next;
|
||||
pthread_t self;
|
||||
|
||||
AVERT(Ring, threadRing);
|
||||
AVERT(Ring, deadRing);
|
||||
AVER(FUNCHECK(func));
|
||||
|
||||
self = pthread_self();
|
||||
RING_FOR(node, threadRing, next) {
|
||||
Thread thread = RING_ELT(Thread, arenaRing, node);
|
||||
AVERT(Thread, thread);
|
||||
if(! pthread_equal(self, thread->id)) /* .thread.id */
|
||||
(*func)(thread);
|
||||
AVER(thread->alive);
|
||||
if (!pthread_equal(self, thread->id) /* .thread.id */
|
||||
&& !(*func)(thread))
|
||||
{
|
||||
thread->alive = FALSE;
|
||||
RingRemove(&thread->arenaRing);
|
||||
RingAppend(deadRing, &thread->arenaRing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ThreadRingSuspend -- suspend all threads on a ring, expect the current one */
|
||||
/* ThreadRingSuspend -- suspend all threads on a ring, except the
|
||||
* current one.
|
||||
*/
|
||||
|
||||
|
||||
static void threadSuspend(Thread thread)
|
||||
static Bool threadSuspend(Thread thread)
|
||||
{
|
||||
/* .error.suspend */
|
||||
/* In the error case (PThreadextSuspend returning ResFAIL), we */
|
||||
/* assume the thread has been destroyed. */
|
||||
/* In which case we simply continue. */
|
||||
/* .error.suspend: if PThreadextSuspend fails, we assume the thread
|
||||
* has been terminated. */
|
||||
Res res;
|
||||
AVER(thread->mfc == NULL);
|
||||
res = PThreadextSuspend(&thread->thrextStruct, &thread->mfc);
|
||||
if(res != ResOK)
|
||||
thread->mfc = NULL;
|
||||
AVER(res == ResOK);
|
||||
AVER(thread->mfc != NULL);
|
||||
/* design.thread-manager.sol.thread.term.attempt */
|
||||
return res == ResOK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ThreadRingSuspend(Ring threadRing)
|
||||
void ThreadRingSuspend(Ring threadRing, Ring deadRing)
|
||||
{
|
||||
mapThreadRing(threadRing, threadSuspend);
|
||||
mapThreadRing(threadRing, deadRing, threadSuspend);
|
||||
}
|
||||
|
||||
|
||||
/* ThreadRingResume -- resume all threads on a ring (expect the current one) */
|
||||
|
||||
|
||||
static void threadResume(Thread thread)
|
||||
static Bool threadResume(Thread thread)
|
||||
{
|
||||
/* .error.resume */
|
||||
/* If the previous suspend failed (thread->mfc == NULL), */
|
||||
/* or in the error case (PThreadextResume returning ResFAIL), */
|
||||
/* assume the thread has been destroyed. */
|
||||
/* In which case we simply continue. */
|
||||
if(thread->mfc != NULL) {
|
||||
(void)PThreadextResume(&thread->thrextStruct);
|
||||
thread->mfc = NULL;
|
||||
}
|
||||
Res res;
|
||||
/* .error.resume: If PThreadextResume fails, we assume the thread
|
||||
* has been terminated. */
|
||||
AVER(thread->mfc != NULL);
|
||||
res = PThreadextResume(&thread->thrextStruct);
|
||||
AVER(res == ResOK);
|
||||
thread->mfc = NULL;
|
||||
/* design.thread-manager.sol.thread.term.attempt */
|
||||
return res == ResOK;
|
||||
}
|
||||
|
||||
void ThreadRingResume(Ring threadRing)
|
||||
void ThreadRingResume(Ring threadRing, Ring deadRing)
|
||||
{
|
||||
mapThreadRing(threadRing, threadResume);
|
||||
mapThreadRing(threadRing, deadRing, threadResume);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -231,20 +248,16 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
|
|||
self = pthread_self();
|
||||
if(pthread_equal(self, thread->id)) {
|
||||
/* scan this thread's stack */
|
||||
AVER(thread->alive);
|
||||
res = StackScan(ss, stackBot);
|
||||
if(res != ResOK)
|
||||
return res;
|
||||
} else {
|
||||
} else if (thread->alive) {
|
||||
MutatorFaultContext mfc;
|
||||
Addr *stackBase, *stackLimit, stackPtr;
|
||||
|
||||
mfc = thread->mfc;
|
||||
if(mfc == NULL) {
|
||||
/* .error.suspend */
|
||||
/* We assume that the thread must have been destroyed. */
|
||||
/* We ignore the situation by returning immediately. */
|
||||
return ResOK;
|
||||
}
|
||||
AVER(mfc != NULL);
|
||||
|
||||
stackPtr = MutatorFaultContextSP(mfc);
|
||||
/* .stack.align */
|
||||
|
|
@ -280,6 +293,7 @@ Res ThreadDescribe(Thread thread, mps_lib_FILE *stream, Count depth)
|
|||
"Thread $P ($U) {\n", (WriteFP)thread, (WriteFU)thread->serial,
|
||||
" arena $P ($U)\n",
|
||||
(WriteFP)thread->arena, (WriteFU)thread->arena->serial,
|
||||
" alive $S\n", WriteFYesNo(thread->alive),
|
||||
" id $U\n", (WriteFU)thread->id,
|
||||
"} Thread $P ($U)\n", (WriteFP)thread, (WriteFU)thread->serial,
|
||||
NULL);
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ Res ThreadRegister(Thread *threadReturn, Arena arena)
|
|||
thread->serial = arena->threadSerial;
|
||||
++arena->threadSerial;
|
||||
thread->arena = arena;
|
||||
thread->alive = TRUE;
|
||||
|
||||
AVERT(Thread, thread);
|
||||
|
||||
|
|
@ -138,60 +139,66 @@ void ThreadDeregister(Thread thread, Arena arena)
|
|||
}
|
||||
|
||||
|
||||
/* Map over threads on ring calling f on each one except the
|
||||
* current thread.
|
||||
/* mapThreadRing -- map over threads on ring calling a function on
|
||||
* each one except the current thread.
|
||||
*
|
||||
* Threads that are found to be dead (that is, if func returns FALSE)
|
||||
* are moved to deadRing.
|
||||
*/
|
||||
static void mapThreadRing(Ring ring, void (*f)(Thread thread))
|
||||
|
||||
static void mapThreadRing(Ring threadRing, Ring deadRing, Bool (*func)(Thread))
|
||||
{
|
||||
Ring node;
|
||||
Ring node, next;
|
||||
DWORD id;
|
||||
|
||||
AVERT(Ring, threadRing);
|
||||
AVERT(Ring, deadRing);
|
||||
AVER(FUNCHECK(func));
|
||||
|
||||
id = GetCurrentThreadId();
|
||||
node = RingNext(ring);
|
||||
while(node != ring) {
|
||||
Ring next = RingNext(node);
|
||||
Thread thread;
|
||||
|
||||
thread = RING_ELT(Thread, arenaRing, node);
|
||||
RING_FOR(node, threadRing, next) {
|
||||
Thread thread = RING_ELT(Thread, arenaRing, node);
|
||||
AVERT(Thread, thread);
|
||||
if(id != thread->id) /* .thread.id */
|
||||
(*f)(thread);
|
||||
|
||||
node = next;
|
||||
AVER(thread->alive);
|
||||
if (id != thread->id /* .thread.id */
|
||||
&& !(*func)(thread))
|
||||
{
|
||||
thread->alive = FALSE;
|
||||
RingRemove(&thread->arenaRing);
|
||||
RingAppend(deadRing, &thread->arenaRing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void suspend(Thread thread)
|
||||
static Bool suspendThread(Thread thread)
|
||||
{
|
||||
/* .thread.handle.susp-res */
|
||||
/* .error.suspend */
|
||||
/* In the error case (SuspendThread returning 0xFFFFFFFF), we */
|
||||
/* assume the thread has been destroyed (as part of process shutdown). */
|
||||
/* In which case we simply continue. */
|
||||
/* In the error case (SuspendThread returning -1), we */
|
||||
/* assume the thread has been terminated. */
|
||||
/* [GetLastError appears to return 5 when SuspendThread is called */
|
||||
/* on a destroyed thread, but I'm not sufficiently confident of this */
|
||||
/* on a terminated thread, but I'm not sufficiently confident of this */
|
||||
/* to check -- drj 1998-04-09] */
|
||||
(void)SuspendThread(thread->handle);
|
||||
return SuspendThread(thread->handle) != (DWORD)-1;
|
||||
}
|
||||
|
||||
void ThreadRingSuspend(Ring ring)
|
||||
void ThreadRingSuspend(Ring threadRing, Ring deadRing)
|
||||
{
|
||||
mapThreadRing(ring, suspend);
|
||||
mapThreadRing(threadRing, deadRing, suspendThread);
|
||||
}
|
||||
|
||||
static void resume(Thread thread)
|
||||
static Bool resumeThread(Thread thread)
|
||||
{
|
||||
/* .thread.handle.susp-res */
|
||||
/* .error.resume */
|
||||
/* In the error case (ResumeThread returning 0xFFFFFFFF), we */
|
||||
/* assume the thread has been destroyed (as part of process shutdown). */
|
||||
/* In which case we simply continue. */
|
||||
(void)ResumeThread(thread->handle);
|
||||
/* In the error case (ResumeThread returning -1), we */
|
||||
/* assume the thread has been terminated. */
|
||||
return ResumeThread(thread->handle) != (DWORD)-1;
|
||||
}
|
||||
|
||||
void ThreadRingResume(Ring ring)
|
||||
void ThreadRingResume(Ring threadRing, Ring deadRing)
|
||||
{
|
||||
mapThreadRing(ring, resume);
|
||||
mapThreadRing(threadRing, deadRing, resumeThread);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -220,6 +227,7 @@ Res ThreadDescribe(Thread thread, mps_lib_FILE *stream, Count depth)
|
|||
"Thread $P ($U) {\n", (WriteFP)thread, (WriteFU)thread->serial,
|
||||
" arena $P ($U)\n",
|
||||
(WriteFP)thread->arena, (WriteFU)thread->arena->serial,
|
||||
" alive $S\n", WriteFYesNo(thread->alive),
|
||||
" handle $W\n", (WriteFW)thread->handle,
|
||||
" id $U\n", (WriteFU)thread->id,
|
||||
"} Thread $P ($U)\n", (WriteFP)thread, (WriteFU)thread->serial,
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ typedef struct mps_thr_s { /* Win32 thread structure */
|
|||
Serial serial; /* from arena->threadSerial */
|
||||
Arena arena; /* owning arena */
|
||||
RingStruct arenaRing; /* threads attached to arena */
|
||||
Bool alive; /* thread believed to be alive? */
|
||||
HANDLE handle; /* Handle of thread, see
|
||||
* <code/thw3.c#thread.handle> */
|
||||
DWORD id; /* Thread id of thread */
|
||||
|
|
|
|||
|
|
@ -74,7 +74,13 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
|
|||
|
||||
id = GetCurrentThreadId();
|
||||
|
||||
if(id != thread->id) { /* .thread.id */
|
||||
if (id == thread->id) { /* .thread.id */
|
||||
/* scan this thread's stack */
|
||||
AVER(thread->alive);
|
||||
res = StackScan(ss, stackBot);
|
||||
if(res != ResOK)
|
||||
return res;
|
||||
} else if (thread->alive) {
|
||||
CONTEXT context;
|
||||
BOOL success;
|
||||
Addr *stackBase, *stackLimit, stackPtr;
|
||||
|
|
@ -116,11 +122,6 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
|
|||
(Addr *)((char *)&context + sizeof(CONTEXT)));
|
||||
if(res != ResOK)
|
||||
return res;
|
||||
|
||||
} else { /* scan this thread's stack */
|
||||
res = StackScan(ss, stackBot);
|
||||
if(res != ResOK)
|
||||
return res;
|
||||
}
|
||||
|
||||
return ResOK;
|
||||
|
|
|
|||
|
|
@ -74,7 +74,13 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
|
|||
|
||||
id = GetCurrentThreadId();
|
||||
|
||||
if(id != thread->id) { /* .thread.id */
|
||||
if (id == thread->id) { /* .thread.id */
|
||||
/* scan this thread's stack */
|
||||
AVER(thread->alive);
|
||||
res = StackScan(ss, stackBot);
|
||||
if(res != ResOK)
|
||||
return res;
|
||||
} else if (thread->alive) {
|
||||
CONTEXT context;
|
||||
BOOL success;
|
||||
Addr *stackBase, *stackLimit, stackPtr;
|
||||
|
|
@ -116,11 +122,6 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
|
|||
(Addr *)((char *)&context + sizeof(CONTEXT)));
|
||||
if(res != ResOK)
|
||||
return res;
|
||||
|
||||
} else { /* scan this thread's stack */
|
||||
res = StackScan(ss, stackBot);
|
||||
if(res != ResOK)
|
||||
return res;
|
||||
}
|
||||
|
||||
return ResOK;
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ typedef struct mps_thr_s { /* OS X / Mach thread structure */
|
|||
Serial serial; /* from arena->threadSerial */
|
||||
Arena arena; /* owning arena */
|
||||
RingStruct arenaRing; /* attaches to arena */
|
||||
Bool alive; /* thread believed to be alive? */
|
||||
thread_port_t port; /* thread kernel port */
|
||||
} ThreadStruct;
|
||||
|
||||
|
|
@ -46,6 +47,7 @@ Bool ThreadCheck(Thread thread)
|
|||
CHECKU(Arena, thread->arena);
|
||||
CHECKL(thread->serial < thread->arena->threadSerial);
|
||||
CHECKD_NOSIG(Ring, &thread->arenaRing);
|
||||
CHECKL(BoolCheck(thread->alive));
|
||||
CHECKL(MACH_PORT_VALID(thread->port));
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -78,6 +80,7 @@ Res ThreadRegister(Thread *threadReturn, Arena arena)
|
|||
|
||||
thread->serial = arena->threadSerial;
|
||||
++arena->threadSerial;
|
||||
thread->alive = TRUE;
|
||||
thread->port = mach_thread_self();
|
||||
thread->sig = ThreadSig;
|
||||
AVERT(Thread, thread);
|
||||
|
|
@ -108,62 +111,80 @@ void ThreadDeregister(Thread thread, Arena arena)
|
|||
}
|
||||
|
||||
|
||||
/* mapThreadRing -- map over threads on ring calling a function on each one
|
||||
* except the current thread
|
||||
/* mapThreadRing -- map over threads on ring calling a function on
|
||||
* each one except the current thread.
|
||||
*
|
||||
* Threads that are found to be dead (that is, if func returns FALSE)
|
||||
* are marked as dead and moved to deadRing, in order to implement
|
||||
* design.thread-manager.sol.thread.term.attempt.
|
||||
*/
|
||||
|
||||
static void mapThreadRing(Ring threadRing, void (*func)(Thread))
|
||||
static void mapThreadRing(Ring threadRing, Ring deadRing, Bool (*func)(Thread))
|
||||
{
|
||||
Ring node, next;
|
||||
mach_port_t self;
|
||||
|
||||
AVERT(Ring, threadRing);
|
||||
AVERT(Ring, deadRing);
|
||||
AVER(FUNCHECK(func));
|
||||
|
||||
self = mach_thread_self();
|
||||
AVER(MACH_PORT_VALID(self));
|
||||
RING_FOR(node, threadRing, next) {
|
||||
Thread thread = RING_ELT(Thread, arenaRing, node);
|
||||
AVERT(Thread, thread);
|
||||
if(thread->port != self)
|
||||
(*func)(thread);
|
||||
AVER(thread->alive);
|
||||
if (thread->port != self
|
||||
&& !(*func)(thread))
|
||||
{
|
||||
thread->alive = FALSE;
|
||||
RingRemove(&thread->arenaRing);
|
||||
RingAppend(deadRing, &thread->arenaRing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void threadSuspend(Thread thread)
|
||||
static Bool threadSuspend(Thread thread)
|
||||
{
|
||||
kern_return_t kern_return;
|
||||
kern_return = thread_suspend(thread->port);
|
||||
/* No rendezvous is necessary: thread_suspend "prevents the thread
|
||||
* from executing any more user-level instructions" */
|
||||
AVER(kern_return == KERN_SUCCESS);
|
||||
/* Experimentally, values other then KERN_SUCCESS indicate the thread has
|
||||
terminated <https://info.ravenbrook.com/mail/2014/10/25/18-12-36/0/>. */
|
||||
/* design.thread-manager.sol.thread.term.attempt */
|
||||
return kern_return == KERN_SUCCESS;
|
||||
}
|
||||
|
||||
static void threadResume(Thread thread)
|
||||
static Bool threadResume(Thread thread)
|
||||
{
|
||||
kern_return_t kern_return;
|
||||
kern_return = thread_resume(thread->port);
|
||||
/* Mach has no equivalent of EAGAIN. */
|
||||
AVER(kern_return == KERN_SUCCESS);
|
||||
/* Experimentally, values other then KERN_SUCCESS indicate the thread has
|
||||
terminated <https://info.ravenbrook.com/mail/2014/10/25/18-12-36/0/>. */
|
||||
/* design.thread-manager.sol.thread.term.attempt */
|
||||
return kern_return == KERN_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* ThreadRingSuspend -- suspend all threads on a ring, except the
|
||||
* current one.
|
||||
*/
|
||||
void ThreadRingSuspend(Ring threadRing)
|
||||
void ThreadRingSuspend(Ring threadRing, Ring deadRing)
|
||||
{
|
||||
AVERT(Ring, threadRing);
|
||||
mapThreadRing(threadRing, threadSuspend);
|
||||
mapThreadRing(threadRing, deadRing, threadSuspend);
|
||||
}
|
||||
|
||||
/* ThreadRingResume -- resume all threads on a ring, except the
|
||||
* current one.
|
||||
*/
|
||||
void ThreadRingResume(Ring threadRing)
|
||||
void ThreadRingResume(Ring threadRing, Ring deadRing)
|
||||
{
|
||||
AVERT(Ring, threadRing);
|
||||
mapThreadRing(threadRing, threadResume);
|
||||
mapThreadRing(threadRing, deadRing, threadResume);
|
||||
}
|
||||
|
||||
Thread ThreadRingThread(Ring threadRing)
|
||||
|
|
@ -199,17 +220,18 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
|
|||
AVER(MACH_PORT_VALID(self));
|
||||
if (thread->port == self) {
|
||||
/* scan this thread's stack */
|
||||
AVER(thread->alive);
|
||||
res = StackScan(ss, stackBot);
|
||||
if(res != ResOK)
|
||||
return res;
|
||||
} else {
|
||||
} else if (thread->alive) {
|
||||
MutatorFaultContextStruct mfcStruct;
|
||||
THREAD_STATE_S threadState;
|
||||
Addr *stackBase, *stackLimit, stackPtr;
|
||||
mach_msg_type_number_t count;
|
||||
kern_return_t kern_return;
|
||||
|
||||
/* Note: We could get the thread state and check the suspend cound in
|
||||
/* Note: We could get the thread state and check the suspend count in
|
||||
order to assert that the thread is suspended, but it's probably
|
||||
unnecessary and is a lot of work to check a static condition. */
|
||||
|
||||
|
|
@ -257,6 +279,7 @@ Res ThreadDescribe(Thread thread, mps_lib_FILE *stream, Count depth)
|
|||
"Thread $P ($U) {\n", (WriteFP)thread, (WriteFU)thread->serial,
|
||||
" arena $P ($U)\n",
|
||||
(WriteFP)thread->arena, (WriteFU)thread->arena->serial,
|
||||
" alive $S\n", WriteFYesNo(thread->alive),
|
||||
" port $U\n", (WriteFU)thread->port,
|
||||
"} Thread $P ($U)\n", (WriteFP)thread, (WriteFU)thread->serial,
|
||||
NULL);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue