test: extend coverage of sigTest
This commit is contained in:
1 parent
4740ca0a05
commit
98b0e27b43
1 file changed
+161
+161
@@ -312,3 +312,164 @@ KTEST(sigSetHandlerInstallsAndReturnsPreviousDisposition)
|
||||
KT_TRUE(t, threadDiscard(id));
|
||||
}
|
||||
|
||||
KTEST(sigSetHandlerRejectsSigKillAndOutOfRangeSignum)
|
||||
{
|
||||
uint32 id = threadCreate("sigHandlerBad", noopThreadEntry);
|
||||
KT_NE(t, id, threadInvalidId);
|
||||
Thread* thread = threadAt(id);
|
||||
|
||||
KT_EQU(t, sigSetHandler(thread, sigKill, 0x40005000ull, 0, 0), sigSetFailed);
|
||||
KT_EQU(t, thread->sigHandlers[sigKill], sigHandlerDefault);
|
||||
|
||||
KT_EQU(t, sigSetHandler(thread, 0, 0x40005000ull, 0, 0), sigSetFailed);
|
||||
KT_EQU(t, sigSetHandler(thread, sigMaxSignals, 0x40005000ull, 0, 0), sigSetFailed);
|
||||
|
||||
KT_TRUE(t, threadDiscard(id));
|
||||
}
|
||||
|
||||
KTEST(sigSetHandlerRejectsSigStopTooLikeRealEinval)
|
||||
{
|
||||
uint32 id = threadCreate("sigStopHandlerBad", noopThreadEntry);
|
||||
KT_NE(t, id, threadInvalidId);
|
||||
Thread* thread = threadAt(id);
|
||||
|
||||
KT_EQU(t, sigSetHandler(thread, sigStop, 0x40005000ull, 0, 0), sigSetFailed);
|
||||
KT_EQU(t, thread->sigHandlers[sigStop], sigHandlerDefault);
|
||||
|
||||
KT_TRUE(t, threadDiscard(id));
|
||||
}
|
||||
|
||||
KTEST(sigSetHandlerStoresMaskStrippedOfSigKillAndSigStop)
|
||||
{
|
||||
uint32 id = threadCreate("sigMaskStoreTarget", noopThreadEntry);
|
||||
KT_NE(t, id, threadInvalidId);
|
||||
Thread* thread = threadAt(id);
|
||||
|
||||
sigSetHandler(thread, sigUsr1, 0x40005000ull,
|
||||
(1ull << sigUsr2) | (1ull << sigKill) | (1ull << sigStop), 0);
|
||||
KT_EQU(t, thread->sigHandlerMasks[sigUsr1], (1ull << sigUsr2));
|
||||
|
||||
/* Installing a handler for a DIFFERENT signum must not disturb sigUsr1's
|
||||
own stored mask -- sigHandlerMasks[] is indexed by the signal being
|
||||
handled, one independent slot per signal number, same as
|
||||
sigHandlers[] itself already is. */
|
||||
sigSetHandler(thread, sigTerm, 0x40006000ull, (1ull << sigHup), 0);
|
||||
KT_EQU(t, thread->sigHandlerMasks[sigUsr1], (1ull << sigUsr2));
|
||||
KT_EQU(t, thread->sigHandlerMasks[sigTerm], (1ull << sigHup));
|
||||
|
||||
KT_TRUE(t, threadDiscard(id));
|
||||
}
|
||||
|
||||
KTEST(sigProcMaskBlockUnblockSetMaskReturnPreviousAndStripSigKill)
|
||||
{
|
||||
uint32 id = threadCreate("sigMaskTarget", noopThreadEntry);
|
||||
KT_NE(t, id, threadInvalidId);
|
||||
Thread* thread = threadAt(id);
|
||||
|
||||
KT_EQU(t, sigProcMask(thread, sigMaskBlock, (1ull << sigUsr1)), 0ull);
|
||||
KT_EQU(t, thread->sigBlocked, (1ull << sigUsr1));
|
||||
|
||||
KT_EQU(t, sigProcMask(thread, sigMaskBlock, (1ull << sigUsr2)),
|
||||
(1ull << sigUsr1));
|
||||
KT_EQU(t, thread->sigBlocked, (1ull << sigUsr1) | (1ull << sigUsr2));
|
||||
|
||||
KT_EQU(t, sigProcMask(thread, sigMaskUnblock, (1ull << sigUsr1)),
|
||||
(1ull << sigUsr1) | (1ull << sigUsr2));
|
||||
KT_EQU(t, thread->sigBlocked, (1ull << sigUsr2));
|
||||
|
||||
KT_EQU(t, sigProcMask(thread, sigMaskSetMask, (1ull << sigTerm)),
|
||||
(1ull << sigUsr2));
|
||||
KT_EQU(t, thread->sigBlocked, (1ull << sigTerm));
|
||||
|
||||
/* sigKill can never be blocked, matching real Unix: its bit is
|
||||
silently stripped from whatever mask is passed in, for BOTH
|
||||
sigMaskBlock and sigMaskSetMask. */
|
||||
KT_EQU(t, sigProcMask(thread, sigMaskSetMask, sigAllBlocked), (1ull << sigTerm));
|
||||
KT_FALSE(t, thread->sigBlocked & (1ull << sigKill));
|
||||
/* sigStop can never be blocked either, same treatment as sigKill. */
|
||||
KT_FALSE(t, thread->sigBlocked & (1ull << sigStop));
|
||||
|
||||
KT_TRUE(t, threadDiscard(id));
|
||||
}
|
||||
|
||||
KTEST(sigConsumePendingReturnsNoneWhenNothingIsPendingOrEverythingIsBlocked)
|
||||
{
|
||||
uint32 id = threadCreate("sigConsumeNone", noopThreadEntry);
|
||||
KT_NE(t, id, threadInvalidId);
|
||||
Thread* thread = threadAt(id);
|
||||
Registers regs = makeUserRegs();
|
||||
int signum = -1;
|
||||
|
||||
KT_EQ(t, sigConsumePending(thread, ®s, &signum), sigOutcomeNone);
|
||||
KT_EQ(t, signum, -1);
|
||||
|
||||
sigRaise(id, sigUsr1);
|
||||
sigProcMask(thread, sigMaskBlock, (1ull << sigUsr1));
|
||||
KT_EQ(t, sigConsumePending(thread, ®s, &signum), sigOutcomeNone);
|
||||
/* Blocked, not delivered: the pending bit must survive untouched for
|
||||
whenever it eventually gets unblocked. */
|
||||
KT_TRUE(t, thread->sigPending & (1ull << sigUsr1));
|
||||
|
||||
KT_TRUE(t, threadDiscard(id));
|
||||
}
|
||||
|
||||
KTEST(sigConsumePendingDismissesIgnoredSignalsAndKeepsScanning)
|
||||
{
|
||||
uint32 id = threadCreate("sigConsumeIgnore", noopThreadEntry);
|
||||
KT_NE(t, id, threadInvalidId);
|
||||
Thread* thread = threadAt(id);
|
||||
Registers regs = makeUserRegs();
|
||||
int signum = -1;
|
||||
|
||||
/* sigChld's real-world default disposition is Ignore -- with no
|
||||
handler installed at all it must be silently dismissed, not
|
||||
terminate the thread. */
|
||||
sigRaise(id, sigChld);
|
||||
KT_EQ(t, sigConsumePending(thread, ®s, &signum), sigOutcomeNone);
|
||||
KT_FALSE(t, thread->sigPending & (1ull << sigChld));
|
||||
|
||||
/* An explicit sigHandlerIgnore dismisses a signal whose default would
|
||||
otherwise be Terminate. */
|
||||
sigSetHandler(thread, sigUsr1, sigHandlerIgnore, 0, 0);
|
||||
sigRaise(id, sigUsr1);
|
||||
KT_EQ(t, sigConsumePending(thread, ®s, &signum), sigOutcomeNone);
|
||||
KT_FALSE(t, thread->sigPending & (1ull << sigUsr1));
|
||||
|
||||
/* An ignored signal must not mask a REAL one raised alongside it in the
|
||||
same scan: sigHup (explicit sigHandlerIgnore here) sits at a LOWER
|
||||
signal number than sigTerm (default Terminate, no handler), so the
|
||||
scan hits the dismissed one first and must keep going instead of
|
||||
stopping there. */
|
||||
sigSetHandler(thread, sigHup, sigHandlerIgnore, 0, 0);
|
||||
sigRaise(id, sigHup);
|
||||
sigRaise(id, sigTerm);
|
||||
KT_EQ(t, sigConsumePending(thread, ®s, &signum), sigOutcomeTerminate);
|
||||
KT_EQ(t, signum, sigTerm);
|
||||
KT_FALSE(t, thread->sigPending & (1ull << sigHup));
|
||||
KT_FALSE(t, thread->sigPending & (1ull << sigTerm));
|
||||
|
||||
KT_TRUE(t, threadDiscard(id));
|
||||
}
|
||||
|
||||
KTEST(sigConsumePendingDefaultDispositionReturnsTerminate)
|
||||
{
|
||||
uint32 id = threadCreate("sigConsumeTerm", noopThreadEntry);
|
||||
KT_NE(t, id, threadInvalidId);
|
||||
Thread* thread = threadAt(id);
|
||||
Registers regs = makeUserRegs();
|
||||
Registers before = regs;
|
||||
int signum = -1;
|
||||
|
||||
sigRaise(id, sigTerm);
|
||||
KT_EQ(t, sigConsumePending(thread, ®s, &signum), sigOutcomeTerminate);
|
||||
KT_EQ(t, signum, sigTerm);
|
||||
KT_FALSE(t, thread->sigPending & (1ull << sigTerm));
|
||||
|
||||
/* Terminate is reported, not carried out, here -- sigConsumePending has
|
||||
no way to hand back a new rsp for a thread it just killed, so it
|
||||
must not touch the trapframe at all; isr.c's deliverPendingSignals
|
||||
is the one that actually calls threadExit. */
|
||||
KT_EQU(t, regs.rip, before.rip);
|
||||
KT_EQU(t, regs.rax, before.rax);
|
||||
KT_EQU(t, thread->sigHandlerDepth, 0u);
|
||||
|
||||
Reference in new issue
Block a user