84 lines
2.3 KiB
C
84 lines
2.3 KiB
C
// 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;
|
|
}
|