// The ultimate concurrency proof: parent and forked child BOTH dispatch function
// pointers WHILE preemptively interleaved.  They ping-pong a shared turn word
// (proving they time-slice), and on every one of its turns each thread makes an
// indirect call through its own volatile function pointer -- the parent inc's an
// accumulator, the child dec's one.  This only produces the right accumulators
// (parent 0->ROUNDS, child 1000->1000-ROUNDS) if the reentrant __jsl_indir reads
// each thread's OWN per-thread DP target: with the old shared self-modified
// operand the two threads' indirect dispatch aliased and wild-jumped.
//
//   0x025070  ROUNDS*2 (0x0014)  final turn value (ping-pong completed)
//   0x025072  5050  parent did ROUNDS fnptr inc's concurrently (acc==ROUNDS)
//   0x025074  CCCC  child  did ROUNDS fnptr dec's concurrently (acc==1000-ROUNDS)
#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   0x025070UL
#define RES_P  0x025072UL
#define RES_C  0x025074UL
#define ROUNDS 10


static uint16_t incf(uint16_t x) {
    return x + 1;
}


static uint16_t decf(uint16_t x) {
    return x - 1;
}


static uint16_t (*volatile fpP)(uint16_t) = incf;
static uint16_t (*volatile fpC)(uint16_t) = decf;


static void child(void) {
    uint16_t k;
    uint16_t acc;
    acc = 1000;
    for (k = 0; k < ROUNDS; k++) {
        while ((M(TURN) & 1) == 0) {
        }
        acc = fpC(acc);                  // indirect call, concurrent with parent
        M(TURN) = M(TURN) + 1;
    }
    if (acc == (uint16_t)(1000 - ROUNDS)) {
        M(RES_C) = 0xCCCC;
    }
    _exit(0);
}


int main(void) {
    uint16_t k;
    uint16_t acc;
    int      pid;
    int      st;

    M(TURN)  = 0x0000;
    M(RES_P) = 0xDEAD;
    M(RES_C) = 0xDEAD;
    acc = 0;

    pid = fork((void *)child);
    if (pid > 0) {
        for (k = 0; k < ROUNDS; k++) {
            while ((M(TURN) & 1) == 1) {
            }
            acc = fpP(acc);              // indirect call, concurrent with child
            M(TURN) = M(TURN) + 1;
        }
        if (acc == ROUNDS) {
            M(RES_P) = 0x5050;
        }
        wait(&st);
    }
    for (volatile unsigned long j = 0; j < 300000UL; j++) {
    }
    return 0;
}
