feat: extend alarmdefault and argecho
This commit is contained in:
1 parent
4dee5e3009
commit
09239a27e8
5 files changed
+149
No files matched your search
@@ -0,0 +1,53 @@
|
||||
#include "ulib.h"
|
||||
|
||||
/*
|
||||
* Only ever spawned by alarmtest.c. Installs NO sigAlrm handler at all --
|
||||
* the real-Unix default disposition for SIGALRM (signal.c's
|
||||
* sigDefaultIsIgnore explicitly does NOT list sigAlrm, so it falls through
|
||||
* to the same default-Terminate path every other "real" signal in this
|
||||
* kernel already has) is Terminate, not Ignore. userAlarm(1) schedules a
|
||||
* real SIGALRM one second from now against THIS process; the read below
|
||||
* blocks on a pipe no writer will ever attach to (the same "blocked
|
||||
* forever" setup eintrtarget.c/killvictim.c already use), so the only way
|
||||
* this process ever leaves that read is the alarm actually firing and
|
||||
* killing it -- exactly like eintrtarget.c, except the interrupting signal
|
||||
* here comes from schedule()'s own timer-tick expiry scan (sched.c), not
|
||||
* from another process's userSigSend. If threadSetAlarm/schedule's expiry
|
||||
* scan were ever broken, 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 for early-wake.
|
||||
*/
|
||||
|
||||
int main(void)
|
||||
{
|
||||
print("alarmdefault: start, pid=");
|
||||
printDec(userGetpid());
|
||||
print("\n");
|
||||
|
||||
long victimHandle = userPipeCreate();
|
||||
if (victimHandle < 0) {
|
||||
print("alarmdefault: FAIL create victim pipe\n");
|
||||
return 1;
|
||||
}
|
||||
long victimFd = userPipeAttach(victimHandle, 0);
|
||||
if (victimFd < 0) {
|
||||
print("alarmdefault: FAIL attach victim pipe\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (userAlarm(1) != 0) {
|
||||
print("alarmdefault: FAIL unexpected pre-existing alarm\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
print("alarmdefault: blocking on read forever\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 alarm not firing (or firing but
|
||||
not actually terminating this process) is the only way to get here. */
|
||||
print("alarmdefault: FAIL read returned without being signaled\n");
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#include "ulib.h"
|
||||
|
||||
/*
|
||||
* Real ring-3 proof that shell.c's `$NAME`/`$?` expansion (shellExpandArgv,
|
||||
* shellExpandToken) genuinely reaches a SPAWNED program's own argv, not
|
||||
* just a shell builtin's -- every earlier consumer of expansion (export,
|
||||
* env, echo) is a builtin, and shell.c's doEcho never calls shellExpandArgv
|
||||
* at all (only runProgram/runPipelineStages do, for a real spawned
|
||||
* process), so nothing in this kernel's live-demo chain had ever actually
|
||||
* typed a `$` at the real shell before this program existed. Prints each
|
||||
* argv[1..argc) on its own line, prefixed like globcat.c's own
|
||||
* "globcat: " diagnostic style -- a generic argv printer, not tied to any
|
||||
* one variable, so a future demo can reuse it for any other `$NAME`/`$?`
|
||||
* case without needing yet another single-purpose binary.
|
||||
*/
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
for (int i = 1; i < argc; i++) {
|
||||
print("argecho: ");
|
||||
print(argv[i]);
|
||||
print("\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
#include "ulib.h"
|
||||
|
||||
/*
|
||||
* Boot-spawned independently of consolereader2.c (see kmain.c's spawnUser
|
||||
* calls) -- like namedreader.c/namedwriter.c, neither process's pid, argv,
|
||||
* or fd table ever mentions the other. Both simply read fd 0, which every
|
||||
* process gets for free (vfs.c's vfsFdInit) as its own console reader queue
|
||||
* (keyboard.h) rather than a single kernel-wide buffer: proving that two
|
||||
* completely unrelated processes reading "the keyboard" each get their own
|
||||
* independent copy of every keystroke instead of racing each other for it.
|
||||
*
|
||||
* kmain.c's consoleInjectorThread fires exactly one synthetic keystroke a
|
||||
* few hundred milliseconds after boot (there is no automated way to drive a
|
||||
* real PS/2 device under headless QEMU, see its own comment) through the
|
||||
* same keyboardHandleScancode the real IRQ handler calls -- so this process
|
||||
* has to genuinely park in userRead across many timer ticks and be woken
|
||||
* later, not just win a race against a byte that was already queued.
|
||||
*/
|
||||
|
||||
int main(void)
|
||||
{
|
||||
print("consolereader1: start, pid=");
|
||||
printDec(userGetpid());
|
||||
print(", blocking on fd 0\n");
|
||||
|
||||
char c = 0;
|
||||
long got = userRead(0, &c, 1);
|
||||
if (got != 1) {
|
||||
print("consolereader1: FAIL read\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
print("consolereader1: got byte '");
|
||||
userWrite(1, &c, 1);
|
||||
print("' -> console-fanout-1-ok\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
#include "ulib.h"
|
||||
|
||||
/* See consolereader1.c's comment -- an entirely independent process reading
|
||||
the same fd 0, spawned separately by kmain.c, sharing nothing with
|
||||
consolereader1 but the fact that both happen to be alive when
|
||||
consoleInjectorThread's single synthetic keystroke fires. If fan-out
|
||||
ever regressed back to one shared buffer, whichever of the two processes
|
||||
the scheduler happened to run first would steal the only queued byte and
|
||||
the other would hang forever -- the boot gate's timeout would catch that
|
||||
as a missing needle rather than a hang, since only this process is
|
||||
missing, not the whole machine. */
|
||||
|
||||
int main(void)
|
||||
{
|
||||
print("consolereader2: start, pid=");
|
||||
printDec(userGetpid());
|
||||
print(", blocking on fd 0\n");
|
||||
|
||||
char c = 0;
|
||||
long got = userRead(0, &c, 1);
|
||||
if (got != 1) {
|
||||
print("consolereader2: FAIL read\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
print("consolereader2: got byte '");
|
||||
userWrite(1, &c, 1);
|
||||
print("' -> console-fanout-2-ok\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -2,6 +2,11 @@
|
||||
.global _start
|
||||
_start:
|
||||
xorq %rbp, %rbp
|
||||
/* Real x86_64 SysV process entry: rsp points at argc, with argv[0..]
|
||||
and a NULL terminator right above it (elfBuildInitialStack,
|
||||
elf.c/syscall.c doExec/doSpawn, kmain.c spawnUser). */
|
||||
movq (%rsp), %rdi
|
||||
leaq 8(%rsp), %rsi
|
||||
call main
|
||||
movq %rax, %rdi
|
||||
movq $0, %rax
|
||||
|
||||
Reference in new issue
Block a user