| // Copyright (c) 2012, 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. |
| |
| // Patch file for the dart:isolate library. |
| |
| import 'dart:_js_helper' show patch; |
| import 'dart:_isolate_helper' show CapabilityImpl, |
| IsolateNatives, |
| ReceivePortImpl, |
| RawReceivePortImpl; |
| |
| typedef _UnaryFunction(arg); |
| |
| @patch |
| class Isolate { |
| static final _currentIsolateCache = IsolateNatives.currentIsolate; |
| |
| // `current` must be a getter, not just a final field, |
| // to match the external declaration. |
| @patch |
| static Isolate get current => _currentIsolateCache; |
| |
| @patch |
| static Future<Uri> get packageRoot { |
| throw new UnsupportedError("Isolate.packageRoot"); |
| } |
| |
| @patch |
| static Future<Uri> get packageConfig { |
| throw new UnsupportedError("Isolate.packageConfig"); |
| } |
| |
| static Uri _packageBase = Uri.base.resolve(IsolateNatives.packagesBase); |
| |
| @patch |
| static Future<Uri> resolvePackageUri(Uri packageUri) async { |
| if (packageUri.scheme != 'package') return packageUri; |
| return _packageBase.resolveUri(packageUri.replace(scheme: '')); |
| } |
| |
| @patch |
| static Future<Isolate> spawn(void entryPoint(message), var message, |
| {bool paused: false, bool errorsAreFatal, |
| SendPort onExit, SendPort onError}) { |
| bool forcePause = (errorsAreFatal != null) || |
| (onExit != null) || |
| (onError != null); |
| try { |
| // Check for the type of `entryPoint` on the spawning isolate to make |
| // error-handling easier. |
| if (entryPoint is! _UnaryFunction) { |
| throw new ArgumentError(entryPoint); |
| } |
| // TODO: Consider passing the errorsAreFatal/onExit/onError values |
| // as arguments to the internal spawnUri instead of setting |
| // them after the isolate has been created. |
| return IsolateNatives.spawnFunction(entryPoint, message, |
| paused || forcePause) |
| .then((msg) { |
| var isolate = new Isolate(msg[1], |
| pauseCapability: msg[2], |
| terminateCapability: msg[3]); |
| if (forcePause) { |
| if (errorsAreFatal != null) { |
| isolate.setErrorsFatal(errorsAreFatal); |
| } |
| if (onExit != null) { |
| isolate.addOnExitListener(onExit); |
| } |
| if (onError != null) { |
| isolate.addErrorListener(onError); |
| } |
| if (!paused) { |
| isolate.resume(isolate.pauseCapability); |
| } |
| } |
| return isolate; |
| }); |
| } catch (e, st) { |
| return new Future<Isolate>.error(e, st); |
| } |
| } |
| |
| @patch |
| static Future<Isolate> spawnUri( |
| Uri uri, List<String> args, var message, |
| {bool paused: false, |
| SendPort onExit, |
| SendPort onError, |
| bool errorsAreFatal, |
| bool checked, |
| Map<String, String> environment, |
| Uri packageRoot, |
| Uri packageConfig, |
| bool automaticPackageResolution: false}) { |
| if (environment != null) throw new UnimplementedError("environment"); |
| if (packageRoot != null) throw new UnimplementedError("packageRoot"); |
| if (packageConfig != null) throw new UnimplementedError("packageConfig"); |
| // TODO(lrn): Figure out how to handle the automaticPackageResolution |
| // parameter. |
| bool forcePause = (errorsAreFatal != null) || |
| (onExit != null) || |
| (onError != null); |
| try { |
| if (args is List<String>) { |
| for (int i = 0; i < args.length; i++) { |
| if (args[i] is! String) { |
| throw new ArgumentError("Args must be a list of Strings $args"); |
| } |
| } |
| } else if (args != null) { |
| throw new ArgumentError("Args must be a list of Strings $args"); |
| } |
| // TODO: Handle [packageRoot] somehow, possibly by throwing. |
| // TODO: Consider passing the errorsAreFatal/onExit/onError values |
| // as arguments to the internal spawnUri instead of setting |
| // them after the isolate has been created. |
| return IsolateNatives.spawnUri(uri, args, message, paused || forcePause) |
| .then((msg) { |
| var isolate = new Isolate(msg[1], |
| pauseCapability: msg[2], |
| terminateCapability: msg[3]); |
| if (forcePause) { |
| if (errorsAreFatal != null) { |
| isolate.setErrorsFatal(errorsAreFatal); |
| } |
| if (onExit != null) { |
| isolate.addOnExitListener(onExit); |
| } |
| if (onError != null) { |
| isolate.addErrorListener(onError); |
| } |
| if (!paused) { |
| isolate.resume(isolate.pauseCapability); |
| } |
| } |
| return isolate; |
| }); |
| } catch (e, st) { |
| return new Future<Isolate>.error(e, st); |
| } |
| } |
| |
| @patch |
| void _pause(Capability resumeCapability) { |
| var message = new List(3) |
| ..[0] = "pause" |
| ..[1] = pauseCapability |
| ..[2] = resumeCapability; |
| controlPort.send(message); |
| } |
| |
| @patch |
| void resume(Capability resumeCapability) { |
| var message = new List(2) |
| ..[0] = "resume" |
| ..[1] = resumeCapability; |
| controlPort.send(message); |
| } |
| |
| @patch |
| void addOnExitListener(SendPort responsePort, {Object response}) { |
| // TODO(lrn): Can we have an internal method that checks if the receiving |
| // isolate of a SendPort is still alive? |
| var message = new List(3) |
| ..[0] = "add-ondone" |
| ..[1] = responsePort |
| ..[2] = response; |
| controlPort.send(message); |
| } |
| |
| @patch |
| void removeOnExitListener(SendPort responsePort) { |
| var message = new List(2) |
| ..[0] = "remove-ondone" |
| ..[1] = responsePort; |
| controlPort.send(message); |
| } |
| |
| @patch |
| void setErrorsFatal(bool errorsAreFatal) { |
| var message = new List(3) |
| ..[0] = "set-errors-fatal" |
| ..[1] = terminateCapability |
| ..[2] = errorsAreFatal; |
| controlPort.send(message); |
| } |
| |
| @patch |
| void kill({int priority: BEFORE_NEXT_EVENT}) { |
| controlPort.send(["kill", terminateCapability, priority]); |
| } |
| |
| @patch |
| void ping(SendPort responsePort, {Object response, |
| int priority: IMMEDIATE}) { |
| var message = new List(4) |
| ..[0] = "ping" |
| ..[1] = responsePort |
| ..[2] = priority |
| ..[3] = response; |
| controlPort.send(message); |
| } |
| |
| @patch |
| void addErrorListener(SendPort port) { |
| var message = new List(2) |
| ..[0] = "getErrors" |
| ..[1] = port; |
| controlPort.send(message); |
| } |
| |
| @patch |
| void removeErrorListener(SendPort port) { |
| var message = new List(2) |
| ..[0] = "stopErrors" |
| ..[1] = port; |
| controlPort.send(message); |
| } |
| } |
| |
| /** Default factory for receive ports. */ |
| @patch |
| class ReceivePort { |
| @patch |
| factory ReceivePort() = ReceivePortImpl; |
| |
| @patch |
| factory ReceivePort.fromRawReceivePort(RawReceivePort rawPort) { |
| return new ReceivePortImpl.fromRawReceivePort(rawPort); |
| } |
| } |
| |
| @patch |
| class RawReceivePort { |
| @patch |
| factory RawReceivePort([void handler(event)]) { |
| return new RawReceivePortImpl(handler); |
| } |
| } |
| |
| @patch |
| class Capability { |
| @patch |
| factory Capability() = CapabilityImpl; |
| } |