55 lines
1.7 KiB
C
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;
|
|
}
|