Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1403)

Unified Diff: sdk/lib/_internal/lib/isolate_helper.dart

Issue 169703002: Add an error listener on isolates. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Mark isolate_throws_test/01 failing. The test is wrong, and we should remove it (In another CL). Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | sdk/lib/isolate/isolate.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sdk/lib/_internal/lib/isolate_helper.dart
diff --git a/sdk/lib/_internal/lib/isolate_helper.dart b/sdk/lib/_internal/lib/isolate_helper.dart
index 85d9f2bd0442e559dfcd67a695fed23a543e3243..0a6bcb7799490c662b794787f17bb8d86587f804 100644
--- a/sdk/lib/_internal/lib/isolate_helper.dart
+++ b/sdk/lib/_internal/lib/isolate_helper.dart
@@ -89,7 +89,6 @@ void startRootIsolate(entry, args) {
// isolate automatically we try to give them a reasonable context to live in
// by having a "default" isolate (the first one created).
_globalState.currentContext = rootContext;
-
if (entry is _MainFunctionArgs) {
rootContext.eval(() { entry(args); });
} else if (entry is _MainFunctionArgsMessage) {
@@ -271,6 +270,13 @@ class _IsolateContext implements IsolateContext {
final Capability pauseCapability = new Capability();
final Capability terminateCapability = new Capability(); // License to kill.
+ /// Boolean flag set when the initial method of the isolate has been executed.
+ ///
+ /// Used to avoid considering the isolate dead when it has no open
+ /// receive ports and no scheduled timers, because it hasn't had time to
+ /// create them yet.
+ bool initialized = false;
+
// TODO(lrn): Store these in single "PauseState" object, so they don't take
// up as much room when not pausing.
bool isPaused = false;
@@ -290,11 +296,11 @@ class _IsolateContext implements IsolateContext {
var _scheduledControlEvents;
bool _isExecutingEvent = false;
- /** Whether errors are considered fatal. */
- // This doesn't do anything yet. We need to be able to catch uncaught errors
- // (oxymoronically) in order to take lethal action. This is waiting for the
- // same change as the uncaught error listeners.
- bool errorsAreFatal = false;
+ /** Whether uncaught errors are considered fatal. */
+ bool errorsAreFatal = true;
+
+ // Set of ports that listen to uncaught errors.
+ Set<SendPort> errorPorts = new Set();
_IsolateContext() {
this.registerWeak(controlPort._id, controlPort);
@@ -379,6 +385,40 @@ class _IsolateContext implements IsolateContext {
_scheduledControlEvents.addLast(kill);
}
+ void addErrorListener(SendPort port) {
+ errorPorts.add(port);
+ }
+
+ void removeErrorListener(SendPort port) {
+ errorPorts.remove(port);
+ }
+
+ /** Function called with an uncaught error. */
+ void handleUncaughtError(error, StackTrace stackTrace) {
+ // Just print the error if there is no error listener registered.
+ if (errorPorts.isEmpty) {
+ // An uncaught error in the root isolate will terminate the program?
+ if (errorsAreFatal && identical(this, _globalState.rootContext)) {
+ // The error will be rethrown to reach the global scope, so
+ // don't print it.
+ return;
+ }
+ if (JS('bool', '#.console != null && '
+ 'typeof #.console.error == "function"',
+ globalThis, globalThis)) {
+ JS('void', '#.console.error(#, #)', globalThis, error, stackTrace);
+ } else {
+ print(error);
+ if (stackTrace != null) print(stackTrace);
+ }
+ return;
+ }
+ List message = new List(2)
+ ..[0] = error.toString()
+ ..[1] = (stackTrace == null) ? null : stackTrace.toString();
+ for (SendPort port in errorPorts) port.send(message);
+ }
+
/**
* Run [code] in the context of the isolate represented by [this].
*/
@@ -390,6 +430,15 @@ class _IsolateContext implements IsolateContext {
_isExecutingEvent = true;
try {
result = code();
+ } catch (e, s) {
+ handleUncaughtError(e, s);
+ if (errorsAreFatal) {
+ kill();
+ // An uncaught error in the root context terminates all isolates.
+ if (identical(this, _globalState.rootContext)) {
+ rethrow;
+ }
+ }
} finally {
_isExecutingEvent = false;
_globalState.currentContext = old;
@@ -437,6 +486,12 @@ class _IsolateContext implements IsolateContext {
case "kill":
handleKill(message[1], message[2]);
break;
+ case "getErrors":
+ addErrorListener(message[1]);
+ break;
+ case "stopErrors":
+ removeErrorListener(message[1]);
+ break;
default:
}
}
@@ -468,7 +523,7 @@ class _IsolateContext implements IsolateContext {
}
void _updateGlobalState() {
- if (ports.length - weakPorts.length > 0 || isPaused) {
+ if (ports.length - weakPorts.length > 0 || isPaused || !initialized) {
_globalState.isolates[id] = this; // indicate this isolate is active
} else {
kill();
@@ -490,6 +545,7 @@ class _IsolateContext implements IsolateContext {
ports.clear();
weakPorts.clear();
_globalState.isolates.remove(id); // indicate this isolate is not active
+ errorPorts.clear();
if (doneHandlers != null) {
for (SendPort port in doneHandlers) {
port.send(null);
@@ -920,6 +976,7 @@ class IsolateNatives {
context.terminateCapability]);
void runStartFunction() {
+ context.initialized = true;
if (!isSpawnUri) {
topLevel(message);
} else if (topLevel is _MainFunctionArgsMessage) {
« no previous file with comments | « no previous file | sdk/lib/isolate/isolate.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698