// 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 get packageRoot { throw new UnsupportedError("Isolate.packageRoot"); } @patch static Future get packageConfig { throw new UnsupportedError("Isolate.packageConfig"); } static Uri _packageBase = Uri.base.resolve(IsolateNatives.packagesBase); @patch static Future resolvePackageUri(Uri packageUri) async { if (packageUri.scheme != 'package') return packageUri; return _packageBase.resolveUri(packageUri.replace(scheme: '')); } @patch static Future 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.error(e, st); } } @patch static Future spawnUri(Uri uri, List args, var message, {bool paused: false, SendPort onExit, SendPort onError, bool errorsAreFatal, bool checked, Map 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) { 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.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; }