Files

168 lines
6.8 KiB
C

#include "ulib.h"
/*
* Boot-time, single-process live demo of sigFlagNoDefer (signalnum.h /
* signal.c's sigConsumePending): unlike every other signal demo in this
* kernel (nesttest/masktest/jobtest/...), this needs no second process --
* SA_NODEFER is entirely about whether a signal can interrupt ITS OWN
* still-active handler, a property one process can raise against itself
* and observe directly, with no inter-process rendezvous required at all.
*
* Two contrasting handlers, proven in the same run:
*
* onUsr1 is registered WITH sigFlagNoDefer. Its first invocation
* self-raises sigUsr1 again (userSigSend(selfPid, sigUsr1)) while still
* active. Since sigFlagNoDefer means sigUsr1's own bit was never added
* to sigBlocked, that re-raise is genuinely deliverable the instant the
* self-raise syscall itself returns to ring 3 (isr.c's
* deliverPendingSignals, unconditional on every trap return) -- entering
* a SECOND, NESTED instance of onUsr1 before the first one's own
* userSigSend call ever returns to it. The nested instance sees
* usr1EnterCount already 2 and does not re-raise again (bounded
* recursion), returns via the trampoline's automatic sysSigReturn,
* letting the outer instance resume exactly where its self-raise call
* left off and observe the count already at 2 -- proof the nesting
* already happened, not a race it merely hopes for.
*
* onUsr2 is registered WITHOUT the flag (plain default, like every other
* handler in this kernel before this session). Its first invocation
* self-raises sigUsr2 the same way, but sigUsr2's own bit IS in
* sigBlocked for as long as onUsr2 is active, so that re-raise's own
* syscall returns without anything nesting -- onUsr2 finishes its first
* invocation having observed no nested re-entry at all (the negative
* half of the proof), and only once it actually returns (sysSigReturn
* restoring sigBlocked without sigUsr2's self-block, isrDispatch
* immediately re-checking pending signals on that very trap return,
* exactly like masktarget.c's own deferred-delivery proof) does the
* deferred second raise finally arrive, as its own fresh TOP-LEVEL
* invocation, never nested.
*
* No sleep/timing guess anywhere: every self-raise's pending-bit write
* happens synchronously inside the syscall against this exact same
* thread, and delivery/deferral is entirely decided by sigBlocked at the
* next trap return, which happens deterministically at each userSigSend's
* or handler-return's own int 0x80 -- there is no window for either
* outcome to be a coincidence of scheduling.
*/
static long selfPid = -1;
static volatile int usr1EnterCount = 0;
static volatile int usr1NestedConfirmed = 0;
static void onUsr1(int signum)
{
(void)signum;
usr1EnterCount++;
if (usr1EnterCount == 1) {
print("nodefertest: onUsr1 first entry, self-raising sigUsr1 (NODEFER)\n");
if (userSigSend(selfPid, sigUsr1) != 0) {
print("nodefertest: FAIL self-raise sigUsr1\n");
return;
}
/* If sigFlagNoDefer genuinely lifted the self-block, the nested
instance of THIS SAME function already ran to completion, in
full, during the userSigSend call above (its own return-to-ring3
delivered it before ever coming back here) -- so usr1EnterCount
must already read 2 by the time control resumes at this exact
line, not merely "eventually". */
if (usr1EnterCount >= 2) {
usr1NestedConfirmed = 1;
print("nodefertest: onUsr1 observed its own nested re-entry (nodefer-self-nest-ok)\n");
} else {
print("nodefertest: FAIL onUsr1 did not nest into itself\n");
}
} else {
print("nodefertest: onUsr1 nested entry (depth 2)\n");
}
}
static volatile int usr2EnterCount = 0;
static volatile int usr2WronglyNested = 0;
static void onUsr2(int signum)
{
(void)signum;
usr2EnterCount++;
if (usr2EnterCount == 1) {
print("nodefertest: onUsr2 first entry, self-raising sigUsr2 (default defer)\n");
if (userSigSend(selfPid, sigUsr2) != 0) {
print("nodefertest: FAIL self-raise sigUsr2\n");
return;
}
/* Unlike onUsr1 above: sigUsr2's own bit IS self-blocked here (no
sigFlagNoDefer), so the re-raise above must NOT have nested --
usr2EnterCount must still read exactly 1 at this exact line. */
if (usr2EnterCount != 1) {
usr2WronglyNested = 1;
print("nodefertest: FAIL onUsr2 nested into itself without sigFlagNoDefer\n");
} else {
print("nodefertest: onUsr2 confirmed no self-nest while deferred (still-deferred-ok)\n");
}
} else {
print("nodefertest: onUsr2 second, TOP-LEVEL entry after first returned\n");
}
}
int main(void)
{
print("nodefertest: start, pid=");
printDec(userGetpid());
print("\n");
selfPid = userGetpid();
if (userSigAction(sigUsr1, onUsr1, 0, sigFlagNoDefer) == (long)sigSetFailed ||
userSigAction(sigUsr2, onUsr2, 0, 0) == (long)sigSetFailed) {
print("nodefertest: FAIL install handlers\n");
return 1;
}
/* This syscall's own return-to-ring3 is what delivers onUsr1's FIRST
invocation -- the nested second one (see onUsr1's own comment)
happens entirely inside that delivery, synchronously, before this
call ever returns to main() below. */
if (userSigSend(selfPid, sigUsr1) != 0) {
print("nodefertest: FAIL send sigUsr1 to self\n");
return 1;
}
if (!usr1NestedConfirmed) {
print("nodefertest: FAIL usr1 nodefer self-nest never confirmed\n");
return 1;
}
if (usr1EnterCount != 2) {
print("nodefertest: FAIL expected exactly 2 usr1 entries, got ");
printDec(usr1EnterCount);
print("\n");
return 1;
}
print("nodefertest: nodefer-self-nest-verified-ok\n");
/* Same shape for onUsr2: this call's return delivers its first
invocation; the DEFERRED second one (no nesting) is delivered on
that first invocation's own sysSigReturn, still inside this single
userSigSend's worth of ring-3 return handling, before control ever
reaches back here. */
if (userSigSend(selfPid, sigUsr2) != 0) {
print("nodefertest: FAIL send sigUsr2 to self\n");
return 1;
}
if (usr2WronglyNested) {
print("nodefertest: FAIL usr2 self-nested despite no sigFlagNoDefer\n");
return 1;
}
if (usr2EnterCount != 2) {
print("nodefertest: FAIL expected exactly 2 usr2 entries (deferred, not nested), got ");
printDec(usr2EnterCount);
print("\n");
return 1;
}
print("nodefertest: default-defer-no-self-nest-verified-ok\n");
print("nodefertest: sa-nodefer-contrast-ok\n");
return 0;
}