Chromium Code Reviews| 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..5b5739b15af1346d1cc54a73c6772d98f6530b39 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 if it has no open |
|
floitsch
2014/05/15 12:15:25
"when if"
|
| + /// 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,34 @@ 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; |
| + } |
| + print(error); |
|
floitsch
2014/05/15 12:15:25
I would prefer using console.error when available.
Lasse Reichstein Nielsen
2014/05/19 11:13:37
Done.
|
| + 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 +424,15 @@ class _IsolateContext implements IsolateContext { |
| _isExecutingEvent = true; |
| try { |
| result = code(); |
| + } catch (e, s) { |
|
floitsch
2014/05/15 12:15:25
I'm afraid that this means that we won't have "bre
Lasse Reichstein Nielsen
2014/05/19 11:13:37
True.
That may have been one of the reasons for p
|
| + 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 +480,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 +517,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 +539,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 +970,7 @@ class IsolateNatives { |
| context.terminateCapability]); |
| void runStartFunction() { |
| + context.initialized = true; |
| if (!isSpawnUri) { |
| topLevel(message); |
| } else if (topLevel is _MainFunctionArgsMessage) { |