- Pass additional state in the IsolateSpawnState to set
  error and exit handlers, as well as fatal errors on isolate start.

BUG=
R=floitsch@google.com

Review URL: https://codereview.chromium.org//1244733002 .
This commit is contained in:
Ivan Posva 2015-07-20 16:46:54 +02:00
parent 4d933a2d0d
commit fe03640e85
15 changed files with 409 additions and 16 deletions

View file

@ -217,11 +217,15 @@ static void Spawn(Isolate* parent_isolate, IsolateSpawnState* state) {
}
DEFINE_NATIVE_ENTRY(Isolate_spawnFunction, 4) {
DEFINE_NATIVE_ENTRY(Isolate_spawnFunction, 7) {
GET_NON_NULL_NATIVE_ARGUMENT(SendPort, port, arguments->NativeArgAt(0));
GET_NON_NULL_NATIVE_ARGUMENT(Instance, closure, arguments->NativeArgAt(1));
GET_NON_NULL_NATIVE_ARGUMENT(Instance, message, arguments->NativeArgAt(2));
GET_NON_NULL_NATIVE_ARGUMENT(Bool, paused, arguments->NativeArgAt(3));
GET_NATIVE_ARGUMENT(Bool, fatalErrors, arguments->NativeArgAt(4));
GET_NATIVE_ARGUMENT(SendPort, onExit, arguments->NativeArgAt(5));
GET_NATIVE_ARGUMENT(SendPort, onError, arguments->NativeArgAt(6));
if (closure.IsClosure()) {
Function& func = Function::Handle();
func = Closure::function(closure);
@ -233,10 +237,18 @@ DEFINE_NATIVE_ENTRY(Isolate_spawnFunction, 4) {
#endif
// Get the parent function so that we get the right function name.
func = func.parent_function();
bool fatal_errors = fatalErrors.IsNull() ? true : fatalErrors.value();
Dart_Port on_exit_port = onExit.IsNull() ? ILLEGAL_PORT : onExit.Id();
Dart_Port on_error_port = onError.IsNull() ? ILLEGAL_PORT : onError.Id();
Spawn(isolate, new IsolateSpawnState(port.Id(),
func,
message,
paused.value()));
paused.value(),
fatal_errors,
on_exit_port,
on_error_port));
return Object::null();
}
}
@ -247,7 +259,7 @@ DEFINE_NATIVE_ENTRY(Isolate_spawnFunction, 4) {
}
DEFINE_NATIVE_ENTRY(Isolate_spawnUri, 7) {
DEFINE_NATIVE_ENTRY(Isolate_spawnUri, 10) {
GET_NON_NULL_NATIVE_ARGUMENT(SendPort, port, arguments->NativeArgAt(0));
GET_NON_NULL_NATIVE_ARGUMENT(String, uri, arguments->NativeArgAt(1));
GET_NON_NULL_NATIVE_ARGUMENT(Instance, args, arguments->NativeArgAt(2));
@ -255,6 +267,9 @@ DEFINE_NATIVE_ENTRY(Isolate_spawnUri, 7) {
GET_NON_NULL_NATIVE_ARGUMENT(Bool, paused, arguments->NativeArgAt(4));
GET_NATIVE_ARGUMENT(Bool, checked, arguments->NativeArgAt(5));
GET_NATIVE_ARGUMENT(String, package_root, arguments->NativeArgAt(6));
GET_NATIVE_ARGUMENT(Bool, fatalErrors, arguments->NativeArgAt(7));
GET_NATIVE_ARGUMENT(SendPort, onExit, arguments->NativeArgAt(8));
GET_NATIVE_ARGUMENT(SendPort, onError, arguments->NativeArgAt(9));
// Canonicalize the uri with respect to the current isolate.
char* error = NULL;
@ -275,12 +290,19 @@ DEFINE_NATIVE_ENTRY(Isolate_spawnUri, 7) {
utf8_package_root[len] = '\0';
}
bool fatal_errors = fatalErrors.IsNull() ? true : fatalErrors.value();
Dart_Port on_exit_port = onExit.IsNull() ? ILLEGAL_PORT : onExit.Id();
Dart_Port on_error_port = onError.IsNull() ? ILLEGAL_PORT : onError.Id();
IsolateSpawnState* state = new IsolateSpawnState(port.Id(),
canonical_uri,
utf8_package_root,
args,
message,
paused.value());
paused.value(),
fatal_errors,
on_exit_port,
on_error_port);
// If we were passed a value then override the default flags state for
// checked mode.
if (!checked.IsNull()) {

View file

@ -282,7 +282,8 @@ patch class Isolate {
try {
// The VM will invoke [_startIsolate] with entryPoint as argument.
readyPort = new RawReceivePort();
_spawnFunction(readyPort.sendPort, entryPoint, message, paused);
_spawnFunction(readyPort.sendPort, entryPoint, message,
paused, errorsAreFatal, onExit, onError);
Completer completer = new Completer<Isolate>.sync();
readyPort.handler = (readyMessage) {
readyPort.close();
@ -314,7 +315,8 @@ patch class Isolate {
var packageRootString =
(packageRoot == null) ? null : packageRoot.toString();
_spawnUri(readyPort.sendPort, uri.toString(), args, message,
paused, checked, packageRootString);
paused, checked, packageRootString,
errorsAreFatal, onExit, onError);
Completer completer = new Completer<Isolate>.sync();
readyPort.handler = (readyMessage) {
readyPort.close();
@ -351,12 +353,14 @@ patch class Isolate {
static void _spawnFunction(SendPort readyPort, Function topLevelFunction,
var message, bool paused)
var message, bool paused, bool errorsAreFatal,
SendPort onExit, SendPort onError)
native "Isolate_spawnFunction";
static void _spawnUri(SendPort readyPort, String uri,
List<String> args, var message,
bool paused, bool checked, String packageRoot)
bool paused, bool checked, String packageRoot,
bool errorsAreFatal, SendPort onExit, SendPort onError)
native "Isolate_spawnUri";
static void _sendOOB(port, msg) native "Isolate_sendOOB";

View file

@ -298,8 +298,8 @@ namespace dart {
V(Int32x4_setFlagZ, 2) \
V(Int32x4_setFlagW, 2) \
V(Int32x4_select, 3) \
V(Isolate_spawnFunction, 4) \
V(Isolate_spawnUri, 7) \
V(Isolate_spawnFunction, 7) \
V(Isolate_spawnUri, 10) \
V(Isolate_getPortAndCapabilitiesOfCurrentIsolate, 0) \
V(Isolate_sendOOB, 2) \
V(Mirrors_evalInLibraryWithPrivateKey, 2) \

View file

@ -1232,6 +1232,24 @@ static bool RunIsolate(uword parameter) {
StartIsolateScope start_scope(isolate);
StackZone zone(isolate);
HandleScope handle_scope(isolate);
// If particular values were requested for this newly spawned isolate, then
// they are set here before the isolate starts executing user code.
isolate->SetErrorsFatal(state->errors_are_fatal());
if (state->on_exit_port() != ILLEGAL_PORT) {
const SendPort& listener =
SendPort::Handle(SendPort::New(state->on_exit_port()));
isolate->AddExitListener(listener, Instance::null_instance());
}
if (state->on_error_port() != ILLEGAL_PORT) {
const SendPort& listener =
SendPort::Handle(SendPort::New(state->on_error_port()));
isolate->AddErrorListener(listener);
}
// Switch back to spawning isolate.
if (!ClassFinalizer::ProcessPendingClasses()) {
// Error is in sticky error already.
return false;
@ -1952,9 +1970,14 @@ static RawInstance* DeserializeObject(Isolate* isolate,
IsolateSpawnState::IsolateSpawnState(Dart_Port parent_port,
const Function& func,
const Instance& message,
bool paused)
bool paused,
bool errors_are_fatal,
Dart_Port on_exit_port,
Dart_Port on_error_port)
: isolate_(NULL),
parent_port_(parent_port),
on_exit_port_(on_exit_port),
on_error_port_(on_error_port),
script_url_(NULL),
package_root_(NULL),
library_url_(NULL),
@ -1965,7 +1988,8 @@ IsolateSpawnState::IsolateSpawnState(Dart_Port parent_port,
serialized_message_(NULL),
serialized_message_len_(0),
isolate_flags_(),
paused_(paused) {
paused_(paused),
errors_are_fatal_(errors_are_fatal) {
script_url_ = NULL;
const Class& cls = Class::Handle(func.Owner());
const Library& lib = Library::Handle(cls.library());
@ -1993,9 +2017,14 @@ IsolateSpawnState::IsolateSpawnState(Dart_Port parent_port,
const char* package_root,
const Instance& args,
const Instance& message,
bool paused)
bool paused,
bool errors_are_fatal,
Dart_Port on_exit_port,
Dart_Port on_error_port)
: isolate_(NULL),
parent_port_(parent_port),
on_exit_port_(on_exit_port),
on_error_port_(on_error_port),
package_root_(NULL),
library_url_(NULL),
class_name_(NULL),
@ -2005,7 +2034,8 @@ IsolateSpawnState::IsolateSpawnState(Dart_Port parent_port,
serialized_message_(NULL),
serialized_message_len_(0),
isolate_flags_(),
paused_(paused) {
paused_(paused),
errors_are_fatal_(errors_are_fatal) {
script_url_ = strdup(script_url);
if (package_root != NULL) {
package_root_ = strdup(package_root);

View file

@ -1013,19 +1013,27 @@ class IsolateSpawnState {
IsolateSpawnState(Dart_Port parent_port,
const Function& func,
const Instance& message,
bool paused);
bool paused,
bool errorsAreFatal,
Dart_Port onExit,
Dart_Port onError);
IsolateSpawnState(Dart_Port parent_port,
const char* script_url,
const char* package_root,
const Instance& args,
const Instance& message,
bool paused);
bool paused,
bool errorsAreFatal,
Dart_Port onExit,
Dart_Port onError);
~IsolateSpawnState();
Isolate* isolate() const { return isolate_; }
void set_isolate(Isolate* value) { isolate_ = value; }
Dart_Port parent_port() const { return parent_port_; }
Dart_Port on_exit_port() const { return on_exit_port_; }
Dart_Port on_error_port() const { return on_error_port_; }
char* script_url() const { return script_url_; }
char* package_root() const { return package_root_; }
char* library_url() const { return library_url_; }
@ -1033,6 +1041,7 @@ class IsolateSpawnState {
char* function_name() const { return function_name_; }
bool is_spawn_uri() const { return library_url_ == NULL; }
bool paused() const { return paused_; }
bool errors_are_fatal() const { return errors_are_fatal_; }
Isolate::Flags* isolate_flags() { return &isolate_flags_; }
RawObject* ResolveFunction();
@ -1043,6 +1052,8 @@ class IsolateSpawnState {
private:
Isolate* isolate_;
Dart_Port parent_port_;
Dart_Port on_exit_port_;
Dart_Port on_error_port_;
char* script_url_;
char* package_root_;
char* library_url_;
@ -1054,6 +1065,7 @@ class IsolateSpawnState {
intptr_t serialized_message_len_;
Isolate::Flags isolate_flags_;
bool paused_;
bool errors_are_fatal_;
};
} // namespace dart

View file

@ -0,0 +1,34 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library error_at_spawn;
import "dart:isolate";
import "dart:async";
import "package:async_helper/async_helper.dart";
import "package:expect/expect.dart";
isomain(args) {
throw new ArgumentError("fast error");
}
main(){
asyncStart();
// Capture errors from other isolate as raw messages.
RawReceivePort errorPort = new RawReceivePort();
errorPort.handler = (message) {
String error = message[0];
String stack = message[1];
Expect.equals(new ArgumentError("fast error").toString(), "$error");
errorPort.close();
asyncEnd();
};
Isolate.spawn(isomain,
null,
// Setup handler as part of spawn.
errorsAreFatal: false,
onError: errorPort.sendPort);
}

View file

@ -0,0 +1,9 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library error_at_spawnuri_iso;
main() {
throw new ArgumentError("fast error");
}

View file

@ -0,0 +1,30 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library error_at_spawnuri;
import "dart:isolate";
import "dart:async";
import "package:async_helper/async_helper.dart";
import "package:expect/expect.dart";
main(){
asyncStart();
// Capture errors from other isolate as raw messages.
RawReceivePort errorPort = new RawReceivePort();
errorPort.handler = (message) {
String error = message[0];
String stack = message[1];
Expect.equals(new ArgumentError("fast error").toString(), "$error");
errorPort.close();
asyncEnd();
};
Isolate.spawnUri(Uri.parse("error_at_spawnuri_iso.dart"), [],
null,
// Setup handler as part of spawn.
errorsAreFatal: false,
onError: errorPort.sendPort);
}

View file

@ -0,0 +1,88 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library error_exit_at_spawn;
import "dart:isolate";
import "dart:async";
import "package:async_helper/async_helper.dart";
import "package:expect/expect.dart";
isomain(replyPort) {
RawReceivePort port = new RawReceivePort();
port.handler = (v) {
switch (v) {
case 0:
replyPort.send(42);
break;
case 1:
throw new ArgumentError("whoops");
case 2:
throw new RangeError.value(37);
case 3:
port.close();
}
};
replyPort.send(port.sendPort);
}
main(){
asyncStart();
// Setup the port for communication with the newly spawned isolate.
RawReceivePort reply = new RawReceivePort(null);
SendPort sendPort;
int state = 0;
reply.handler = (port) {
sendPort = port;
port.send(state);
reply.handler = (v) {
Expect.equals(0, state);
Expect.equals(42, v);
state++;
sendPort.send(state);
};
};
// Capture errors from other isolate as raw messages.
RawReceivePort errorPort = new RawReceivePort();
errorPort.handler = (message) {
String error = message[0];
String stack = message[1];
switch (state) {
case 1:
Expect.equals(new ArgumentError("whoops").toString(), "$error");
state++;
sendPort.send(state);
break;
case 2:
Expect.equals(new RangeError.value(37).toString(), "$error");
state++;
sendPort.send(state);
reply.close();
errorPort.close();
break;
default:
throw "Bad state for error: $state: $error";
}
};
// Get exit notifications from other isolate as raw messages.
RawReceivePort exitPort = new RawReceivePort();
exitPort.handler = (message) {
// onExit ports registered at spawn cannot have a particular message
// associated.
Expect.equals(null, message);
// Only exit after sending the termination message.
Expect.equals(3, state);
exitPort.close();
asyncEnd();
};
Isolate.spawn(isomain,
reply.sendPort,
// Setup handlers as part of spawn.
errorsAreFatal: false,
onError: errorPort.sendPort,
onExit: exitPort.sendPort);
}

View file

@ -0,0 +1,25 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library error_exit_at_spawnuri_iso;
import "dart:isolate";
main(args, replyPort) {
RawReceivePort port = new RawReceivePort();
port.handler = (v) {
switch (v) {
case 0:
replyPort.send(42);
break;
case 1:
throw new ArgumentError("whoops");
case 2:
throw new RangeError.value(37);
case 3:
port.close();
}
};
replyPort.send(port.sendPort);
}

View file

@ -0,0 +1,70 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library error_exit_at_spawnuri;
import "dart:isolate";
import "dart:async";
import "package:async_helper/async_helper.dart";
import "package:expect/expect.dart";
main(){
asyncStart();
// Setup the port for communication with the newly spawned isolate.
RawReceivePort reply = new RawReceivePort(null);
SendPort sendPort;
int state = 0;
reply.handler = (port) {
sendPort = port;
port.send(state);
reply.handler = (v) {
Expect.equals(0, state);
Expect.equals(42, v);
state++;
sendPort.send(state);
};
};
// Capture errors from other isolate as raw messages.
RawReceivePort errorPort = new RawReceivePort();
errorPort.handler = (message) {
String error = message[0];
String stack = message[1];
switch (state) {
case 1:
Expect.equals(new ArgumentError("whoops").toString(), "$error");
state++;
sendPort.send(state);
break;
case 2:
Expect.equals(new RangeError.value(37).toString(), "$error");
state++;
sendPort.send(state);
reply.close();
errorPort.close();
break;
default:
throw "Bad state for error: $state: $error";
}
};
// Get exit notifications from other isolate as raw messages.
RawReceivePort exitPort = new RawReceivePort();
exitPort.handler = (message) {
// onExit ports registered at spawn cannot have a particular message
// associated.
Expect.equals(null, message);
// Only exit after sending the termination message.
Expect.equals(3, state);
exitPort.close();
asyncEnd();
};
Isolate.spawnUri(Uri.parse("error_exit_at_spawnuri_iso.dart"), [],
reply.sendPort,
// Setup handlers as part of spawn.
errorsAreFatal: false,
onError: errorPort.sendPort,
onExit: exitPort.sendPort);
}

View file

@ -0,0 +1,29 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library exit_at_spawn;
import "dart:isolate";
import "dart:async";
import "package:async_helper/async_helper.dart";
import "package:expect/expect.dart";
isomain(args) {}
main(){
asyncStart();
RawReceivePort exitPort = new RawReceivePort();
exitPort.handler = (message) {
Expect.equals(null, message);
exitPort.close();
asyncEnd();
};
Isolate.spawn(isomain,
null,
// Setup handler as part of spawn.
errorsAreFatal: false,
onExit: exitPort.sendPort);
}

View file

@ -0,0 +1,7 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library exit_at_spawn_iso;
main() {}

View file

@ -0,0 +1,27 @@
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library exit_at_spawn;
import "dart:isolate";
import "dart:async";
import "package:async_helper/async_helper.dart";
import "package:expect/expect.dart";
main(){
asyncStart();
RawReceivePort exitPort = new RawReceivePort();
exitPort.handler = (message) {
Expect.equals(null, message);
exitPort.close();
asyncEnd();
};
Isolate.spawnUri(Uri.parse("exit_at_spawnuri_iso.dart"), [],
null,
// Setup handler as part of spawn.
errorsAreFatal: false,
onExit: exitPort.sendPort);
}

View file

@ -49,6 +49,9 @@ issue_21398_parent_isolate_test: SkipByDesign # Test uses a ".dart" URI.
issue_21398_parent_isolate1_test: SkipByDesign # Test uses a ".dart" URI.
issue_21398_parent_isolate2_test: SkipByDesign # Test uses a ".dart" URI.
function_send1_test: SkipByDesign # Test uses a ".dart" URI.
error_exit_at_spawnuri_test: SkipByDesign # Test uses a ".dart" URI.
error_at_spawnuri_test: SkipByDesign # Test uses a ".dart" URI.
eexit_at_spawnuri_test: SkipByDesign # Test uses a ".dart" URI.
message3_test/constList: RuntimeError # Issue 21817
message3_test/constList_identical: RuntimeError # Issue 21817
message3_test/constMap: RuntimeError # Issue 21817
@ -117,6 +120,9 @@ deferred_in_isolate2_test: Fail, OK # Issue 16209, 13921 Dom isolates don't sup
bool_from_environment_default_value_test: Skip
int_from_environment_default_value_test: Skip
string_from_environment_default_value_test: Skip
error_exit_at_spawn_test: SkipByDesign # 13921 Dom isolates don't support spawnFunction
error_at_spawn_test: SkipByDesign # 13921 Dom isolates don't support spawnFunction
exit_at_spawn_test: SkipByDesign # 13921 Dom isolates don't support spawnFunction
[ $compiler == dartanalyzer || $compiler == dart2analyzer ]
browser/typed_data_message_test: StaticWarning