// 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 #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; }