test: extend coverage of noopThreadEntry
This commit is contained in:
1 parent
7c2a04ceb4
commit
d4cdde3ea0
1 file changed
+151
+151
@@ -0,0 +1,151 @@
|
||||
#include "ktest.h"
|
||||
#include "sched.h"
|
||||
#include "ports.h"
|
||||
#include "elf.h"
|
||||
#include "paging.h"
|
||||
#include "pmm.h"
|
||||
#include "pipe.h"
|
||||
#include "signal.h"
|
||||
#include "pit.h"
|
||||
#include "klib.h"
|
||||
|
||||
/*
|
||||
* ktestRunAll() runs before schedStart() (see ktest.h), on a single thread
|
||||
* with no live scheduler - there is no second execution context to actually
|
||||
* context-switch into, and no interrupts to wake a genuinely halted CPU.
|
||||
* The first block of tests below therefore exercises schedBlockCurrent/
|
||||
* schedWakeChannel as the pure state-machine they are (mark-blocked /
|
||||
* match-and-wake), using the always-present current thread (idle, id 0 at
|
||||
* this point in boot) rather than creating new threads.
|
||||
*
|
||||
* The second block tests threadCreate/threadReap/threadJoin's bookkeeping
|
||||
* (slot allocation, exhaustion, reuse, bounds-checking) directly: a thread
|
||||
* created here is never actually scheduled to run (the scheduler is not yet
|
||||
* live), so as long as every thread a test creates is reaped again before
|
||||
* the test returns, the real thread table is left exactly as it found it -
|
||||
* no throwaway slot is ever left behind to eat into kmain.c's later budget.
|
||||
* The one path that genuinely cannot be tested here is threadJoin() ever
|
||||
* actually parking (schedBlockCurrent + halt()) on a thread that is still
|
||||
* alive: that requires a second thread for the scheduler to switch to,
|
||||
* which does not exist before schedStart(). That path is instead proven
|
||||
* live by the join demo in kmain.c (needle "join-reap-ok" in ci-test.sh).
|
||||
*/
|
||||
|
||||
KTEST(schedBlockCurrentMarksBlockedWithChannel)
|
||||
{
|
||||
ThreadState saved = currentThread()->state;
|
||||
int channel;
|
||||
|
||||
schedBlockCurrent(&channel);
|
||||
KT_EQ(t, currentThread()->state, threadBlocked);
|
||||
KT_EQP(t, currentThread()->waitChannel, &channel);
|
||||
|
||||
schedWakeChannel(&channel);
|
||||
currentThread()->state = saved;
|
||||
}
|
||||
|
||||
KTEST(schedWakeChannelIgnoresMismatchedChannel)
|
||||
{
|
||||
ThreadState saved = currentThread()->state;
|
||||
int channelA;
|
||||
int channelB;
|
||||
|
||||
schedBlockCurrent(&channelA);
|
||||
KT_EQ(t, currentThread()->state, threadBlocked);
|
||||
|
||||
schedWakeChannel(&channelB);
|
||||
KT_EQ(t, currentThread()->state, threadBlocked);
|
||||
KT_EQP(t, currentThread()->waitChannel, &channelA);
|
||||
|
||||
schedWakeChannel(&channelA);
|
||||
KT_EQ(t, currentThread()->state, threadRunnable);
|
||||
|
||||
currentThread()->state = saved;
|
||||
}
|
||||
|
||||
KTEST(schedWakeChannelClearsWaitChannelOnWake)
|
||||
{
|
||||
ThreadState saved = currentThread()->state;
|
||||
int channel;
|
||||
|
||||
schedBlockCurrent(&channel);
|
||||
schedWakeChannel(&channel);
|
||||
KT_EQ(t, currentThread()->state, threadRunnable);
|
||||
KT_NULL(t, currentThread()->waitChannel);
|
||||
|
||||
currentThread()->state = saved;
|
||||
}
|
||||
|
||||
KTEST(schedPollChannelIsStableAndUsableLikeAnyOtherChannel)
|
||||
{
|
||||
ThreadState saved = currentThread()->state;
|
||||
|
||||
/* Same address every call -- every not-yet-satisfied sysPoll (poll.h)
|
||||
across every thread blocks on this ONE shared channel, so callers
|
||||
must never see it move. */
|
||||
KT_EQP(t, schedPollChannel(), schedPollChannel());
|
||||
KT_NOTNULL(t, schedPollChannel());
|
||||
|
||||
/* And it works exactly like any other channel schedBlockCurrent/
|
||||
schedWakeChannel already accept -- the schedule()-driven pollDeadline
|
||||
expiry scan (sched.c) that forces a wake even with nobody calling
|
||||
schedWakeChannel(schedPollChannel()) needs a live scheduler
|
||||
(schedulerActive) to run at all, so it is proven live instead, by
|
||||
user/polltest.c's real timeout phase (tools/ci-test.sh's
|
||||
"polltest: poll-timeout-ok" needle) -- the same split schedTest.c's
|
||||
own file comment already documents for sleepUntil/alarmAt. */
|
||||
schedBlockCurrent(schedPollChannel());
|
||||
KT_EQ(t, currentThread()->state, threadBlocked);
|
||||
KT_EQP(t, currentThread()->waitChannel, schedPollChannel());
|
||||
|
||||
schedWakeChannel(schedPollChannel());
|
||||
KT_EQ(t, currentThread()->state, threadRunnable);
|
||||
|
||||
currentThread()->state = saved;
|
||||
}
|
||||
|
||||
KTEST(schedWakeChannelWithNoWaiterIsHarmlessNoop)
|
||||
{
|
||||
ThreadState saved = currentThread()->state;
|
||||
int channel;
|
||||
|
||||
/* Nobody is blocked on this address: waking it must not touch any
|
||||
thread's state, including the caller's own. */
|
||||
schedWakeChannel(&channel);
|
||||
KT_EQ(t, currentThread()->state, saved);
|
||||
|
||||
currentThread()->state = saved;
|
||||
}
|
||||
|
||||
KTEST(schedBlockCurrentIsIdempotentUnderRepeatedCalls)
|
||||
{
|
||||
ThreadState saved = currentThread()->state;
|
||||
int channelA;
|
||||
int channelB;
|
||||
|
||||
schedBlockCurrent(&channelA);
|
||||
schedBlockCurrent(&channelB);
|
||||
KT_EQ(t, currentThread()->state, threadBlocked);
|
||||
KT_EQP(t, currentThread()->waitChannel, &channelB);
|
||||
|
||||
/* Waking the stale first channel must not affect a thread that has since
|
||||
re-blocked on a different one. */
|
||||
schedWakeChannel(&channelA);
|
||||
KT_EQ(t, currentThread()->state, threadBlocked);
|
||||
|
||||
schedWakeChannel(&channelB);
|
||||
KT_EQ(t, currentThread()->state, threadRunnable);
|
||||
|
||||
currentThread()->state = saved;
|
||||
}
|
||||
|
||||
/* Never actually invoked (the scheduler is not live yet) -- just a valid
|
||||
function pointer for threadCreate's entry parameter. If it were ever
|
||||
scheduled for real it would be a harmless, correctly-behaved kernel
|
||||
thread body (park forever), same convention as workerA/workerB. */
|
||||
static void noopThreadEntry(void)
|
||||
{
|
||||
for (;;)
|
||||
halt();
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user