56 lines
2.5 KiB
C
56 lines
2.5 KiB
C
// Process-lifecycle core regression for GNO: fork a leaf child that _exit(42)s,
|
|
// have the parent wait() and assert the real exit status propagates. Covers two
|
|
// fixed bugs at once:
|
|
// 1. Kernel dispatch vector: gnoKernel.s called $E10000 (the standard Tool
|
|
// Locator, toolset $03 = Misc Tools) instead of GNO's udispatch $E10008, so
|
|
// EVERY K* primitive hung. Latent until this probe -- fork is the first K*
|
|
// call ever exercised under GNO.
|
|
// 2. Exit status: _exit routed QUIT through __gnoGsosCall, which loaded
|
|
// A = callNum (0x2029) right before the trap, so GNO's StackGSOS recorded
|
|
// 0x2029 as the exit code and wait() decoded WEXITSTATUS = 0x29 (41).
|
|
// __gnoQuit now leaves A = status, so wait() sees 42 (0x2A).
|
|
//
|
|
// GNO fork is a thread-spawn: the child begins at child() on a fresh stack/DP, so
|
|
// child() is a LEAF using only absolute-long stores + _exit (no DP scratch).
|
|
// Bank-2 absolute markers (DBR-independent), per the gnoHeapProbe convention.
|
|
// 0x025000 C0DE reached end (no hang in fork/wait)
|
|
// 0x025010 C41D child was scheduled + ran
|
|
// 0x025014 002A WEXITSTATUS == 42 (the status propagated)
|
|
// 0x025016 0001 wait() reaped the same pid fork() returned
|
|
// 0x025018 600D exit status is NOT the old 41/0x29 miscompile
|
|
#include <stdint.h>
|
|
#include <sys/wait.h>
|
|
|
|
extern int fork(void *subr); // GNO thread-spawn: subr = (void *)&childFn
|
|
extern int wait(int *status);
|
|
extern __attribute__((noreturn)) void _exit(int status);
|
|
|
|
#define M(a) (*(volatile uint16_t *)(a))
|
|
|
|
|
|
static void child(void) {
|
|
M(0x025010UL) = 0xC41D; // child was scheduled + entered child()
|
|
_exit(42); // exit code 42 -> status word 0x2A00
|
|
}
|
|
|
|
|
|
int main(void) {
|
|
M(0x025000UL) = 0x0000;
|
|
int pid = fork((void *)child);
|
|
if (pid <= 0) {
|
|
M(0x025016UL) = 0xDEAD; // fork failed / returned no child
|
|
M(0x025000UL) = 0xC0DE;
|
|
for (volatile unsigned long j = 0; j < 300000UL; j++) {
|
|
}
|
|
return 0;
|
|
}
|
|
int st = 0;
|
|
int w = wait(&st); // blocks until the child dies (race-free)
|
|
M(0x025014UL) = WIFEXITED(st) ? (uint16_t)WEXITSTATUS(st) : 0xEEEE; // == 0x002A
|
|
M(0x025016UL) = (w == pid) ? 0x0001 : 0xDEAD; // pid round-trip
|
|
M(0x025018UL) = (WEXITSTATUS(st) == 41) ? 0xDEAD : 0x600D; // guard old bug
|
|
M(0x025000UL) = 0xC0DE; // reached end
|
|
for (volatile unsigned long j = 0; j < 300000UL; j++) {
|
|
}
|
|
return 0;
|
|
}
|