feat: add onUsr1 and printErr
This commit is contained in:
1 parent
9480af603f
commit
0f4437ed80
3 files changed
+203
No files matched your search
@@ -0,0 +1,90 @@
|
||||
#include "ulib.h"
|
||||
|
||||
/*
|
||||
* Spawned directly by kmain.c at boot, alongside pgroupfg.c. Deliberately
|
||||
* NEVER told to keyboardSetForegroundPgid -- every boot-time spawnUser call
|
||||
* becomes its own new process group leader by default (sched.c's
|
||||
* initialPgid), so this process's pgid already differs from pgroupfg's
|
||||
* without any extra call, the same way two independently-launched
|
||||
* background jobs in a real shell would each get their own group. This is
|
||||
* the CONTROL side of the pgroupfg/pgroupbg pair: pgroupfg proves the
|
||||
* injected Ctrl-C reaches the foreground group and kills it; this file
|
||||
* proves that exact same event does NOT reach a DIFFERENT group at all --
|
||||
* if keyboard.c's scoping were ever broken to deliver sigInt/sigTstp to
|
||||
* every live thread (the bug this whole subsystem exists to prevent), this
|
||||
* process would already be Dead by the time kmain.c's injector later tries
|
||||
* to prove it alive, and every needle below would simply never appear.
|
||||
*
|
||||
* Along the way, exercises the actual syscall boundary (sysSetpgid/
|
||||
* sysGetpgid, syscall.c) that sched.c's own KTEST coverage cannot reach on
|
||||
* its own (ktestRunAll runs before schedStart(), with no int 0x80 path at
|
||||
* all -- see schedTest.c's file comment): userGetpgid(0) must already
|
||||
* equal this process's own pid (new-group-leader default), and an
|
||||
* explicit, real setpgid(0, 0) self-affirmation (the same defensive call a
|
||||
* real shell places a background job's own PID with, even when it is
|
||||
* already its own leader) must be a harmless no-op.
|
||||
*/
|
||||
|
||||
static volatile int handlerFired = 0;
|
||||
|
||||
static void onUsr1(int signum)
|
||||
{
|
||||
(void)signum;
|
||||
handlerFired = 1;
|
||||
print("pgroupbg: still-alive-after-ctrlc-ok\n");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
long myPid = userGetpid();
|
||||
print("pgroupbg: start, pid=");
|
||||
printDec(myPid);
|
||||
print("\n");
|
||||
|
||||
long pgid = userGetpgid(0);
|
||||
if (pgid != myPid) {
|
||||
print("pgroupbg: FAIL expected to be its own group leader\n");
|
||||
return 1;
|
||||
}
|
||||
if (userSetpgid(0, 0) != 0) {
|
||||
print("pgroupbg: FAIL self setpgid(0,0) rejected\n");
|
||||
return 1;
|
||||
}
|
||||
if (userGetpgid(0) != myPid) {
|
||||
print("pgroupbg: FAIL pgid changed after self-affirming setpgid\n");
|
||||
return 1;
|
||||
}
|
||||
print("pgroupbg: own-process-group-ok\n");
|
||||
|
||||
if (userSigAction(sigUsr1, onUsr1, 0, 0) == (long)sigSetFailed) {
|
||||
print("pgroupbg: FAIL install handler\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
long victimHandle = userPipeCreate();
|
||||
if (victimHandle < 0) {
|
||||
print("pgroupbg: FAIL create victim pipe\n");
|
||||
return 1;
|
||||
}
|
||||
long victimFd = userPipeAttach(victimHandle, 0);
|
||||
if (victimFd < 0) {
|
||||
print("pgroupbg: FAIL attach victim pipe\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
print("pgroupbg: ready, blocking on go pipe\n");
|
||||
char buffer[4];
|
||||
userRead((int)victimFd, buffer, sizeof(buffer));
|
||||
|
||||
if (!handlerFired) {
|
||||
print("pgroupbg: FAIL read returned without being signaled\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Reached only if the read was genuinely interrupted (errInterrupted,
|
||||
no sigFlagRestart) by onUsr1 above, itself only ever sent by
|
||||
kmain.c's own injector thread well AFTER the Ctrl-C event -- proving
|
||||
this process was never touched by it at all. */
|
||||
print("pgroupbg: resumed-after-signal-ok\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
#include "ulib.h"
|
||||
|
||||
/*
|
||||
* Spawned directly by kmain.c at boot, alongside pgroupbg.c -- the live
|
||||
* ring-3 proof that sched.h's new Thread.pgid and keyboard.c's new real
|
||||
* Ctrl-C actually scope a terminal-generated signal to the FOREGROUND
|
||||
* process group, not to "every process reading a keyboard" or "one single
|
||||
* hardcoded target". kmain.c makes this process's own pgid (its default,
|
||||
* unchanged: every boot-time spawnUser call becomes its own new group
|
||||
* leader, sched.c's initialPgid) the foreground via
|
||||
* keyboardSetForegroundPgid right after spawning it.
|
||||
*
|
||||
* Installs NO handler for sigInt at all -- the real-world default
|
||||
* disposition (signal.c's sigDefaultIsIgnore does not list sigInt) is
|
||||
* Terminate, exactly like a real un-caught Ctrl-C killing a foreground
|
||||
* program with no signal handling of its own. The read below blocks on a
|
||||
* pipe no writer will ever attach to (the same "blocked forever" setup
|
||||
* eintrtarget.c/killvictim.c/alarmdefault.c already use), so the only way
|
||||
* this process ever leaves it is the kernel-injected Ctrl-C's early-wake
|
||||
* (signal.c's sigWouldDeliver/sched.c's threadWakeForSignal, the same
|
||||
* mechanism eintrtarget.c's own sigTerm already proves) actually reaching
|
||||
* a genuinely Blocked thread and terminating it. If keyboard.c's group
|
||||
* scoping were ever broken such that this process were somehow excluded
|
||||
* from its own foreground group, this process would simply never return
|
||||
* from the read below, hanging the whole boot gate to its 25s QEMU timeout
|
||||
* instead of merely failing a check -- the same fault-injection-visible
|
||||
* shape eintrtest.c's own file comment already establishes.
|
||||
*/
|
||||
|
||||
int main(void)
|
||||
{
|
||||
print("pgroupfg: start, pid=");
|
||||
printDec(userGetpid());
|
||||
print("\n");
|
||||
|
||||
long victimHandle = userPipeCreate();
|
||||
if (victimHandle < 0) {
|
||||
print("pgroupfg: FAIL create victim pipe\n");
|
||||
return 1;
|
||||
}
|
||||
long victimFd = userPipeAttach(victimHandle, 0);
|
||||
if (victimFd < 0) {
|
||||
print("pgroupfg: FAIL attach victim pipe\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
print("pgroupfg: ready, blocking on go pipe\n");
|
||||
char buffer[4];
|
||||
userRead((int)victimFd, buffer, sizeof(buffer));
|
||||
|
||||
/* Only reached if userRead somehow returned on its own -- nothing ever
|
||||
writes to the victim pipe, so the foreground Ctrl-C never arriving
|
||||
(or arriving but not actually terminating this process) is the only
|
||||
way to get here. */
|
||||
print("pgroupfg: FAIL read returned without being interrupted\n");
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
#include "ulib.h"
|
||||
|
||||
/*
|
||||
* Middle stage of shell.c's new N-stage pipeline live demo
|
||||
* (`pipesrc | pipecat | pipesink`) -- the first process in this kernel with
|
||||
* BOTH ends of two DIFFERENT real inter-process pipes baked into its fds at
|
||||
* once (fd 0 from jobctlSpawnPiped's stdinHandle, fd 1 from its
|
||||
* stdoutHandle). user/hcat.c already proved a piped stdout alongside a
|
||||
* piped stdin, but that stdin was always a shell-fed here-string
|
||||
* (jobctlSpawnPipedHereString), never a second real process-to-process
|
||||
* pipe the way this one's is -- this program is the actual proof that
|
||||
* shell.c's runPipelineStages can wire a genuine middle pipeline stage
|
||||
* where NEITHER end is the console. From this program's own point of view
|
||||
* there is nothing special about either fd: it is simply "cat" -- read
|
||||
* stdin to real EOF, then write exactly those bytes to stdout -- with no
|
||||
* idea either end is a pipe rather than a real file or console, the same
|
||||
* shape as hcat.c's/pipesink.c's own read loops.
|
||||
*
|
||||
* Diagnostics go to fd 2 (never fd 1), same reason as every other filter in
|
||||
* this pipeline family: fd 1 here is the real payload pipesink.c compares
|
||||
* byte-for-byte, and print()/printDec() (ulib.h) are both hardcoded to fd 1.
|
||||
*/
|
||||
|
||||
static void printErr(const char* text)
|
||||
{
|
||||
userWrite(2, text, stringLength(text));
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
printErr("pipecat: reading piped stdin\n");
|
||||
|
||||
char buffer[64];
|
||||
unsigned long total = 0;
|
||||
for (;;) {
|
||||
long got = userRead(0, buffer + total, sizeof(buffer) - 1 - total);
|
||||
if (got < 0) {
|
||||
printErr("pipecat: FAIL read\n");
|
||||
return 1;
|
||||
}
|
||||
if (got == 0)
|
||||
break;
|
||||
total += (unsigned long)got;
|
||||
if (total >= sizeof(buffer) - 1)
|
||||
break;
|
||||
}
|
||||
|
||||
long written = userWrite(1, buffer, total);
|
||||
if (written != (long)total) {
|
||||
printErr("pipecat: FAIL short/failed write\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printErr("pipecat: forwarded payload\n");
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user