65816-llvm-mos/demos/gnoConcurFork.c
2026-07-07 21:11:28 -05:00

66 lines
2.2 KiB
C

// Definitive preemptive-concurrency test via fork() ping-pong. A forked GNO
// thread (child) and the parent alternate ownership of a shared "turn" word in
// bank 2: the parent advances it on EVEN turns, the child on ODD. Each must
// WAIT for the other to hand over the turn, ROUNDS times. This completes ONLY
// if GNO preemptively time-slices the two threads -- if they ran sequentially,
// whichever went first would spin forever at round 2 waiting for a turn the
// other can't give. No program-load latency and no gsh job control to muddy it
// (unlike the two-separate-programs path): fork is in-process and immediate.
//
// The child stays within the leaf-only fork contract: a register loop + absolute
// bank-2 loads/stores + _exit (no calls, libcalls, fn-pointers, or &global).
//
// 0x025050 ROUNDS*2 (0x0014) final turn value if the ping-pong completed
// 0x025052 5050 parent finished all ROUNDS turns (else DEAD = stuck/no sched)
// 0x025054 CCCC child finished all ROUNDS turns (else DEAD = never scheduled)
#include <stdint.h>
extern int fork(void *subr);
extern int wait(int *status);
extern __attribute__((noreturn)) void _exit(int status);
#define M(a) (*(volatile uint16_t *)(a))
#define TURN 0x025050UL
#define RES_P 0x025052UL
#define RES_C 0x025054UL
#define ROUNDS 10
// Child (leaf): take the ODD turns. Wait until TURN is odd, then bump it even.
static void child(void) {
uint16_t k;
for (k = 0; k < ROUNDS; k++) {
while ((M(TURN) & 1) == 0) {
}
M(TURN) = M(TURN) + 1;
}
M(RES_C) = 0xCCCC;
_exit(0);
}
int main(void) {
uint16_t k;
int pid;
int st;
M(TURN) = 0x0000; // even -> parent goes first
M(RES_P) = 0xDEAD;
M(RES_C) = 0xDEAD;
pid = fork((void *)child);
if (pid <= 0) {
M(RES_P) = 0xF00D; // fork failed outright
} else {
for (k = 0; k < ROUNDS; k++) {
while ((M(TURN) & 1) == 1) {
}
M(TURN) = M(TURN) + 1;
}
M(RES_P) = 0x5050; // parent completed its turns
wait(&st);
}
for (volatile unsigned long j = 0; j < 300000UL; j++) {
}
return 0;
}