function* atomic_read(idx) {
yield null;
return D[idx];
}
function* atomic_swap(idx, val) {
yield null;
let got = D[idx];
D[idx] = val;
return got;
}
function* atomic_cas(idx, from, to) {
yield null;
let old = D[idx];
if (old === from) {
D[idx] = to;
}
return old;
}
const RED = 0x10; const GOT = 0xFF;
const is_red = (x) => x >= RED && x < RED*2;
const is_var = (x) => x >= 0 && x < RED;
function* atomic_rewrite(tid, a_dir, b_dir) {
var a_ptr = yield* atomic_swap(a_dir, GOT);
var b_ptr = yield* atomic_swap(b_dir, GOT);
yield* atomic_subst(tid, a_ptr, a_dir, b_ptr);
yield* atomic_subst(tid, b_ptr, b_dir, a_ptr);
}
function* atomic_subst(tid, a_ptr, a_dir, b_ptr) {
var a_got = yield* atomic_cas(a_ptr, a_dir, b_ptr);
yield* atomic_swap(a_dir, a_got == a_dir ? -1 : b_ptr+RED);
yield* atomic_link(tid, a_ptr, b_ptr);
}
function* atomic_link(tid, dir, val) {
var ptr = yield* atomic_read(dir);
if (is_var(ptr)) {
while (1) {
var trg = yield* atomic_read(ptr);
if (is_red(trg)) {
var got = yield* atomic_cas(dir, ptr, trg-RED);
if (got == ptr) {
yield* atomic_swap(ptr, -1);
ptr = trg - RED;
}
} else if (trg == GOT) {
continue;
} else {
break;
}
}
}
}
function progress(ticks) {
for (var i = 0; i < ticks; ++i) {
var tid = Math.floor(Math.random() * 3);
if (T[tid]) {
let result = T[tid].next();
if (result.done) {
T[tid] = null;
}
if (!T[0] && !T[1] && !T[2]) {
break;
}
}
}
}
function show(x) {
if (typeof x == "number") {
return x == -1 ? " " : x == 0xFF ? "::" : ("00"+x.toString(16)).slice(-2);
} else {
return x.map(show).join("|");
}
}
var I = [0,1,2,3,4,5,6,7];
var D = [1,0,3,2,5,4,7,6];
var T = [atomic_rewrite(0,1,2), atomic_rewrite(1,3,4), atomic_rewrite(2,5,6)];
progress(256);
console.log(show(I));
console.log(show(D));