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

55 lines
1.7 KiB
C

// Concurrency test, program A of a pair (run "gnoconcura & gnoconcurb" under
// gsh). Proves two SEPARATE programs run CONCURRENTLY under GNO's preemptive
// scheduler via a shared-memory rendezvous that can ONLY complete if the two
// interleave: A announces itself (flagA), then spins waiting for B's flag. If A
// ran to completion before B ever started, it would time out (0xDEAD). Both
// reaching their rendezvous marker (A=0xAAAA, B=0xBBBB) means the scheduler
// actually time-sliced them. Each also does real work (sumTo) to prove it is
// not a trivial spin. Bank-2 markers are absolute physical RAM, shared across
// processes -- that is what makes the cross-process rendezvous observable.
//
// 0x025040 0001 flagA: A is alive
// 0x025044 AAAA A saw B's flag (rendezvous) AND sumTo(100)==5050; else DEAD
#include <stdint.h>
#define M(a) (*(volatile uint16_t *)(a))
#define FLAG_A 0x025040UL
#define FLAG_B 0x025042UL
#define RES_A 0x025044UL
#define LIMIT 100000000UL
static uint16_t sumTo(uint16_t n) {
uint16_t acc;
uint16_t i;
acc = 0;
for (i = 1; i <= n; i++) {
acc = acc + i;
}
return acc;
}
int main(void) {
unsigned long spin;
uint16_t saw;
M(RES_A) = 0xDEAD;
M(FLAG_A) = 0x0001; // announce A
saw = 0;
for (spin = 0; spin < LIMIT; spin++) {
if (M(FLAG_B) == 0x0001) {
saw = 1;
break;
}
}
if (saw == 1 && sumTo(100) == 5050) {
M(RES_A) = 0xAAAA; // rendezvous + real work OK
}
M(0x025048UL) = 0xE0AA; // A reached end (distinguishes timeout from crash)
for (volatile unsigned long j = 0; j < 300000UL; j++) {
}
return 0;
}