181c03e9cc
TSAN finds data races in generated JavaScript code that use access the SharedArrayBuffer backing store racily. These are races, but they are OK in the sense that the JavaScript memory model allows for the potential bad behavior they could introduce (e.g. potentially tearing reads). Relaxed atomics could be used here instead, but that could introduce performance regressions. This change adds TSAN annotations to the TypedArray reads/writes to prevent TSAN from warning about them. Bug: chromium:722871 Change-Id: I0776475f02a352b678ade7d32ed6bd4a6be98c36 Reviewed-on: https://chromium-review.googlesource.com/656509 Commit-Queue: Ben Smith <binji@chromium.org> Reviewed-by: Clemens Hammacher <clemensh@chromium.org> Cr-Commit-Position: refs/heads/master@{#47929}
114 lines
2.8 KiB
JavaScript
114 lines
2.8 KiB
JavaScript
// 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);
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|