28b0129b03
The issue is that Worker.prototype.terminate was deleting the C++ Worker object, and then Worker.prototype.getMessage was trying to read messages from the queue. The simplest solution is to keep workers in a zombie state when they have been terminated. They won't be reaped until Shell::CleanupWorkers is called. I've also fixed some threading issues with Workers: * Workers can be created by another Worker, so the Shell::workers_ variable must be protected by a mutex. * An individual Worker can typically only be accessed by the isolate that created it, but the main thread can always terminate it, so the Worker::state_ must be accessed in a thread-safe way. BUG=chromium:504136 R=jochen@chromium.org LOG=n Review URL: https://codereview.chromium.org/1208733002 Cr-Commit-Position: refs/heads/master@{#29306}
140 lines
4.5 KiB
JavaScript
140 lines
4.5 KiB
JavaScript
// Copyright 2015 the V8 project authors. All rights reserved.
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are
|
|
// met:
|
|
//
|
|
// * Redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
// * Redistributions in binary form must reproduce the above
|
|
// copyright notice, this list of conditions and the following
|
|
// disclaimer in the documentation and/or other materials provided
|
|
// with the distribution.
|
|
// * Neither the name of Google Inc. nor the names of its
|
|
// contributors may be used to endorse or promote products derived
|
|
// from this software without specific prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
// Test the Worker API of d8. This test only makes sense with d8. A Worker
|
|
// spawns a new OS thread and isolate, and runs it concurrently with the
|
|
// current running thread.
|
|
|
|
function f() {
|
|
postMessage("Starting worker");
|
|
// Set a global variable; should not be visible outside of the worker's
|
|
// context.
|
|
foo = 100;
|
|
|
|
var c = 0;
|
|
onmessage = function(m) {
|
|
switch (c++) {
|
|
case 0:
|
|
if (m !== undefined) throw new Error("undefined");
|
|
break;
|
|
case 1:
|
|
if (m !== null) throw new Error("null");
|
|
break;
|
|
case 2:
|
|
if (m !== true) throw new Error("true");
|
|
break;
|
|
case 3:
|
|
if (m !== false) throw new Error("false");
|
|
break;
|
|
case 4:
|
|
if (m !== 100) throw new Error("Number");
|
|
break;
|
|
case 5:
|
|
if (m !== "hi") throw new Error("String");
|
|
break;
|
|
case 6:
|
|
if (JSON.stringify(m) !== '[4,true,"bye"]') throw new Error("Array");
|
|
break;
|
|
case 7:
|
|
if (JSON.stringify(m) !== '{"a":1,"b":2.5,"c":"three"}')
|
|
throw new Error("Object");
|
|
break;
|
|
case 8:
|
|
var ab = m;
|
|
var t = new Uint32Array(ab);
|
|
if (ab.byteLength !== 16)
|
|
throw new Error("ArrayBuffer clone byteLength");
|
|
for (var i = 0; i < 4; ++i)
|
|
if (t[i] !== i)
|
|
throw new Error("ArrayBuffer clone value " + i);
|
|
break;
|
|
case 9:
|
|
var ab = m;
|
|
var t = new Uint32Array(ab);
|
|
if (ab.byteLength !== 32)
|
|
throw new Error("ArrayBuffer transfer byteLength");
|
|
for (var i = 0; i < 8; ++i)
|
|
if (t[i] !== i)
|
|
throw new Error("ArrayBuffer transfer value " + i);
|
|
break;
|
|
}
|
|
|
|
if (c == 10) {
|
|
postMessage("DONE");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (this.Worker) {
|
|
function createArrayBuffer(byteLength) {
|
|
var ab = new ArrayBuffer(byteLength);
|
|
var t = new Uint32Array(ab);
|
|
for (var i = 0; i < byteLength / 4; ++i)
|
|
t[i] = i;
|
|
return ab;
|
|
}
|
|
|
|
var w = new Worker(f);
|
|
|
|
assertEquals("Starting worker", w.getMessage());
|
|
|
|
w.postMessage(undefined);
|
|
w.postMessage(null);
|
|
w.postMessage(true);
|
|
w.postMessage(false);
|
|
w.postMessage(100);
|
|
w.postMessage("hi");
|
|
w.postMessage([4, true, "bye"]);
|
|
w.postMessage({a: 1, b: 2.5, c: "three"});
|
|
|
|
// Clone ArrayBuffer
|
|
var ab1 = createArrayBuffer(16);
|
|
w.postMessage(ab1);
|
|
assertEquals(16, ab1.byteLength); // ArrayBuffer should not be neutered.
|
|
|
|
// Transfer ArrayBuffer
|
|
var ab2 = createArrayBuffer(32);
|
|
w.postMessage(ab2, [ab2]);
|
|
assertEquals(0, ab2.byteLength); // ArrayBuffer should be neutered.
|
|
|
|
assertEquals("undefined", typeof foo);
|
|
|
|
// Read a message from the worker.
|
|
assertEquals("DONE", w.getMessage());
|
|
|
|
w.terminate();
|
|
|
|
|
|
// Make sure that the main thread doesn't block forever in getMessage() if
|
|
// the worker dies without posting a message.
|
|
function f2() {}
|
|
var w2 = new Worker(f2);
|
|
var msg = w2.getMessage();
|
|
assertEquals(undefined, msg);
|
|
}
|