66 lines
2.2 KiB
C
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;
|
|
}
|