// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
let sab = new SharedArrayBuffer(10 * 4);
let memory = new Int32Array(sab);
let workers = [];
let runningWorkers = 0;

function startWorker(script) {
  let worker = new Worker(script, {type: 'string'});
  worker.done = false;
  worker.idx = workers.length;
  workers.push(worker);
  worker.postMessage(memory);
  ++runningWorkers;
};

let shared = `
  function wait(memory, index, waitCondition, wakeCondition) {
    while (memory[index] == waitCondition) {
      var result = Atomics.wait(memory, index, waitCondition);
      switch (result) {
        case 'not-equal':
        case 'ok':
          break;
        default:
          postMessage('Error: bad result from wait: ' + result);
          break;
      }
      var value = memory[index];
      if (value != wakeCondition) {
        postMessage(
            'Error: wait returned not-equal but the memory has a bad value: ' +
            value);
      }
    }
    var value = memory[index];
    if (value != wakeCondition) {
      postMessage(
          'Error: done waiting but the memory has a bad value: ' + value);
    }
  }

  function wake(memory, index) {
    var result = Atomics.wake(memory, index, 1);
    if (result != 0 && result != 1) {
      postMessage('Error: bad result from wake: ' + result);
    }
  }
`;

let worker1 = startWorker(shared + `
  onmessage = function(msg) {
    let memory = msg;
    const didStartIdx = 0;
    const shouldGoIdx = 1;
    const didEndIdx = 2;

    postMessage("started");
    postMessage("memory: " + memory);
    wait(memory, didStartIdx, 0, 1);
    memory[shouldGoIdx] = 1;
    wake(memory, shouldGoIdx);
    wait(memory, didEndIdx, 0, 1);
    postMessage("memory: " + memory);
    postMessage("done");
  };
`);

let worker2 = startWorker(shared + `
  onmessage = function(msg) {
    let memory = msg;
    const didStartIdx = 0;
    const shouldGoIdx = 1;
    const didEndIdx = 2;

    postMessage("started");
    postMessage("memory: " + memory);
    Atomics.store(memory, didStartIdx, 1);
    wake(memory, didStartIdx);
    wait(memory, shouldGoIdx, 0, 1);
    Atomics.store(memory, didEndIdx, 1);
    wake(memory, didEndIdx, 1);
    postMessage("memory: " + memory);
    postMessage("done");
  };
`);

let running = true;
while (running) {
  for (let worker of workers) {
    if (worker.done) continue;

    let msg = worker.getMessage();
    if (msg) {
      switch (msg) {
        case "done":
          if (worker.done === false) {
            print("worker #" + worker.idx + " done.");
            worker.done = true;
            if (--runningWorkers === 0) {
              running = false;
            }
          }
          break;

        default:
          print("msg from worker #" + worker.idx + ": " + msg);
          break;
      }
    }
  }
}
