Very simple version of Isolates.

R=ajohnsen@google.com, iposva@google.com, kasperl@google.com, lrn@google.com

Review URL: https://codereview.chromium.org//27215002

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@29271 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
floitsch@google.com 2013-10-25 19:23:00 +00:00
parent d66aab045d
commit 6a72655d1b
154 changed files with 2082 additions and 3292 deletions

View file

@ -10,7 +10,9 @@ import 'package:scheduled_test/scheduled_test.dart';
import '../metatest.dart';
import 'utils.dart';
void main() {
void main(List<String> args, message) {
metaTestInit(message);
setUpTimeout();
expectTestsPass("async().create() forwards to file().create", () {

View file

@ -12,7 +12,9 @@ import 'package:scheduled_test/scheduled_test.dart';
import '../metatest.dart';
import 'utils.dart';
void main() {
void main(List<String> args, message) {
metaTestInit(message);
setUpTimeout();
expectTestsPass("directory().create() creates a directory and its contents",

View file

@ -11,7 +11,9 @@ import 'package:scheduled_test/scheduled_test.dart';
import '../metatest.dart';
import 'utils.dart';
void main() {
void main(List<String> args, message) {
metaTestInit(message);
setUpTimeout();
expectTestsPass('file().create() creates a file', () {

View file

@ -11,7 +11,9 @@ import 'package:scheduled_test/scheduled_test.dart';
import '../metatest.dart';
import 'utils.dart';
void main() {
void main(List<String> args, message) {
metaTestInit(message);
setUpTimeout();
expectTestsPass("nothing().create() does nothing", () {

View file

@ -10,7 +10,9 @@ import 'utils.dart';
String sandbox;
void main() {
void main(List<String> args, message) {
metaTestInit(message);
setUpTimeout();
expectTestsPass("pattern().validate() succeeds if there's a file matching "

View file

@ -107,40 +107,47 @@ SendPort _replyTo;
/// The cached [Future] for [_inChildIsolate].
Future<bool> _inChildIsolateFuture;
/// The initial message received by the isolate.
var _initialMessage;
void metaTestInit(message) {
_initialMessage = message;
}
/// Returns whether or not we're running in a child isolate that's supposed to
/// run a test.
Future<bool> get _inChildIsolate {
if (_inChildIsolateFuture != null) return _inChildIsolateFuture;
var completer = new Completer();
port.receive((message, replyTo) {
_testToRun = message['testToRun'];
_executable = message['executable'];
_replyTo = replyTo;
port.close();
completer.complete(true);
});
// TODO(nweiz): don't use a timeout here once issue 8416 is fixed.
_inChildIsolateFuture = timeout(completer.future, 500, () {
port.close();
return false;
});
if (_initialMessage == null) {
_inChildIsolateFuture = new Future.value(false);
} else {
_testToRun = _initialMessage['testToRun'];
_executable = _initialMessage['executable'];
_replyTo = _initialMessage['replyTo'];
_inChildIsolateFuture = new Future.value(true);
}
return _inChildIsolateFuture;
}
/// Runs the test described by [description] in its own isolate. Returns a map
/// describing the results of that test run.
Future<Map> _runInIsolate(String description) {
var replyPort = new ReceivePort();
// TODO(nweiz): Don't use path here once issue 8440 is fixed.
var future = spawnUri(path.join(path.current, Platform.script)).call({
return Isolate.spawnUri(Uri.parse(path.join(path.current, Platform.script)),
[], {
'testToRun': description,
'executable': Platform.executable
});
// TODO(nweiz): Remove this timeout once issue 8417 is fixed and we can
// capture top-level exceptions.
return timeout(future, 30 * 1000, () {
throw 'Timed out waiting for test to complete.';
'executable': Platform.executable,
'replyTo': replyPort.sendPort
}).then((_) {
var future = replyPort.first;
// TODO(nweiz): Remove this timeout once issue 8417 is fixed and we can
// capture top-level exceptions.
return timeout(future, 30 * 1000, () {
throw 'Timed out waiting for test to complete.';
});
});
}

View file

@ -9,7 +9,9 @@ import 'package:scheduled_test/scheduled_test.dart';
import 'metatest.dart';
import 'utils.dart';
void main() {
void main(List<String> args, message) {
metaTestInit(message);
setUpTimeout();
expectTestsPass("expect(..., completes) with a completing future should pass",

View file

@ -15,7 +15,9 @@ import 'package:scheduled_test/scheduled_test.dart';
import 'metatest.dart';
import 'utils.dart';
void main() {
void main(List<String> args, message) {
metaTestInit(message);
setUpTimeout();
expectTestsPass("a process must have kill() or shouldExit() called", () {

View file

@ -15,7 +15,9 @@ import 'package:scheduled_test/src/mock_clock.dart' as mock_clock;
import 'metatest.dart';
import 'utils.dart';
void main() {
void main(List<String> args, message) {
metaTestInit(message);
setUpTimeout();
expectTestsPass("a server with no handlers does nothing", () {

View file

@ -9,7 +9,9 @@ import 'package:scheduled_test/scheduled_test.dart';
import '../metatest.dart';
import '../utils.dart';
void main() {
void main(List<String> args, message) {
metaTestInit(message);
setUpTimeout();
expectTestsPass("aborting the schedule before it's started running should "

View file

@ -9,7 +9,9 @@ import 'package:scheduled_test/scheduled_test.dart';
import '../metatest.dart';
import '../utils.dart';
void main() {
void main(List<String> args, message) {
metaTestInit(message);
setUpTimeout();
expectTestsPass('currentSchedule.currentTask returns the current task while '

View file

@ -10,7 +10,9 @@ import 'package:scheduled_test/src/mock_clock.dart' as mock_clock;
import '../metatest.dart';
import '../utils.dart';
void main() {
void main(List<String> args, message) {
metaTestInit(message);
setUpTimeout();
expectTestsPass('currentSchedule.errors contains the error in the onComplete '

View file

@ -7,7 +7,9 @@ import 'package:scheduled_test/scheduled_test.dart';
import '../metatest.dart';
import '../utils.dart';
void main() {
void main(List<String> args, message) {
metaTestInit(message);
setUpTimeout();
expectTestsPass('currentSchedule.state starts out as SET_UP', () {

View file

@ -10,7 +10,9 @@ import 'package:scheduled_test/src/mock_clock.dart' as mock_clock;
import '../metatest.dart';
import '../utils.dart';
void main() {
void main(List<String> args, message) {
metaTestInit(message);
setUpTimeout();
expectTestsPass("nested schedule() runs its function immediately (but "

View file

@ -9,7 +9,9 @@ import 'package:scheduled_test/scheduled_test.dart';
import '../metatest.dart';
import '../utils.dart';
void main() {
void main(List<String> args, message) {
metaTestInit(message);
setUpTimeout();
expectTestsPass('the onComplete queue is run if a test is successful', () {

View file

@ -9,7 +9,9 @@ import 'package:scheduled_test/scheduled_test.dart';
import '../metatest.dart';
import '../utils.dart';
void main() {
void main(List<String> args, message) {
metaTestInit(message);
setUpTimeout();
expectTestsPass('the onException queue is not run if a test is successful',

View file

@ -10,7 +10,9 @@ import 'package:scheduled_test/src/mock_clock.dart' as mock_clock;
import '../metatest.dart';
import '../utils.dart';
void main() {
void main(List<String> args, message) {
metaTestInit(message);
setUpTimeout();
expectTestsPass("out-of-band schedule() runs its function immediately (but "

View file

@ -7,7 +7,9 @@ import 'package:scheduled_test/scheduled_test.dart';
import '../metatest.dart';
import '../utils.dart';
void main() {
void main(List<String> args, message) {
metaTestInit(message);
setUpTimeout();
expectTestsPass('setUp is run before each test', () {

View file

@ -10,7 +10,9 @@ import 'package:scheduled_test/src/mock_clock.dart' as mock_clock;
import '../metatest.dart';
import '../utils.dart';
void main() {
void main(List<String> args, message) {
metaTestInit(message);
setUpTimeout();
expectTestsFail('an out-of-band error reported via signalError is '

View file

@ -9,7 +9,9 @@ import 'package:scheduled_test/scheduled_test.dart';
import '../metatest.dart';
import '../utils.dart';
void main() {
void main(List<String> args, message) {
metaTestInit(message);
setUpTimeout();
expectTestsPass('a scheduled test with a correct synchronous expectation '

View file

@ -10,7 +10,9 @@ import 'package:scheduled_test/src/mock_clock.dart' as mock_clock;
import '../metatest.dart';
import '../utils.dart';
void main() {
void main(List<String> args, message) {
metaTestInit(message);
setUpTimeout();
expectTestsPass("an error thrown in a scheduled task should be piped to that "

View file

@ -10,7 +10,9 @@ import 'package:scheduled_test/src/mock_clock.dart' as mock_clock;
import '../metatest.dart';
import '../utils.dart';
void main() {
void main(List<String> args, message) {
metaTestInit(message);
setUpTimeout();
expectTestsPass("a single task that takes too long will cause a timeout "

View file

@ -10,7 +10,9 @@ import 'package:scheduled_test/src/mock_clock.dart' as mock_clock;
import '../metatest.dart';
import '../utils.dart';
void main() {
void main(List<String> args, message) {
metaTestInit(message);
setUpTimeout();
expectTestsFail('an out-of-band failure in wrapAsync is handled', () {

View file

@ -10,7 +10,9 @@ import 'package:scheduled_test/src/mock_clock.dart' as mock_clock;
import '../metatest.dart';
import '../utils.dart';
void main() {
void main(List<String> args, message) {
metaTestInit(message);
setUpTimeout();
expectTestsFail('an out-of-band failure in wrapFuture is handled', () {

View file

@ -549,8 +549,9 @@ void main() {
n3.parent = n1;
var s = nodeSerializerReflective(n1);
var output = s.write(n2);
var port = spawnFunction(echo);
return port.call(output).then(verify);
ReceivePort port = new ReceivePort();
var remote = Isolate.spawn(echo, [output, port.sendPort]);
port.first.then(verify);
});
}
@ -808,8 +809,8 @@ class PersonRuleReturningMapWithNonStringKey extends CustomRule {
* Function used in an isolate to make sure that the output passes through
* isolate serialization properly.
*/
void echo() {
port.receive((msg, reply) {
reply.send(msg);
});
void echo(initialMessage) {
var msg = initialMessage[0];
var reply = initialMessage[1];
reply.send(msg);
}

View file

@ -78,18 +78,16 @@ makeImmediateTeardown(index, s) => () {
s.write('l$index D ');
};
runTestInIsolate() {
port.receive((_, sendport) {
var testConfig = new TestConfiguration(sendport);
unittestConfiguration = testConfig;
testFunction(testConfig);
});
runTestInIsolate(sendport) {
var testConfig = new TestConfiguration(sendport);
unittestConfiguration = testConfig;
testFunction(testConfig);
}
main() {
spawnFunction(runTestInIsolate)
.call('')
.then((String msg) {
expect(msg.trim(), equals(expected));
});
var replyPort = new ReceivePort();
Isolate.spawn(runTestInIsolate, replyPort.sendPort);
replyPort.first.then((String msg) {
expect(msg.trim(), equals(expected));
});
}

View file

@ -6,7 +6,7 @@ import 'dart:nativewrappers';
patch class _EventHandler {
/* patch */ static void _sendData(Object sender,
ReceivePort receivePort,
RawReceivePort receivePort,
int data)
native "EventHandler_SendData";
}

View file

@ -6,7 +6,7 @@ patch class _IOService {
// Lazy initialize service ports, 32 per isolate.
static const int _SERVICE_PORT_COUNT = 32;
static List<SendPort> _servicePort = new List(_SERVICE_PORT_COUNT);
static ReceivePort _receivePort;
static RawReceivePort _receivePort;
static SendPort _replyToPort;
static Map<int, Completer> _messageMap = {};
static int _id = 0;
@ -29,9 +29,9 @@ patch class _IOService {
_servicePort[index] = _newServicePort();
}
if (_receivePort == null) {
_receivePort = new ReceivePort();
_replyToPort = _receivePort.toSendPort();
_receivePort.receive((data, _) {
_receivePort = new RawReceivePort();
_replyToPort = _receivePort.sendPort;
_receivePort.handler = (data) {
assert(data is List && data.length == 2);
_messageMap.remove(data[0]).complete(data[1]);
if (_messageMap.length == 0) {
@ -39,7 +39,7 @@ patch class _IOService {
_receivePort.close();
_receivePort = null;
}
});
};
}
}

View file

@ -881,16 +881,32 @@ int main(int argc, char** argv) {
}
} else {
// Lookup and invoke the top level main function.
Dart_Handle main_args[1];
// The top-level function may accept up to two arguments:
// main(List<String> args, var message).
// However most commonly it either accepts one (the args list) or
// none.
// If the message is optional, main(args, [message]), it is invoked with
// one argument only.
Dart_Handle main_args[2];
main_args[0] = CreateRuntimeOptions(&dart_options);
main_args[1] = Dart_Null();
// First try with 1 argument.
result = Dart_Invoke(library, DartUtils::NewString("main"), 1, main_args);
// TODO(iposva): Return a special error type for mismatched argument
// counts from Dart_Invoke to avoid the string comparison.
const char* expected_error = "Dart_Invoke: wrong argument count for "
"function 'main': 1 passed, 0 expected.";
"function 'main': ";
intptr_t length = strlen(expected_error);
if (Dart_IsError(result) &&
strcmp(expected_error, Dart_GetError(result)) == 0) {
result = Dart_Invoke(library, DartUtils::NewString("main"), 0, NULL);
strncmp(expected_error, Dart_GetError(result), length) == 0) {
// Try with two arguments.
result =
Dart_Invoke(library, DartUtils::NewString("main"), 2, main_args);
if (Dart_IsError(result) &&
strncmp(expected_error, Dart_GetError(result), length) == 0) {
// Finally try with 0 arguments.
result = Dart_Invoke(library, DartUtils::NewString("main"), 0, NULL);
}
}
if (Dart_IsError(result)) {
return DartErrorExit(result);

View file

@ -206,7 +206,7 @@ class _NativeSocket extends NativeFieldWrapperClass1 {
// Handlers and receive port for socket events from the event handler.
int eventMask = 0;
List eventHandlers;
ReceivePort eventPort;
RawReceivePort eventPort;
// Indicates if native interrupts can be activated.
bool canActivateEvents = true;
@ -588,8 +588,7 @@ class _NativeSocket extends NativeFieldWrapperClass1 {
void connectToEventHandler() {
if (eventPort == null) {
eventPort = new ReceivePort();
eventPort.receive ((var message, _) => multiplex(message));
eventPort = new RawReceivePort(multiplex);
}
}

View file

@ -12,16 +12,16 @@ class RunningIsolate implements ServiceRequestRouter {
Future sendMessage(List request) {
final completer = new Completer.sync();
final receivePort = new ReceivePort();
final receivePort = new RawReceivePort();
sendServiceMessage(sendPort, receivePort, request);
receivePort.receive((value, ignoreReplyTo) {
receivePort.handler = (value) {
receivePort.close();
if (value is Exception) {
completer.completeError(value);
} else {
completer.complete(value);
}
});
};
return completer.future;
}

View file

@ -31,14 +31,14 @@ class VMService {
}
}
void messageHandler(message, SendPort replyTo) {
void messageHandler(message) {
if (message is List && message.length == 3) {
controlMessageHandler(message[0], message[1], message[2]);
}
}
VMService._internal() {
port.receive(messageHandler);
port.listen(messageHandler);
}
factory VMService() {

View file

@ -53,7 +53,7 @@ static RawObject* ReceivePortCreate(intptr_t port_id) {
Library& isolate_lib = Library::Handle(Library::IsolateLibrary());
ASSERT(!isolate_lib.IsNull());
const String& class_name =
String::Handle(isolate_lib.PrivateName(Symbols::_ReceivePortImpl()));
String::Handle(isolate_lib.PrivateName(Symbols::_RawReceivePortImpl()));
const String& function_name =
String::Handle(isolate_lib.PrivateName(Symbols::_get_or_create()));
func = Resolver::ResolveStatic(isolate_lib,
@ -76,7 +76,7 @@ static RawObject* ReceivePortCreate(intptr_t port_id) {
}
DEFINE_NATIVE_ENTRY(ReceivePortImpl_factory, 1) {
DEFINE_NATIVE_ENTRY(RawReceivePortImpl_factory, 1) {
ASSERT(AbstractTypeArguments::CheckedHandle(
arguments->NativeArgAt(0)).IsNull());
intptr_t port_id =
@ -89,7 +89,7 @@ DEFINE_NATIVE_ENTRY(ReceivePortImpl_factory, 1) {
}
DEFINE_NATIVE_ENTRY(ReceivePortImpl_closeInternal, 1) {
DEFINE_NATIVE_ENTRY(RawReceivePortImpl_closeInternal, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(Smi, id, arguments->NativeArgAt(0));
PortMap::ClosePort(id.Value());
return Object::null();
@ -215,7 +215,7 @@ static RawObject* Spawn(NativeArguments* arguments, IsolateSpawnState* state) {
}
DEFINE_NATIVE_ENTRY(isolate_spawnFunction, 2) {
DEFINE_NATIVE_ENTRY(isolate_spawnFunction, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(Instance, closure, arguments->NativeArgAt(0));
bool throw_exception = false;
Function& func = Function::Handle();
@ -230,27 +230,7 @@ DEFINE_NATIVE_ENTRY(isolate_spawnFunction, 2) {
}
if (throw_exception) {
const String& msg = String::Handle(String::New(
"spawnFunction expects to be passed a closure to a top-level static "
"function"));
Exceptions::ThrowArgumentError(msg);
}
GET_NATIVE_ARGUMENT(Instance, callback, arguments->NativeArgAt(1));
Function& callback_func = Function::Handle();
if (callback.IsClosure()) {
callback_func = Closure::function(callback);
const Class& cls = Class::Handle(callback_func.Owner());
if (!callback_func.IsClosureFunction() || !callback_func.is_static() ||
!cls.IsTopLevel()) {
throw_exception = true;
}
} else if (!callback.IsNull()) {
throw_exception = true;
}
if (throw_exception) {
const String& msg = String::Handle(String::New(
"spawnFunction expects to be passed either a unhandled exception "
"callback to a top-level static function, or null"));
"Isolate.spawn expects to be passed a top-level function"));
Exceptions::ThrowArgumentError(msg);
}
@ -258,13 +238,9 @@ DEFINE_NATIVE_ENTRY(isolate_spawnFunction, 2) {
Context& ctx = Context::Handle();
ctx = Closure::context(closure);
ASSERT(ctx.num_variables() == 0);
if (!callback.IsNull()) {
ctx = Closure::context(callback);
ASSERT(ctx.num_variables() == 0);
}
#endif
return Spawn(arguments, new IsolateSpawnState(func, callback_func));
return Spawn(arguments, new IsolateSpawnState(func));
}

View file

@ -2,125 +2,109 @@
// 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.
class _CloseToken {
/// This token is sent from [IsolateSink]s to [IsolateStream]s to ask them to
/// close themselves.
const _CloseToken();
}
patch bool _isCloseToken(var object) {
// TODO(floitsch): can we compare against const _CloseToken()?
return object is _CloseToken;
}
patch class MessageBox {
/* patch */ MessageBox.oneShot() : this._oneShot(new ReceivePort());
MessageBox._oneShot(ReceivePort receivePort)
: stream = new IsolateStream._fromOriginalReceivePortOneShot(receivePort),
sink = new _IsolateSink._fromPort(receivePort.toSendPort());
/* patch */ MessageBox() : this._(new ReceivePort());
MessageBox._(ReceivePort receivePort)
: stream = new IsolateStream._fromOriginalReceivePort(receivePort),
sink = new _IsolateSink._fromPort(receivePort.toSendPort());
}
class _IsolateSink implements IsolateSink {
bool _isClosed = false;
final SendPort _port;
_IsolateSink._fromPort(this._port);
void add(dynamic message) {
_port.send(message);
}
void addError(Object errorEvent) {
throw new UnimplementedError("addError on isolate streams");
}
void close() {
if (_isClosed) return;
add(const _CloseToken());
_isClosed = true;
}
bool operator==(var other) {
return other is IsolateSink && _port == other._port;
}
int get hashCode => _port.hashCode + 499;
}
patch IsolateSink streamSpawnFunction(
void topLevelFunction(),
[bool unhandledExceptionCallback(IsolateUnhandledException e)]) {
SendPort sendPort = spawnFunction(topLevelFunction,
unhandledExceptionCallback);
return new _IsolateSink._fromPort(sendPort);
}
patch class ReceivePort {
/* patch */ factory ReceivePort() {
return new _ReceivePortImpl();
/* patch */ factory ReceivePort() = _ReceivePortImpl;
/* patch */ factory ReceivePort.fromRawReceivePort(RawReceivePort rawPort) =
_ReceivePortImpl.fromRawReceivePort;
}
patch class RawReceivePort {
/**
* Opens a long-lived port for receiving messages.
*
* A [RawReceivePort] is low level and does not work with [Zone]s. It
* can not be paused. The data-handler must be set before the first
* event is received.
*/
/* patch */ factory RawReceivePort([void handler(event)]) {
_RawReceivePortImpl result = new _RawReceivePortImpl();
result.handler = handler;
return result;
}
}
class _ReceivePortImpl implements ReceivePort {
factory _ReceivePortImpl() native "ReceivePortImpl_factory";
class _ReceivePortImpl extends Stream implements ReceivePort {
_ReceivePortImpl() : this.fromRawReceivePort(new RawReceivePort());
receive(void onMessage(var message, SendPort replyTo)) {
_onMessage = onMessage;
_ReceivePortImpl.fromRawReceivePort(this._rawPort) {
_controller = new StreamController(onCancel: close, sync: true);
_rawPort.handler = _controller.add;
}
SendPort get sendPort {
return _rawPort.sendPort;
}
StreamSubscription listen(void onData(var message),
{ Function onError,
void onDone(),
bool cancelOnError }) {
return _controller.stream.listen(onData,
onError: onError,
onDone: onDone,
cancelOnError: cancelOnError);
}
close() {
_rawPort.close();
_controller.close();
}
final RawReceivePort _rawPort;
StreamController _controller;
}
class _RawReceivePortImpl implements RawReceivePort {
factory _RawReceivePortImpl() native "RawReceivePortImpl_factory";
close() {
_portMap.remove(_id);
_closeInternal(_id);
}
SendPort toSendPort() {
SendPort get sendPort {
return new _SendPortImpl(_id);
}
/**** Internal implementation details ****/
// Called from the VM to create a new ReceivePort instance.
static _ReceivePortImpl _get_or_create(int id) {
if (_portMap != null) {
_ReceivePortImpl port = _portMap[id];
if (port != null) {
return port;
}
// Called from the VM to create a new RawReceivePort instance.
static _RawReceivePortImpl _get_or_create(int id) {
_RawReceivePortImpl port = _portMap[id];
if (port != null) {
return port;
}
return new _ReceivePortImpl._internal(id);
return new _RawReceivePortImpl._internal(id);
}
_ReceivePortImpl._internal(int id) : _id = id {
if (_portMap == null) {
_portMap = new Map();
}
_RawReceivePortImpl._internal(int id) : _id = id {
_portMap[id] = this;
}
// Called from the VM to retrieve the ReceivePort for a message.
static _ReceivePortImpl _lookupReceivePort(int id) {
assert(_portMap != null);
// Called from the VM to retrieve the RawReceivePort for a message.
static _RawReceivePortImpl _lookupReceivePort(int id) {
return _portMap[id];
}
// Called from the VM to dispatch to the handler.
static void _handleMessage(_ReceivePortImpl port, int replyId, var message) {
static void _handleMessage(
_RawReceivePortImpl port, int replyId, var message) {
assert(port != null);
SendPort replyTo = (replyId == 0) ? null : new _SendPortImpl(replyId);
(port._onMessage)(message, replyTo);
port._handler(message);
}
// Call into the VM to close the VM maintained mappings.
static _closeInternal(int id) native "ReceivePortImpl_closeInternal";
static _closeInternal(int id) native "RawReceivePortImpl_closeInternal";
void set handler(Function newHandler) {
this._handler = newHandler;
}
final int _id;
var _onMessage;
Function _handler;
// id to ReceivePort mapping.
static Map _portMap;
// id to RawReceivePort mapping.
static final Map _portMap = new HashMap();
}
@ -135,27 +119,19 @@ class _SendPortImpl implements SendPort {
_sendInternal(_id, replyId, message);
}
Future call(var message) {
final completer = new Completer.sync();
final port = new _ReceivePortImpl();
send(message, port.toSendPort());
port.receive((value, ignoreReplyTo) {
port.close();
if (value is Exception) {
completer.completeError(value);
} else {
completer.complete(value);
}
});
return completer.future;
}
bool operator==(var other) {
return (other is _SendPortImpl) && _id == other._id;
}
int get hashCode {
return _id;
const int MASK = 0x3FFFFFFF;
int hash = _id;
hash = (hash + ((hash & (MASK >> 10)) << 10)) & MASK;
hash ^= (hash >> 6);
hash = (hash + ((hash & (MASK >> 3)) << 3)) & MASK;
hash ^= (hash >> 11);
hash = (hash + ((hash & (MASK >> 15)) << 15)) & MASK;
return hash;
}
/*--- private implementation ---*/
@ -177,19 +153,86 @@ class _SendPortImpl implements SendPort {
_getPortInternal() native "isolate_getPortInternal";
ReceivePort _portInternal;
typedef _MainFunction();
typedef _MainFunctionArgs(args);
typedef _MainFunctionArgsMessage(args, message);
patch class _Isolate {
/* patch */ static ReceivePort get port {
if (_portInternal == null) {
_portInternal = _getPortInternal();
/**
* Takes the real entry point as argument and invokes it with the initial
* message.
*
* The initial message is (currently) received through the global port variable.
*/
void _startIsolate(Function entryPoint, bool isSpawnUri) {
Isolate._port.first.then((message) {
SendPort replyTo = message[0];
// TODO(floitsch): don't send ok-message if we can't find the entry point.
replyTo.send("started");
if (isSpawnUri) {
assert(message.length == 3);
List<String> args = message[1];
var isolateMessage = message[2];
if (entryPoint is _MainFunctionArgsMessage) {
entryPoint(args, isolateMessage);
} else if (entryPoint is _MainFunctionArgs) {
entryPoint(args);
} else {
entryPoint();
}
} else {
assert(message.length == 2);
var entryMessage = message[1];
entryPoint(entryMessage);
}
return _portInternal;
});
}
patch class Isolate {
/* patch */ static Future<Isolate> spawn(
void entryPoint(message), var message) {
Completer completer = new Completer<Isolate>.sync();
try {
// The VM will invoke [_startIsolate] with entryPoint as argument.
SendPort controlPort = _spawnFunction(entryPoint);
RawReceivePort readyPort = new RawReceivePort();
controlPort.send([readyPort.sendPort, message]);
readyPort.handler = (readyMessage) {
assert(readyMessage == 'started');
readyPort.close();
completer.complete(new Isolate._fromControlPort(controlPort));
};
} catch(e, st) {
// TODO(floitsch): we want errors to go into the returned future.
rethrow;
};
return completer.future;
}
/* patch */ static SendPort spawnFunction(void topLevelFunction(),
[bool unhandledExceptionCallback(IsolateUnhandledException e)])
/* patch */ static Future<Isolate> spawnUri(
Uri uri, List<String> args, var message) {
Completer completer = new Completer<Isolate>.sync();
try {
// The VM will invoke [_startIsolate] and not `main`.
SendPort controlPort = _spawnUri(uri.path);
RawReceivePort readyPort = new RawReceivePort();
controlPort.send([readyPort.sendPort, args, message]);
readyPort.handler = (readyMessage) {
assert(readyMessage == 'started');
readyPort.close();
completer.complete(new Isolate._fromControlPort(controlPort));
};
} catch(e, st) {
// TODO(floitsch): we want errors to go into the returned future.
rethrow;
};
return completer.future;
}
static final ReceivePort _port =
new ReceivePort.fromRawReceivePort(_getPortInternal());
static SendPort _spawnFunction(Function topLevelFunction)
native "isolate_spawnFunction";
/* patch */ static SendPort spawnUri(String uri) native "isolate_spawnUri";
static SendPort _spawnUri(String uri) native "isolate_spawnUri";
}

View file

@ -495,7 +495,7 @@ void main() {
'testCustomInstanceMirror']);
// Test that an isolate can reflect on itself.
mirrorSystemOf(exit_port.toSendPort()).then(testMirrorSystem);
mirrorSystemOf(exit_port.sendPort).then(testMirrorSystem);
testIntegerInstanceMirror(reflect(1001));
testStringInstanceMirror(reflect('This\nis\na\nString'));

View file

@ -11,11 +11,9 @@ import "package:expect/expect.dart";
import 'dart:isolate';
import 'dart:mirrors';
void isolateMain() {
port.receive(
(msg, replyPort) {
Expect.fail('Received unexpected message $msg in remote isolate.');
});
void isolateMain(SendPort replyTo) {
var port = new ReceivePort();
replyTo.send(port.sendPort);
}
void testMirrorSystem(MirrorSystem mirror) {
@ -23,11 +21,14 @@ void testMirrorSystem(MirrorSystem mirror) {
}
void main() {
SendPort sp = spawnFunction(isolateMain);
try {
mirrorSystemOf(sp).then(testMirrorSystem);
Expect.fail('Should not reach here. Remote isolates not implemented.');
} catch (exception) {
Expect.isTrue(exception is UnimplementedError);
}
var response = new ReceivePort();
Isolate.spawn(isolateMain, response.sendPort);
response.first.then((sp) {
try {
mirrorSystemOf(sp).then(testMirrorSystem);
Expect.fail('Should not reach here. Remote isolates not implemented.');
} catch (exception) {
Expect.isTrue(exception is UnimplementedError);
}
});
}

View file

@ -1,51 +0,0 @@
// 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.
library isolate_unhandled_exception_test;
import "package:expect/expect.dart";
import 'dart:async';
import 'dart:isolate';
// Tests that an isolate's keeps message handling working after
// throwing an unhandled exception, if it was created with an
// unhandled exception callback that returns true (continue handling).
// This test verifies that a callback function specified in
// Isolate.spawnFunction is called.
// Note: this test will hang if an uncaught exception isn't handled,
// either by an error in the callback or it returning false.
void entry() {
port.receive((message, replyTo) {
if (message == 'throw exception') {
replyTo.call('throwing exception');
throw new UnsupportedError('ignore this exception');
}
replyTo.call('hello');
port.close();
});
}
bool exceptionCallback(IsolateUnhandledException e) {
return e.source.message == 'ignore this exception';
}
void main() {
var isolate_port = spawnFunction(entry, exceptionCallback);
// Send a message that will cause an ignorable exception to be thrown.
Future f = isolate_port.call('throw exception');
f.catchError((error) {
// Exception wasn't ignored as it was supposed to be.
Expect.fail("Error not expected");
});
// Verify that isolate can still handle messages.
isolate_port.call('hi').then((value) {
Expect.equals('hello', value);
}, onError: (error) {
Expect.fail("Error not expected");
});
}

View file

@ -1,49 +0,0 @@
// 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.
library isolate_unhandled_exception_test2;
import 'dart:isolate';
// Tests that an isolate's keeps message handling working after
// throwing an unhandled exception, if there is a top level callback
// method that returns whether to continue handling messages or not.
// This test verifies that a default-named callback function is called
// when no callback is specified in Isolate.spawnFunction.
// Note: this test will hang if an uncaught exception isn't handled,
// either by an error in the callback or it returning false.
void entry() {
port.receive((message, replyTo) {
if (message == 'throw exception') {
replyTo.call('throwing exception');
throw new UnsupportedError('ignore this exception');
}
replyTo.call('hello');
port.close();
});
}
bool _unhandledExceptionCallback(IsolateUnhandledException e) {
return e.source.message == 'ignore this exception';
}
void main() {
var isolate_port = spawnFunction(entry);
// Send a message that will cause an ignorable exception to be thrown.
Future f = isolate_port.call('throw exception');
f.onComplete((future) {
// Exception wasn't ignored as it was supposed to be.
Expect.equals(null, future.exception);
});
// Verify that isolate can still handle messages.
isolate_port.call('hi').onComplete((future) {
Expect.equals(null, future.exception);
Expect.equals('hello', future.value);
});
}

View file

@ -1,25 +0,0 @@
// 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.
library isolate_unhandled_exception_uri_helper;
import 'dart:isolate';
// Isolate script that throws an uncaught exception, which is caught by an
// uncaught exception handler.
void main() {
port.receive((message, replyTo) {
if (message == 'throw exception') {
replyTo.call('throwing exception');
throw new UnsupportedError('ignore this exception');
}
replyTo.call('hello');
port.close();
});
}
bool _unhandledExceptionCallback(IsolateUnhandledException e) {
return e.source.message == 'ignore this exception';
}

View file

@ -1,34 +0,0 @@
// 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.
library isolate_unhandled_exception_uri_helper;
import "package:expect/expect.dart";
import 'dart:async';
import 'dart:isolate';
// Tests that isolate code in another script keeps message handling working
// after throwing an unhandled exception, if it has a function called
// unhandledExceptionCallback that returns true (continue handling).
// Note: this test will hang if an uncaught exception isn't handled,
// either by an error in the callback or it returning false.
void main() {
var isolate_port = spawnUri('isolate_unhandled_exception_uri_helper.dart');
// Send a message that will cause an ignorable exception to be thrown.
Future f = isolate_port.call('throw exception');
f.catchError((error) {
Expect.fail("Error not expected");
});
// Verify that isolate can still handle messages.
isolate_port.call('hi').then((value) {
Expect.equals('hello', value);
}, onError: (error) {
Expect.fail("Error not expected");
});
}

View file

@ -39,8 +39,8 @@ namespace dart {
V(Integer_equalToInteger, 2) \
V(Integer_parse, 1) \
V(Integer_leftShiftWithMask32, 3) \
V(ReceivePortImpl_factory, 1) \
V(ReceivePortImpl_closeInternal, 1) \
V(RawReceivePortImpl_factory, 1) \
V(RawReceivePortImpl_closeInternal, 1) \
V(SendPortImpl_sendInternal_, 3) \
V(Smi_shlFromInt, 2) \
V(Smi_shrFromInt, 2) \
@ -249,7 +249,7 @@ namespace dart {
V(Uint32x4_setFlagW, 2) \
V(Uint32x4_select, 3) \
V(isolate_getPortInternal, 0) \
V(isolate_spawnFunction, 2) \
V(isolate_spawnFunction, 1) \
V(isolate_spawnUri, 1) \
V(Mirrors_isLocalPort, 1) \
V(Mirrors_makeLocalClassMirror, 1) \

View file

@ -24,7 +24,7 @@ static Dart_NativeFunction NativeLookup(Dart_Handle name, int argc);
static const char* kCustomIsolateScriptChars =
"import 'dart:isolate';\n"
"\n"
"ReceivePort mainPort;\n"
"RawReceivePort mainPort;\n"
"\n"
"echo(arg) native \"native_echo\";\n"
"\n"
@ -51,21 +51,23 @@ static const char* kCustomIsolateScriptChars =
"\n"
"isolateMain() {\n"
" echo('Running isolateMain');\n"
" mainPort.receive((message, SendPort replyTo) {\n"
" echo('Received: $message');\n"
" replyTo.send((message + 1), null);\n"
" });\n"
" mainPort.handler = (message) {\n"
" var data = message[0];\n"
" var replyTo = message[1];\n"
" echo('Received: $data');\n"
" replyTo.send(data + 1);\n"
" };\n"
"}\n"
"\n"
"main() {\n"
" var isolate = new CustomIsolate(\"isolateMain\");\n"
" var receivePort = new ReceivePort();\n"
" var receivePort = new RawReceivePort();\n"
" SendPort port = isolate.spawn();\n"
" port.send(42, receivePort.toSendPort());\n"
" receivePort.receive((message, _) {\n"
" port.send([42, receivePort.sendPort]);\n"
" receivePort.handler = (message) {\n"
" receivePort.close();\n"
" echo('Received: $message');\n"
" });\n"
" };\n"
" return 'success';\n"
"}\n";

View file

@ -1069,7 +1069,7 @@ DART_EXPORT Dart_Handle Dart_GetReceivePort(Dart_Port port_id) {
Library& isolate_lib = Library::Handle(isolate, Library::IsolateLibrary());
ASSERT(!isolate_lib.IsNull());
const String& class_name = String::Handle(
isolate, isolate_lib.PrivateName(Symbols::_ReceivePortImpl()));
isolate, isolate_lib.PrivateName(Symbols::_RawReceivePortImpl()));
// TODO(asiva): Symbols should contain private keys.
const String& function_name =
String::Handle(isolate_lib.PrivateName(Symbols::_get_or_create()));

View file

@ -3672,22 +3672,24 @@ TEST_CASE(NegativeNativeFieldInIsolateMessage) {
const char* kScriptChars =
"import 'dart:isolate';\n"
"import 'dart:nativewrappers';\n"
"echo() {\n"
" port.receive((msg, reply) {\n"
" reply.send('echoing ${msg(1)}}');\n"
" });\n"
"echo(msg) {\n"
" var data = msg[0];\n"
" var reply = msg[1];\n"
" reply.send('echoing ${data(1)}}');\n"
"}\n"
"class Test extends NativeFieldWrapperClass2 {\n"
" Test(this.i, this.j);\n"
" int i, j;\n"
"}\n"
"main() {\n"
" var snd = spawnFunction(echo);\n"
" var port = new RawReceivePort();\n"
" var obj = new Test(1,2);\n"
" snd.send(obj, port.toSendPort());\n"
" port.receive((msg, reply) {\n"
" var msg = [obj, port.sendPort];\n"
" var snd = Isolate.spawn(echo, msg);\n"
" port.handler = (msg) {\n"
" port.close();\n"
" print('from worker ${msg}');\n"
" });\n"
" };\n"
"}\n";
DARTSCOPE(Isolate::Current());
@ -5780,12 +5782,12 @@ UNIT_TEST_CASE(NewNativePort) {
const char* kScriptChars =
"import 'dart:isolate';\n"
"void callPort(SendPort port) {\n"
" var receivePort = new ReceivePort();\n"
" port.send(null, receivePort.toSendPort());\n"
" receivePort.receive((message, _) {\n"
" var receivePort = new RawReceivePort();\n"
" port.send(null, receivePort.sendPort);\n"
" receivePort.handler = (message) {\n"
" receivePort.close();\n"
" throw new Exception(message);\n"
" });\n"
" };\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
Dart_EnterScope();
@ -5834,26 +5836,24 @@ static Dart_Isolate RunLoopTestCallback(const char* script_name,
const char* kScriptChars =
"import 'builtin';\n"
"import 'dart:isolate';\n"
"void entry() {\n"
" port.receive((message, replyTo) {\n"
" if (message) {\n"
" throw new Exception('MakeChildExit');\n"
" } else {\n"
" replyTo.call('hello');\n"
" port.close();\n"
" }\n"
" });\n"
"void entry(message) {\n"
" var data = message[0];\n"
" var replyTo = message[1];\n"
" if (data) {\n"
" throw new Exception('MakeChildExit');\n"
" } else {\n"
" replyTo.send('hello');\n"
" }\n"
"}\n"
"\n"
"void main(exc_child, exc_parent) {\n"
" var port = spawnFunction(entry);\n"
" var receivePort = new ReceivePort();\n"
" port.send(exc_child, receivePort.toSendPort());\n"
" receivePort.receive((message, _) {\n"
" var receivePort = new RawReceivePort();\n"
" Isolate.spawn(entry, [exc_child, receivePort.sendPort]);\n"
" receivePort.handler = (message) {\n"
" receivePort.close();\n"
" if (message != 'hello') throw new Exception('ShouldNotHappen');\n"
" if (exc_parent) throw new Exception('MakeParentExit');\n"
" });\n"
" };\n"
"}\n";
if (Dart_CurrentIsolate() != NULL) {

View file

@ -383,7 +383,7 @@ RawObject* DartLibraryCalls::LookupReceivePort(Dart_Port port_id) {
Library& isolate_lib = Library::Handle(Library::IsolateLibrary());
ASSERT(!isolate_lib.IsNull());
const String& class_name =
String::Handle(isolate_lib.PrivateName(Symbols::_ReceivePortImpl()));
String::Handle(isolate_lib.PrivateName(Symbols::_RawReceivePortImpl()));
const String& function_name =
String::Handle(isolate_lib.PrivateName(Symbols::_lookupReceivePort()));
function = Resolver::ResolveStatic(isolate_lib,
@ -415,7 +415,7 @@ RawObject* DartLibraryCalls::HandleMessage(const Object& receive_port,
Library& isolate_lib = Library::Handle(Library::IsolateLibrary());
ASSERT(!isolate_lib.IsNull());
const String& class_name =
String::Handle(isolate_lib.PrivateName(Symbols::_ReceivePortImpl()));
String::Handle(isolate_lib.PrivateName(Symbols::_RawReceivePortImpl()));
const String& function_name =
String::Handle(isolate_lib.PrivateName(Symbols::_handleMessage()));
function = Resolver::ResolveStatic(isolate_lib,

View file

@ -510,6 +510,7 @@ static bool RunIsolate(uword parameter) {
Object& result = Object::Handle();
result = state->ResolveFunction();
bool is_spawn_uri = state->is_spawn_uri();
delete state;
state = NULL;
if (result.IsError()) {
@ -519,7 +520,27 @@ static bool RunIsolate(uword parameter) {
ASSERT(result.IsFunction());
Function& func = Function::Handle(isolate);
func ^= result.raw();
result = DartEntry::InvokeFunction(func, Object::empty_array());
func = func.ImplicitClosureFunction();
// Instead of directly invoking the entry point we call '_startIsolate' with
// the entry point as argument. The '_startIsolate' function will
// communicate with the spawner to receive the initial message before it
// executes the real entry point.
// Since this function ("RunIsolate") is used for both Isolate.spawn and
// Isolate.spawnUri we also send a boolean flag as argument so that the
// "_startIsolate" function can act corresponding to how the isolate was
// created.
const Array& args = Array::Handle(Array::New(2));
args.SetAt(0, Instance::Handle(func.ImplicitStaticClosure()));
args.SetAt(1, is_spawn_uri ? Bool::True() : Bool::False());
const Library& lib = Library::Handle(Library::IsolateLibrary());
const String& entry_name = String::Handle(String::New("_startIsolate"));
const Function& entry_point =
Function::Handle(lib.LookupLocalFunction(entry_name));
ASSERT(entry_point.IsFunction() && !entry_point.IsNull());
result = DartEntry::InvokeFunction(entry_point, args);
if (result.IsError()) {
StoreError(isolate, result);
return false;
@ -968,8 +989,7 @@ T* Isolate::AllocateReusableHandle() {
}
IsolateSpawnState::IsolateSpawnState(const Function& func,
const Function& callback_func)
IsolateSpawnState::IsolateSpawnState(const Function& func)
: isolate_(NULL),
script_url_(NULL),
library_url_(NULL),
@ -984,12 +1004,7 @@ IsolateSpawnState::IsolateSpawnState(const Function& func,
const String& func_name = String::Handle(func.name());
function_name_ = strdup(func_name.ToCString());
if (!callback_func.IsNull()) {
const String& callback_name = String::Handle(callback_func.name());
exception_callback_name_ = strdup(callback_name.ToCString());
} else {
exception_callback_name_ = strdup("_unhandledExceptionCallback");
}
exception_callback_name_ = strdup("_unhandledExceptionCallback");
}

View file

@ -512,7 +512,7 @@ class SwitchIsolateScope {
class IsolateSpawnState {
public:
IsolateSpawnState(const Function& func, const Function& callback_func);
explicit IsolateSpawnState(const Function& func);
explicit IsolateSpawnState(const char* script_url);
~IsolateSpawnState();
@ -522,6 +522,7 @@ class IsolateSpawnState {
char* library_url() const { return library_url_; }
char* function_name() const { return function_name_; }
char* exception_callback_name() const { return exception_callback_name_; }
bool is_spawn_uri() const { return library_url_ == NULL; }
RawObject* ResolveFunction();
void Cleanup();

View file

@ -23,10 +23,10 @@ UNIT_TEST_CASE(IsolateCurrent) {
TEST_CASE(IsolateSpawn) {
const char* kScriptChars =
"import 'dart:isolate';\n"
"void entry() {}\n"
"void entry(message) {}\n"
"int testMain() {\n"
" try {\n"
" spawnFunction(entry);\n"
" Isolate.spawn(entry, null);\n"
" } catch (e) {\n"
" rethrow;\n"
" }\n"

View file

@ -2604,8 +2604,8 @@ UNIT_TEST_CASE(PostCObject) {
"main() {\n"
" var messageCount = 0;\n"
" var exception = '';\n"
" var port = new ReceivePort();\n"
" port.receive((message, replyTo) {\n"
" var port = new RawReceivePort();\n"
" port.handler = (message) {\n"
" if (messageCount < 8) {\n"
" exception = '$exception${message}';\n"
" } else {\n"
@ -2616,8 +2616,8 @@ UNIT_TEST_CASE(PostCObject) {
" }\n"
" messageCount++;\n"
" if (messageCount == 9) throw new Exception(exception);\n"
" });\n"
" return port.toSendPort();\n"
" };\n"
" return port.sendPort;\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
Dart_EnterScope();

View file

@ -216,7 +216,7 @@ class ObjectPointerVisitor;
V(InvocationMirror, "_InvocationMirror") \
V(AllocateInvocationMirror, "_allocateInvocationMirror") \
V(toString, "toString") \
V(_ReceivePortImpl, "_ReceivePortImpl") \
V(_RawReceivePortImpl, "_RawReceivePortImpl") \
V(_lookupReceivePort, "_lookupReceivePort") \
V(_handleMessage, "_handleMessage") \
V(_SendPortImpl, "_SendPortImpl") \
@ -234,7 +234,7 @@ class ObjectPointerVisitor;
V(InternalError, "InternalError") \
V(NullThrownError, "NullThrownError") \
V(IsolateSpawnException, "IsolateSpawnException") \
V(IsolateUnhandledException, "IsolateUnhandledException") \
V(IsolateUnhandledException, "_IsolateUnhandledException") \
V(JavascriptIntegerOverflowError, "_JavascriptIntegerOverflowError") \
V(MirroredCompilationError, "MirroredCompilationError") \
V(_setupFullStackTrace, "_setupFullStackTrace") \

View file

@ -34,7 +34,7 @@ patch class _Directory {
patch class _EventHandler {
patch static void _sendData(Object sender,
ReceivePort receivePort,
RawReceivePort receivePort,
int data) {
throw new UnsupportedError("EventHandler._sendData");
}

View file

@ -22,38 +22,6 @@ import 'dart:_interceptors' show JSExtendableArray;
ReceivePort lazyPort;
class CloseToken {
/// This token is sent from [IsolateSink]s to [IsolateStream]s to ask them to
/// close themselves.
const CloseToken();
}
class JsIsolateSink extends EventSink<dynamic> implements IsolateSink {
bool _isClosed = false;
final SendPort _port;
JsIsolateSink.fromPort(this._port);
void add(dynamic message) {
_port.send(message);
}
void addError(errorEvent) {
throw new UnimplementedError("addError on isolate streams");
}
void close() {
if (_isClosed) return;
add(const CloseToken());
_isClosed = true;
}
bool operator==(var other) {
return other is IsolateSink && _port == other._port;
}
int get hashCode => _port.hashCode + 499;
}
/**
* Called by the compiler to support switching
* between isolates when we get a callback from the DOM.
@ -90,7 +58,13 @@ void startRootIsolate(entry) {
// by having a "default" isolate (the first one created).
_globalState.currentContext = rootContext;
rootContext.eval(entry);
if (entry is _MainFunctionArgs) {
rootContext.eval(() { entry([]); });
} else if (entry is _MainFunctionArgsMessage) {
rootContext.eval(() { entry([], null); });
} else {
rootContext.eval(entry);
}
_globalState.topEventLoop.run();
}
@ -417,6 +391,10 @@ var globalWorker = JS('', "#.Worker", globalThis);
bool globalPostMessageDefined =
JS('', "#.postMessage !== (void 0)", globalThis);
typedef _MainFunction();
typedef _MainFunctionArgs(args);
typedef _MainFunctionArgsMessage(args, message);
class IsolateNatives {
static String thisScript = computeThisScript();
@ -500,10 +478,13 @@ class IsolateNatives {
Function entryPoint = (functionName == null)
? _globalState.entry
: _getJSFunctionFromName(functionName);
var args = msg['args'];
var message = _deserializeMessage(msg['msg']);
var isSpawnUri = msg['isSpawnUri'];
var replyTo = _deserializeMessage(msg['replyTo']);
var context = new _IsolateContext();
_globalState.topEventLoop.enqueue(context, () {
_startIsolate(entryPoint, replyTo);
_startIsolate(entryPoint, args, message, isSpawnUri, replyTo);
}, 'worker-start');
// Make sure we always have a current context in this worker.
// TODO(7907): This is currently needed because we're using
@ -515,13 +496,15 @@ class IsolateNatives {
_globalState.topEventLoop.run();
break;
case 'spawn-worker':
_spawnWorker(msg['functionName'], msg['uri'], msg['replyPort']);
_spawnWorker(msg['functionName'], msg['uri'],
msg['args'], msg['msg'],
msg['isSpawnUri'], msg['replyPort']);
break;
case 'message':
SendPort port = msg['port'];
// If the port has been closed, we ignore the message.
if (port != null) {
msg['port'].send(msg['msg'], msg['replyTo']);
msg['port'].send(msg['msg']);
}
_globalState.topEventLoop.run();
break;
@ -582,19 +565,25 @@ class IsolateNatives {
return JS("", "new #()", ctor);
}
static SendPort spawnFunction(void topLevelFunction()) {
static SendPort spawnFunction(void topLevelFunction(message), message) {
final name = _getJSFunctionName(topLevelFunction);
if (name == null) {
throw new UnsupportedError(
"only top-level functions can be spawned.");
}
return spawn(name, null, false);
return spawn(name, null, null, message, false, false);
}
static SendPort spawnUri(Uri uri, List<String> args, message) {
return spawn(null, uri.path, args, message, false, true);
}
// TODO(sigmund): clean up above, after we make the new API the default:
/// If [uri] is `null` it is replaced with the current script.
static spawn(String functionName, String uri, bool isLight) {
static SendPort spawn(String functionName, String uri,
List<String> args, message,
bool isLight, bool isSpawnUri) {
// Assume that the compiled version of the Dart file lives just next to the
// dart file.
// TODO(floitsch): support precompiled version of dart2js output.
@ -602,60 +591,86 @@ class IsolateNatives {
Completer<SendPort> completer = new Completer<SendPort>.sync();
ReceivePort port = new ReceivePort();
port.receive((msg, SendPort replyPort) {
port.listen((msg) {
port.close();
assert(msg == _SPAWNED_SIGNAL);
completer.complete(replyPort);
assert(msg[0] == _SPAWNED_SIGNAL);
completer.complete(msg[1]);
});
SendPort signalReply = port.toSendPort();
SendPort signalReply = port.sendPort;
if (_globalState.useWorkers && !isLight) {
_startWorker(functionName, uri, signalReply);
_startWorker(functionName, uri, args, message, isSpawnUri, signalReply);
} else {
_startNonWorker(functionName, uri, signalReply);
_startNonWorker(
functionName, uri, args, message, isSpawnUri, signalReply);
}
return new _BufferingSendPort(
_globalState.currentContext.id, completer.future);
}
static SendPort _startWorker(
String functionName, String uri, SendPort replyPort) {
static void _startWorker(
String functionName, String uri,
List<String> args, message,
bool isSpawnUri,
SendPort replyPort) {
if (_globalState.isWorker) {
_globalState.mainManager.postMessage(_serializeMessage({
'command': 'spawn-worker',
'functionName': functionName,
'args': args,
'msg': message,
'uri': uri,
'isSpawnUri': isSpawnUri,
'replyPort': replyPort}));
} else {
_spawnWorker(functionName, uri, replyPort);
_spawnWorker(functionName, uri, args, message, isSpawnUri, replyPort);
}
}
static SendPort _startNonWorker(
String functionName, String uri, SendPort replyPort) {
static void _startNonWorker(
String functionName, String uri,
List<String> args, message,
bool isSpawnUri,
SendPort replyPort) {
// TODO(eub): support IE9 using an iframe -- Dart issue 1702.
if (uri != null) throw new UnsupportedError(
"Currently spawnUri is not supported without web workers.");
if (uri != null) {
throw new UnsupportedError(
"Currently spawnUri is not supported without web workers.");
}
_globalState.topEventLoop.enqueue(new _IsolateContext(), () {
final func = _getJSFunctionFromName(functionName);
_startIsolate(func, replyPort);
_startIsolate(func, args, message, isSpawnUri, replyPort);
}, 'nonworker start');
}
static void _startIsolate(Function topLevel, SendPort replyTo) {
static void _startIsolate(Function topLevel,
List<String> args, message,
bool isSpawnUri,
SendPort replyTo) {
_IsolateContext context = JS_CURRENT_ISOLATE_CONTEXT();
Primitives.initializeStatics(context.id);
lazyPort = new ReceivePort();
replyTo.send(_SPAWNED_SIGNAL, port.toSendPort());
topLevel();
replyTo.send([_SPAWNED_SIGNAL, lazyPort.sendPort]);
if (!isSpawnUri) {
topLevel(message);
} else if (topLevel is _MainFunctionArgsMessage) {
topLevel(args, message);
} else if (topLevel is _MainFunctionArgs) {
topLevel(args);
} else {
topLevel();
}
}
/**
* Spawns an isolate in a worker. [factoryName] is the Javascript constructor
* name for the isolate entry point class.
*/
static void _spawnWorker(functionName, uri, replyPort) {
static void _spawnWorker(functionName, String uri,
List<String> args, message,
bool isSpawnUri,
SendPort replyPort) {
if (uri == null) uri = thisScript;
final worker = JS('var', 'new Worker(#)', uri);
@ -676,6 +691,9 @@ class IsolateNatives {
// the port (port deserialization is sensitive to what is the current
// workerId).
'replyTo': _serializeMessage(replyPort),
'args': args,
'msg': _serializeMessage(message),
'isSpawnUri': isSpawnUri,
'functionName': functionName }));
}
}
@ -700,22 +718,7 @@ class _BaseSendPort implements SendPort {
}
}
Future call(var message) {
final completer = new Completer();
final port = new ReceivePortImpl();
send(message, port.toSendPort());
port.receive((value, ignoreReplyTo) {
port.close();
if (value is Exception) {
completer.completeError(value);
} else {
completer.complete(value);
}
});
return completer.future;
}
void send(var message, [SendPort replyTo]);
void send(var message);
bool operator ==(var other);
int get hashCode;
}
@ -726,13 +729,12 @@ class _NativeJsSendPort extends _BaseSendPort implements SendPort {
const _NativeJsSendPort(this._receivePort, int isolateId) : super(isolateId);
void send(var message, [SendPort replyTo = null]) {
_waitForPendingPorts([message, replyTo], () {
_checkReplyTo(replyTo);
void send(var message, [SendPort replyTo]) {
_waitForPendingPorts(message, () {
// Check that the isolate still runs and the port is still open
final isolate = _globalState.isolates[_isolateId];
if (isolate == null) return;
if (_receivePort._callback == null) return;
if (_receivePort._controller.isClosed) return;
// We force serialization/deserialization as a simple way to ensure
// isolate communication restrictions are respected between isolates that
@ -744,18 +746,15 @@ class _NativeJsSendPort extends _BaseSendPort implements SendPort {
final shouldSerialize = _globalState.currentContext != null
&& _globalState.currentContext.id != _isolateId;
var msg = message;
var reply = replyTo;
if (shouldSerialize) {
msg = _serializeMessage(msg);
reply = _serializeMessage(reply);
}
_globalState.topEventLoop.enqueue(isolate, () {
if (_receivePort._callback != null) {
if (!_receivePort._controller.isClosed) {
if (shouldSerialize) {
msg = _deserializeMessage(msg);
reply = _deserializeMessage(reply);
}
_receivePort._callback(msg, reply);
_receivePort._controller.add(msg);
}
}, 'receive $message');
});
@ -776,14 +775,12 @@ class _WorkerSendPort extends _BaseSendPort implements SendPort {
const _WorkerSendPort(this._workerId, int isolateId, this._receivePortId)
: super(isolateId);
void send(var message, [SendPort replyTo = null]) {
_waitForPendingPorts([message, replyTo], () {
_checkReplyTo(replyTo);
void send(var message, [SendPort replyTo]) {
_waitForPendingPorts(message, () {
final workerMessage = _serializeMessage({
'command': 'message',
'port': this,
'msg': message,
'replyTo': replyTo});
'msg': message});
if (_globalState.isWorker) {
// Communication from one worker to another go through the
@ -838,7 +835,7 @@ class _BufferingSendPort extends _BaseSendPort implements SendPort {
_futurePort.then((p) {
_port = p;
for (final item in pending) {
p.send(item['message'], item['replyTo']);
p.send(item);
}
pending = null;
});
@ -853,7 +850,7 @@ class _BufferingSendPort extends _BaseSendPort implements SendPort {
if (_port != null) {
_port.send(message, replyTo);
} else {
pending.add({'message': message, 'replyTo': replyTo});
pending.add(message);
}
}
@ -863,26 +860,32 @@ class _BufferingSendPort extends _BaseSendPort implements SendPort {
}
/** Implementation of a multi-use [ReceivePort] on top of JavaScript. */
class ReceivePortImpl implements ReceivePort {
int _id;
Function _callback;
class ReceivePortImpl extends Stream implements ReceivePort {
static int _nextFreeId = 1;
final int _id;
StreamController _controller;
ReceivePortImpl()
: _id = _nextFreeId++ {
_controller = new StreamController(onCancel: close, sync: true);
_globalState.currentContext.register(_id, this);
}
void receive(void onMessage(var message, SendPort replyTo)) {
_callback = onMessage;
StreamSubscription listen(void onData(var event),
{Function onError,
void onDone(),
bool cancelOnError}) {
return _controller.stream.listen(onData, onError: onError, onDone: onDone,
cancelOnError: cancelOnError);
}
void close() {
_callback = null;
if (_controller.isClosed) return;
_controller.close();
_globalState.currentContext.unregister(_id);
}
SendPort toSendPort() {
SendPort get sendPort {
return new _NativeJsSendPort(this, _globalState.currentContext.id);
}
}
@ -908,9 +911,7 @@ class _PendingSendPortFinder extends _MessageTraverser {
final seen = _visited[list];
if (seen != null) return;
_visited[list] = true;
// TODO(sigmund): replace with the following: (bug #1660)
// list.forEach(_dispatch);
list.forEach((e) => _dispatch(e));
list.forEach(_dispatch);
}
visitMap(Map map) {
@ -918,9 +919,7 @@ class _PendingSendPortFinder extends _MessageTraverser {
if (seen != null) return;
_visited[map] = true;
// TODO(sigmund): replace with the following: (bug #1660)
// map.values.forEach(_dispatch);
map.values.forEach((e) => _dispatch(e));
map.values.forEach(_dispatch);
}
visitSendPort(var port) {
@ -928,14 +927,6 @@ class _PendingSendPortFinder extends _MessageTraverser {
ports.add(port._futurePort);
}
}
visitIsolateSink(JsIsolateSink sink) {
visitSendPort(sink._port);
}
visitCloseToken(CloseToken token) {
// Do nothing.
}
}
/********************************************************
@ -993,16 +984,6 @@ class _JsSerializer extends _Serializer {
" ports are resolved at this point.";
}
}
visitIsolateSink(JsIsolateSink sink) {
SendPort port = sink._port;
bool isClosed = sink._isClosed;
return ['isolateSink', visitSendPort(port), isClosed];
}
visitCloseToken(CloseToken token) {
return ['closeToken'];
}
}
@ -1036,18 +1017,6 @@ class _JsCopier extends _Copier {
" ports are resolved at this point.";
}
}
IsolateSink visitIsolateSink(JsIsolateSink sink) {
SendPort port = sink._port;
bool isClosed = sink._isClosed;
JsIsolateSink result = new JsIsolateSink.fromPort(visitSendPort(port));
result._isClosed = isClosed;
return result;
}
CloseToken visitCloseToken(CloseToken token) {
return token; // Can be shared.
}
}
class _JsDeserializer extends _Deserializer {
@ -1068,18 +1037,6 @@ class _JsDeserializer extends _Deserializer {
return new _WorkerSendPort(managerId, isolateId, receivePortId);
}
}
IsolateSink deserializeIsolateSink(List list) {
SendPort port = deserializeSendPort(list[1]);
bool isClosed = list[2];
JsIsolateSink result = new JsIsolateSink.fromPort(port);
result._isClosed = isClosed;
return result;
}
CloseToken deserializeCloseToken(List list) {
return const CloseToken();
}
}
class _JsVisitedMap implements _MessageTraverserVisitedMap {
@ -1177,8 +1134,6 @@ class _MessageTraverser {
if (x is Map) return visitMap(x);
if (x is SendPort) return visitSendPort(x);
if (x is SendPortSync) return visitSendPortSync(x);
if (x is JsIsolateSink) return visitIsolateSink(x);
if (x is CloseToken) return visitCloseToken(x);
// Overridable fallback.
return visitObject(x);
@ -1189,8 +1144,6 @@ class _MessageTraverser {
visitMap(Map x);
visitSendPort(SendPort x);
visitSendPortSync(SendPortSync x);
visitIsolateSink(IsolateSink x);
visitCloseToken(CloseToken x);
visitObject(Object x) {
// TODO(floitsch): make this a real exception. (which one)?
@ -1302,8 +1255,6 @@ class _Deserializer {
case 'list': return _deserializeList(x);
case 'map': return _deserializeMap(x);
case 'sendport': return deserializeSendPort(x);
case 'isolateSink': return deserializeIsolateSink(x);
case 'closeToken': return deserializeCloseToken(x);
default: return deserializeObject(x);
}
}
@ -1345,10 +1296,6 @@ class _Deserializer {
deserializeSendPort(List x);
deserializeIsolateSink(List x);
deserializeCloseToken(List x);
deserializeObject(List x) {
// TODO(floitsch): Use real exception (which one?).
throw "Unexpected serialized object";

View file

@ -10,31 +10,26 @@ import 'dart:_isolate_helper' show IsolateNatives,
CloseToken,
JsIsolateSink;
patch class _Isolate {
patch static ReceivePort get port {
if (lazyPort == null) {
lazyPort = new ReceivePort();
patch class Isolate {
patch static Future<Isolate> spawn(void entryPoint(message), var message) {
SendPort controlPort = IsolateNatives.spawnFunction(entryPoint, message);
return new Future<Isolate>.value(new Isolate._fromControlPort(controlPort));
}
patch static Future<Isolate> spawnUri(
Uri uri, List<String> args, var message) {
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");
}
return lazyPort;
SendPort controlPort = IsolateNatives.spawnUri(uri, args, message);
return new Future<Isolate>.value(new Isolate._fromControlPort(controlPort));
}
patch static SendPort spawnFunction(void topLevelFunction(),
[bool unhandledExceptionCallback(IsolateUnhandledException e)]) {
if (unhandledExceptionCallback != null) {
// TODO(9012): Implement the UnhandledExceptionCallback.
throw new UnimplementedError(
"spawnFunction with unhandledExceptionCallback");
}
return IsolateNatives.spawnFunction(topLevelFunction);
}
patch static SendPort spawnUri(String uri) {
return IsolateNatives.spawn(null, uri, false);
}
}
patch bool _isCloseToken(var object) {
return identical(object, const CloseToken());
}
/** Default factory for receive ports. */
@ -42,24 +37,14 @@ patch class ReceivePort {
patch factory ReceivePort() {
return new ReceivePortImpl();
}
patch factory ReceivePort.fromRawReceivePort(RawReceivePort rawPort) {
throw new UnimplementedError("ReceivePort.fromRawReceivePort");
}
}
patch class MessageBox {
patch MessageBox.oneShot() : this._oneShot(new ReceivePort());
MessageBox._oneShot(ReceivePort receivePort)
: stream = new IsolateStream._fromOriginalReceivePortOneShot(receivePort),
sink = new JsIsolateSink.fromPort(receivePort.toSendPort());
patch MessageBox() : this._(new ReceivePort());
MessageBox._(ReceivePort receivePort)
: stream = new IsolateStream._fromOriginalReceivePort(receivePort),
sink = new JsIsolateSink.fromPort(receivePort.toSendPort());
}
patch IsolateSink streamSpawnFunction(
void topLevelFunction(),
[bool unhandledExceptionCallback(IsolateUnhandledException e)]) {
SendPort sendPort = spawnFunction(topLevelFunction,
unhandledExceptionCallback);
return new JsIsolateSink.fromPort(sendPort);
patch class RawReceivePort {
patch factory RawReceivePort([void handler(event)]) {
throw new UnimplementedError("RawReceivePort");
}
}

View file

@ -32,9 +32,11 @@ import 'http://<<HOST_AND_PORT>>/packages/stack_trace/stack_trace.dart';
import 'http://<<HOST_AND_PORT>>/packages/barback/barback.dart';
/// Sets up the initial communication with the host isolate.
void main() {
port.receive((args, replyTo) {
_sendFuture(replyTo, new Future.sync(() {
void main(List<String> args, SendPort replyTo) {
var port = new ReceivePort();
replyTo.send(['success', port.sendPort]);
port.listen((args) {
_sendFuture(args['replyTo'], new Future.sync(() {
var library = Uri.parse(args['library']);
var configuration = JSON.decode(args['configuration']);
return initialize(library, configuration).
@ -112,10 +114,10 @@ class ForeignTransform implements Transform {
}
Future<Asset> getInput(AssetId id) {
return _receiveFuture(_port.call({
return _callAndReceiveFuture(_port, {
'type': 'getInput',
'id': _serializeId(id)
})).then(_deserializeAsset);
}).then(_deserializeAsset);
}
Future<String> readInputAsString(AssetId id, {Encoding encoding}) {
@ -181,7 +183,8 @@ Map _serializeTransformerOrGroup(transformerOrGroup) {
/// Converts [transformer] into a serializable map.
Map _serializeTransformer(Transformer transformer) {
var port = new ReceivePort();
port.receive((message, replyTo) {
port.listen((message) {
var replyTo = message['replyTo'];
_sendFuture(replyTo, new Future.sync(() {
if (message['type'] == 'isPrimary') {
return transformer.isPrimary(_deserializeAsset(message['asset']));
@ -196,7 +199,7 @@ Map _serializeTransformer(Transformer transformer) {
return {
'type': 'Transformer',
'toString': transformer.toString(),
'port': port.toSendPort()
'port': port.sendPort
};
}
@ -211,11 +214,29 @@ Map _serializeTransformerGroup(TransformerGroup group) {
};
}
/// When the input receives a 'done' as data-event, transforms it to a
/// done event and cancels the subscription.
StreamSubscription doneTransformer(Stream input, bool cancelOnError) {
var subscription;
var transformed = input.transform(new StreamTransformer.fromHandlers(
handleData: (data, sink) {
if (data == 'done') {
sink.close();
subscription.cancel();
} else {
sink.add(data);
}
}));
subscription = transformed.listen(null, cancelOnError: cancelOnError);
return subscription;
}
/// Converts a serializable map into an [Asset].
Asset _deserializeAsset(Map asset) {
var box = new MessageBox();
asset['sink'].add(box.sink);
return new Asset.fromStream(_deserializeId(asset['id']), box.stream);
var receivePort = new ReceivePort();
asset['sendPort'].send(receivePort.sendPort);
var stream = receivePort.transform(const StreamTransformer(doneTransformer));
return new Asset.fromStream(_deserializeId(asset['id']), stream);
}
/// Converts a serializable map into an [AssetId].
@ -225,16 +246,18 @@ AssetId _deserializeId(Map id) => new AssetId(id['package'], id['path']);
Map _serializeAsset(Asset asset) {
// We can't send IsolateStreams (issue 12437), so instead we send a sink and
// get the isolate to send us back another sink.
var box = new MessageBox();
box.stream.first.then((sink) {
asset.read().listen(sink.add,
onError: sink.addError,
onDone: sink.close);
var receivePort = new ReceivePort();
receivePort.first.then((sendPort) {
asset.read().listen(sendPort.send,
onError: (error, stackTrace) {
throw new UnimplementedError('Error during asset serialization');
},
onDone: () { sendPort.send('done'); });
});
return {
'id': _serializeId(asset.id),
'sink': box.sink
'sendPort': receivePort.sendPort
};
}
@ -280,11 +303,18 @@ void _sendFuture(SendPort port, Future future) {
/// Receives the result of [_sendFuture] from [portCall], which should be the
/// return value of [SendPort.call].
Future _receiveFuture(Future portCall) {
return portCall.then((response) {
if (response.containsKey('success')) return response['success'];
return new Future.error(
new CrossIsolateException.deserialize(response['error']));
///
/// The [message] argument is modified to include the [replyTo] port.
Future _callAndReceiveFuture(SendPort port, Map message) {
var responsePort = new ReceivePort();
message['replyTo'] = responsePort.sendPort;
return new Future.sync(() {
port.send(message);
return responsePort.first.then((response) {
if (response.containsKey('success')) return response['success'];
return new Future.error(
new CrossIsolateException.deserialize(response['error']));
});
});
}
@ -379,11 +409,11 @@ Future<Set> loadTransformers(BarbackServer server, TransformerId id) {
log.fine("Loading transformers from $assetId");
return dart.runInIsolate(code).then((sendPort) {
return _receiveFuture(sendPort.call({
return _callAndReceiveFuture(sendPort, {
'library': uri,
// TODO(nweiz): support non-JSON-encodable configuration maps.
'configuration': JSON.encode(id.configuration)
})).then((transformers) {
}).then((transformers) {
transformers = transformers.map(_deserializeTransformerOrGroup).toSet();
log.fine("Transformers from $assetId: $transformers");
return transformers;
@ -422,17 +452,17 @@ class _ForeignTransformer extends Transformer {
_toString = map['toString'];
Future<bool> isPrimary(Asset asset) {
return _receiveFuture(_port.call({
return _callAndReceiveFuture(_port, {
'type': 'isPrimary',
'asset': _serializeAsset(asset)
}));
});
}
Future apply(Transform transform) {
return _receiveFuture(_port.call({
return _callAndReceiveFuture(_port, {
'type': 'apply',
'transform': _serializeTransform(transform)
}));
});
}
String toString() => _toString;
@ -464,7 +494,8 @@ _deserializeTransformerOrGroup(Map map) {
/// Converts [transform] into a serializable map.
Map _serializeTransform(Transform transform) {
var receivePort = new ReceivePort();
receivePort.receive((message, replyTo) {
receivePort.listen((message) {
var replyTo = message['replyTo'];
if (message['type'] == 'getInput') {
_sendFuture(replyTo, transform.getInput(_deserializeId(message['id']))
.then(_serializeAsset));
@ -492,16 +523,34 @@ Map _serializeTransform(Transform transform) {
});
return {
'port': receivePort.toSendPort(),
'port': receivePort.sendPort,
'primaryInput': _serializeAsset(transform.primaryInput)
};
}
/// When the input receives a 'done' as data-event, transforms it to a
/// done event and cancels the subscription.
StreamSubscription doneTransformer(Stream input, bool cancelOnError) {
var subscription;
var transformed = input.transform(new StreamTransformer.fromHandlers(
handleData: (data, sink) {
if (data == 'done') {
sink.close();
subscription.cancel();
} else {
sink.add(data);
}
}));
subscription = transformed.listen(null, cancelOnError: cancelOnError);
return subscription;
}
/// Converts a serializable map into an [Asset].
Asset _deserializeAsset(Map asset) {
var box = new MessageBox();
asset['sink'].add(box.sink);
return new Asset.fromStream(_deserializeId(asset['id']), box.stream);
var receivePort = new ReceivePort();
asset['sendPort'].send(receivePort.sendPort);
var stream = receivePort.transform(const StreamTransformer(doneTransformer));
return new Asset.fromStream(_deserializeId(asset['id']), stream);
}
/// Converts a serializable map into an [AssetId].
@ -528,16 +577,18 @@ Location _deserializeLocation(Map location) {
Map _serializeAsset(Asset asset) {
// We can't send IsolateStreams (issue 12437), so instead we send a sink and
// get the isolate to send us back another sink.
var box = new MessageBox();
box.stream.first.then((sink) {
asset.read().listen(sink.add,
onError: sink.addError,
onDone: sink.close);
var receivePort = new ReceivePort();
receivePort.first.then((sendPort) {
asset.read().listen(sendPort.send,
onError: (error, stackTrace) {
throw new UnimplementedError('Error during asset serialization');
},
onDone: () { sendPort.send('done'); });
});
return {
'id': _serializeId(asset.id),
'sink': box.sink
'sendPort': receivePort.sendPort
};
}
@ -546,7 +597,7 @@ Map _serializeId(AssetId id) => {'package': id.package, 'path': id.path};
/// Sends the result of [future] through [port].
///
/// This should be received on the other end using [_receiveFuture]. It
/// This should be received on the other end using [_callAndReceiveFuture]. It
/// re-raises any exceptions on the other side as [dart.CrossIsolateException]s.
void _sendFuture(SendPort port, Future future) {
future.then((result) {
@ -559,10 +610,17 @@ void _sendFuture(SendPort port, Future future) {
/// Receives the result of [_sendFuture] from [portCall], which should be the
/// return value of [SendPort.call].
Future _receiveFuture(Future portCall) {
return portCall.then((response) {
if (response.containsKey('success')) return response['success'];
return new Future.error(
new dart.CrossIsolateException.deserialize(response['error']));
///
/// The [message] argument is modified to include the [replyTo] port.
Future _callAndReceiveFuture(SendPort port, Map message) {
var responsePort = new ReceivePort();
message['replyTo'] = responsePort.sendPort;
return new Future.sync(() {
port.send(message);
return responsePort.first.then((response) {
if (response.containsKey('success')) return response['success'];
return new Future.error(
new dart.CrossIsolateException.deserialize(response['error']));
});
});
}

View file

@ -92,14 +92,18 @@ Future<SendPort> runInIsolate(String code) {
return withTempDir((dir) {
var dartPath = path.join(dir, 'runInIsolate.dart');
writeTextFile(dartPath, code, dontLogContents: true);
var bufferPort = spawnFunction(_isolateBuffer);
return bufferPort.call(path.toUri(dartPath).toString()).then((response) {
if (response.first == 'error') {
return new Future.error(
new CrossIsolateException.deserialize(response.last));
}
var port = new ReceivePort();
var initialMessage = [path.toUri(dartPath).toString(), port.sendPort];
var isolate = Isolate.spawn(_isolateBuffer, initialMessage);
return isolate.then((_) {
return port.first.then((response) {
if (response.first == 'error') {
return new Future.error(
new CrossIsolateException.deserialize(response.last));
}
return response.last;
return response.last;
});
});
});
}
@ -110,14 +114,18 @@ Future<SendPort> runInIsolate(String code) {
/// [spawnUri] synchronously loads the file and its imports, which can deadlock
/// the host isolate if there's an HTTP import pointing at a server in the host.
/// Adding an additional isolate in the middle works around this.
void _isolateBuffer() {
port.receive((uri, replyTo) {
try {
replyTo.send(['success', spawnUri(uri)]);
} catch (e, stack) {
void _isolateBuffer(initialMessage) {
var uri = initialMessage[0];
var replyTo = initialMessage[1];
try {
// TODO(floitsch): If we do it right we shouldn't need to have a try/catch
// and a catchError.
Isolate.spawnUri(Uri.parse(uri), [], replyTo).catchError((e, stack) {
replyTo.send(['error', CrossIsolateException.serialize(e, stack)]);
}
});
});
} catch (e, stack) {
replyTo.send(['error', CrossIsolateException.serialize(e, stack)]);
}
}
/// An exception that was originally raised in another isolate.

View file

@ -26,7 +26,6 @@ main() {
]).create();
createLockFile('myapp', pkg: ['barback']);
var pub = startPub(args: ['serve', '--port=0', "--hostname=127.0.0.1"]);
expect(pub.nextErrLine(), completion(matches(new RegExp(
r"Error: line 1 pos 1: library handler failed$"))));

View file

@ -701,16 +701,18 @@ class _CustomizedZone extends _BaseZone {
void _rootHandleUncaughtError(
Zone self, ZoneDelegate parent, Zone zone, error, StackTrace stackTrace) {
_scheduleAsyncCallback(() {
print("Uncaught Error: ${error}");
var trace = stackTrace;
if (trace == null) trace = getAttachedStackTrace(error);
// Clear the attached stack trace (if any).
_attachStackTrace(error, null);
if (trace != null) {
print("Stack Trace: \n$trace\n");
}
throw error;
self.run(() {
_scheduleAsyncCallback(() {
print("Uncaught Error: ${error}");
var trace = stackTrace;
if (trace == null) trace = getAttachedStackTrace(error);
// Clear the attached stack trace (if any).
_attachStackTrace(error, null);
if (trace != null) {
print("Stack Trace: \n$trace\n");
}
throw error;
});
});
}

View file

@ -29269,6 +29269,8 @@ class _JsDeserializer extends _Deserializer {
}
}
class SendPortSync {}
// The receiver is JS.
class _JsSendPortSync implements SendPortSync {

View file

@ -25599,13 +25599,13 @@ class Url extends NativeFieldWrapperClass2 {
if ((blob_OR_source_OR_stream is Blob || blob_OR_source_OR_stream == null)) {
return _createObjectURL_1(blob_OR_source_OR_stream);
}
if ((blob_OR_source_OR_stream is MediaSource || blob_OR_source_OR_stream == null)) {
if ((blob_OR_source_OR_stream is MediaStream || blob_OR_source_OR_stream == null)) {
return _createObjectURL_2(blob_OR_source_OR_stream);
}
if ((blob_OR_source_OR_stream is _WebKitMediaSource || blob_OR_source_OR_stream == null)) {
if ((blob_OR_source_OR_stream is MediaSource || blob_OR_source_OR_stream == null)) {
return _createObjectURL_3(blob_OR_source_OR_stream);
}
if ((blob_OR_source_OR_stream is MediaStream || blob_OR_source_OR_stream == null)) {
if ((blob_OR_source_OR_stream is _WebKitMediaSource || blob_OR_source_OR_stream == null)) {
return _createObjectURL_4(blob_OR_source_OR_stream);
}
throw new ArgumentError("Incorrect number or type of arguments");
@ -31209,6 +31209,8 @@ class _JsDeserializer extends _Deserializer {
}
}
class SendPortSync {}
// The receiver is JS.
class _JsSendPortSync implements SendPortSync {

View file

@ -6,6 +6,6 @@ part of dart.io;
class _EventHandler {
external static void _sendData(Object sender,
ReceivePort receivePort,
RawReceivePort receivePort,
int data);
}

View file

@ -11,7 +11,7 @@ class _Timer extends LinkedListEntry<_Timer> implements Timer {
// Timers are ordered by wakeup time.
static LinkedList<_Timer> _timers = new LinkedList<_Timer>();
static ReceivePort _receivePort;
static RawReceivePort _receivePort;
static bool _handling_callbacks = false;
Function _callback;
@ -163,10 +163,7 @@ class _Timer extends LinkedListEntry<_Timer> implements Timer {
}
if(_receivePort == null) {
_receivePort = new ReceivePort();
_receivePort.receive((var message, ignored) {
_handleTimeout();
});
_receivePort = new RawReceivePort((_) { _handleTimeout(); });
}
}

View file

@ -15,62 +15,67 @@
library dart.isolate;
import "dart:async";
import "dart:collection" show HashMap;
part "isolate_stream.dart";
/**
* Thrown when an isolate cannot be created.
*/
class IsolateSpawnException implements Exception {
// TODO(floitsch): clean up spawn exception.
const IsolateSpawnException(String this._s);
String toString() => "IsolateSpawnException: '$_s'";
final String _s;
}
/**
* The initial ReceivePort available by default for this isolate.
*
* This ReceivePort is created automatically
* and is commonly used to establish
* the first communication between isolates.
* (See [spawnFunction] and [spawnUri].)
*/
ReceivePort get port => _Isolate.port;
class Isolate {
final SendPort _controlPort;
Isolate._fromControlPort(SendPort controlPort)
: this._controlPort = controlPort;
/**
* Creates and spawns an isolate that shares the same code as the current
* isolate.
*
* The argument [entryPoint] specifies the entry point of the spawned
* isolate. It must be a static top-level function or a static method that
* takes no arguments. It is not allowed to pass a function closure.
*
* The entry-point function is invoked with the initial [message].
* Usually the initial [message] contains a [SendPort] so
* that the spawner and spawnee can communicate with each other.
*
* Returns a future that will complete with an [Isolate] instance. The
* isolate instance can be used to control the spawned isolate.
*/
external static Future<Isolate> spawn(void entryPoint(message), var message);
/**
* Creates and spawns an isolate that runs the code from the library with
* the specified URI.
*
* The isolate starts executing the top-level `main` function of the library
* with the given URI.
*
* The target `main` may have one of the four following signatures:
*
* * `main()`
* * `main(args)`
* * `main(args, message)`
*
* When present, the argument `message` is set to the initial [message].
* When present, the argument `args` is set to the provided [args] list.
*
* Returns a future that will complete with an [Isolate] instance. The
* isolate instance can be used to control the spawned isolate.
*/
external static Future<Isolate> spawnUri(
Uri uri, List<String> args, var message);
}
/**
* Creates and spawns an isolate
* that shares the same code as the current isolate,
* but that starts from the specified function.
*
* The [topLevelFunction] argument must be
* a static top-level function or a static method that takes no
* arguments. It is illegal to pass a function closure.
*
* When any isolate starts (even the main script of the application), a default
* [ReceivePort] is created for it. This port is available from the top-level
* getter [port] defined in this library.
*
* This function returns a [SendPort] derived from
* the child isolate's default port.
*
* The optional [unhandledExceptionCallback] argument is invoked whenever an
* exception inside the isolate is unhandled. It can be seen as a big
* `try/catch` around everything that is executed inside the isolate. The
* callback should return `true` if it was able to handle the exception.
*/
SendPort spawnFunction(void topLevelFunction(),
[bool unhandledExceptionCallback(IsolateUnhandledException e)])
=> _Isolate.spawnFunction(topLevelFunction, unhandledExceptionCallback);
/**
* Creates and spawns an isolate that runs the code from the specified URI.
*
* As with [spawnFunction],
* the child isolate has a default [ReceivePort],
* and this function returns a [SendPort] derived from it.
*/
SendPort spawnUri(String uri) => _Isolate.spawnUri(uri);
/**
* Together with [ReceivePort],
* the only means of communication between isolates.
* Sends messages to its [ReceivePort]s.
*
* [SendPort]s are created from [ReceivePort]s. Any message sent through
* a [SendPort] is delivered to its respective [ReceivePort]. There might be
@ -82,8 +87,7 @@ abstract class SendPort {
/**
* Sends an asynchronous [message] to this send port. The message is copied to
* the receiving isolate. If specified, the [replyTo] port will be provided to
* the receiver to facilitate exchanging sequences of messages.
* the receiving isolate.
*
* The content of [message] can be: primitive values (null, num, bool, double,
* String), instances of [SendPort], and lists and maps whose elements are any
@ -95,21 +99,10 @@ abstract class SendPort {
* process). This is currently only supported by the dartvm. For now, the
* dart2js compiler only supports the restricted messages described above.
*
* Deprecation note: it is no longer valid to transmit a [ReceivePort] in a
* message. Previously they were translated to the corresponding send port
* before being transmitted.
* The second argument [replyTo] is deprecated and its value is ignored.
*/
void send(var message, [SendPort replyTo]);
/**
* Sends a message to this send port and returns a [Future] of the reply.
* Basically, this internally creates a new receive port, sends a
* message to this send port with replyTo set to such receive port, and, when
* a reply is received, it closes the receive port and completes the returned
* future.
*/
Future call(var message);
/**
* Tests whether [other] is a [SendPort] pointing to the same
* [ReceivePort] as this one.
@ -121,49 +114,95 @@ abstract class SendPort {
* consistent with the == operator.
*/
int get hashCode;
}
/**
* Together with [SendPort], the only means of
* communication between isolates.
* Together with [SendPort], the only means of communication between isolates.
*
* [ReceivePort]s have a [:toSendPort:] method
* which returns a [SendPort]. Any message that is sent through this [SendPort]
* is delivered to the [ReceivePort] it has been created from. There, they are
* dispatched to the callback that has been registered on the receive port.
* [ReceivePort]s have a `sendport` getter which returns a [SendPort].
* Any message that is sent through this [SendPort]
* is delivered to the [ReceivePort] it has been created from. There, the
* message is dispatched to its listener.
*
* A [ReceivePort] is a non-broadcast stream. This means that it buffers
* incoming messages until a listener is registered. Only one listener can
* receive messages. See [Stream.asBroadcastStream] for transforming the port
* to a broadcast stream.
*
* A [ReceivePort] may have many [SendPort]s.
*/
abstract class ReceivePort {
abstract class ReceivePort implements Stream {
/**
* Opens a long-lived port for receiving messages. The returned port
* must be explicitly closed through [ReceivePort.close].
* Opens a long-lived port for receiving messages.
*
* A [ReceivePort] is a non-broadcast stream. This means that it buffers
* incoming messages until a listener is registered. Only one listener can
* receive messages. See [Stream.asBroadcastStream] for transforming the port
* to a broadcast stream.
*
* A receive port is closed by canceling its subscription.
*/
external factory ReceivePort();
/**
* Sets up a callback function for receiving pending or future
* messages on this receive port.
* Creates a [ReceivePort] from a [RawReceivePort].
*
* The handler of the given [rawPort] is overwritten during the construction
* of the result.
*/
void receive(void callback(var message, SendPort replyTo));
external factory ReceivePort.fromRawReceivePort(RawReceivePort rawPort);
/**
* Closes this receive port immediately. Pending messages will not
* be processed and it is impossible to re-open the port. Single-shot
* reply ports, such as those created through [SendPort.call], are
* automatically closed when the reply has been received. Multiple
* invocations of [close] are allowed but ignored.
* Inherited from [Stream].
*
* Note that all named arguments are ignored since a ReceivePort will never
* receive an error, or done message.
*/
StreamSubscription listen(void onData(var message),
{ Function onError,
void onDone(),
bool cancelOnError });
/**
* Closes `this`.
*
* If the stream has not been canceled yet, adds a close-event to the event
* queue and discards any further incoming messages.
*
* If the stream has already been canceled this method has no effect.
*/
void close();
/**
* Creates a new send port that sends to this receive port. It is legal to
* create several [SendPort]s from the same [ReceivePort].
* Returns a send port that sends to this receive port.
*/
SendPort toSendPort();
SendPort get sendPort;
}
abstract class RawReceivePort {
/**
* Opens a long-lived port for receiving messages.
*
* A [RawReceivePort] is low level and does not work with [Zone]s. It
* can not be paused. The data-handler must be set before the first
* event is received.
*/
external factory RawReceivePort([void handler(event)]);
/**
* Sets the handler that is invoked for every incoming message.
*
* The handler is invoked in the root-zone ([Zone.ROOT]).
*/
void set handler(Function newHandler);
/**
* Closes the port.
*
* After a call to this method any incoming message is silently dropped.
*/
void close();
}
/**
@ -172,7 +211,10 @@ abstract class ReceivePort {
* might be many [SendPortSync]s for the same [ReceivePortSync].
*
* [SendPortSync]s can be transmitted to other isolates.
*
* *DEPRECATED*.
*/
@deprecated
abstract class SendPortSync {
/**
* Sends a synchronous message to this send port and returns the result.
@ -192,22 +234,13 @@ abstract class SendPortSync {
int get hashCode;
}
// The VM doesn't support accessing external globals in the same library. We
// therefore create this wrapper class.
// TODO(6997): Don't go through static class for external variables.
abstract class _Isolate {
external static ReceivePort get port;
external static SendPort spawnFunction(void topLevelFunction(),
[bool unhandledExceptionCallback(IsolateUnhandledException e)]);
external static SendPort spawnUri(String uri);
}
/**
* Wraps unhandled exceptions thrown during isolate execution. It is
* used to show both the error message and the stack trace for unhandled
* exceptions.
*/
class IsolateUnhandledException implements Exception {
// TODO(floitsch): probably going to remove and replace with something else.
class _IsolateUnhandledException implements Exception {
/** Message being handled when exception occurred. */
final message;
@ -217,7 +250,7 @@ class IsolateUnhandledException implements Exception {
/** Trace for the wrapped exception. */
final Object stackTrace;
const IsolateUnhandledException(this.message, this.source, this.stackTrace);
const _IsolateUnhandledException(this.message, this.source, this.stackTrace);
String toString() {
return 'IsolateUnhandledException: exception while handling message: '

View file

@ -6,6 +6,5 @@
'sources': [
'isolate.dart',
# The above file needs to be first as it lists the parts below.
'isolate_stream.dart',
],
}

View file

@ -1,156 +0,0 @@
// 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.
part of dart.isolate;
/**
* The initial IsolateStream available by default for this isolate.
*
* This IsolateStream is created automatically and is commonly used
* to establish the first communication between isolates.
* (See [streamSpawnFunction].)
*/
final IsolateStream stream = new IsolateStream._fromOriginalReceivePort(port);
/**
* The creator of the [IsolateStream] and [IsolateSink]
* that allow an isolate to exchange messages with other isolates.
*
* Any message that is written into the [sink] (independent of the isolate) is
* sent to the [stream] where its subscribers can react to the messages.
*/
class MessageBox {
final IsolateStream stream;
final IsolateSink sink;
external MessageBox.oneShot();
external MessageBox();
}
external bool _isCloseToken(var object);
/**
* Together with [IsolateSink], the only means of
* communication between isolates.
*
* Each IsolateStream has a corresponding
* [IsolateSink]. Any message written into that sink will be delivered to
* the stream and then dispatched to the stream's subscribers.
*/
class IsolateStream extends Stream<dynamic> {
bool _isClosed = false;
final ReceivePort _port;
StreamController _controller = new StreamController(sync: true);
IsolateStream._fromOriginalReceivePort(this._port) {
_port.receive((message, replyTo) {
assert(replyTo == null);
_add(message);
});
}
IsolateStream._fromOriginalReceivePortOneShot(this._port) {
_port.receive((message, replyTo) {
assert(replyTo == null);
_add(message);
close();
});
}
void _add(var message) {
if (_isCloseToken(message)) {
close();
} else {
_controller.sink.add(message);
}
}
/**
* Closes the stream from the receiving end.
*
* Closing an already closed port has no effect.
*/
void close() {
if (!_isClosed) {
_isClosed = true;
_port.close();
_controller.close();
}
}
StreamSubscription listen(void onData(event),
{ void onError(error),
void onDone(),
bool cancelOnError}) {
return _controller.stream.listen(onData,
onError: onError,
onDone: onDone,
cancelOnError: cancelOnError);
}
}
/**
* The feed for an [IsolateStream].
*
* Any message written to [this] is delivered
* to its respective [IsolateStream].
* [IsolateSink]s are created by [MessageBox]es.
*
* [IsolateSink]s can be transmitted to other isolates.
*/
abstract class IsolateSink extends EventSink<dynamic> {
// TODO(floitsch): Actually it should be a StreamSink (being able to flow-
// control).
/**
* Sends an asynchronous [message] to the linked [IsolateStream];
* the message is copied to the receiving isolate.
*
* The content of [message] can be: primitive values (null, num, bool, double,
* String), instances of [IsolateSink]s, and lists and maps whose elements are
* any of these. List and maps are also allowed to be cyclic.
*
* In the special circumstances when two isolates share the same code and are
* running in the same process (e.g. isolates created via [spawnFunction]), it
* is also possible to send object instances (which would be copied in the
* process). This is currently only supported by the dartvm. For now, the
* dart2js compiler only supports the restricted messages described above.
*/
void add(dynamic message);
void addError(errorEvent);
/** Closing multiple times is allowed. */
void close();
/**
* Tests whether [other] is an [IsolateSink] feeding into the same
* [IsolateStream] as this one.
*/
bool operator==(var other);
}
/**
* Creates and spawns an isolate that shares the same code as the current
* isolate, but that starts from the specified function.
*
* The [topLevelFunction] argument must be
* a static top-level function or a static method that takes no arguments.
*
* When any isolate starts (even the main script of the application), a default
* [IsolateStream] is created for it. This sink is available from the top-level
* getter [stream] defined in this library.
*
* [spawnFunction] returns an [IsolateSink] feeding into the child isolate's
* default stream.
*
* The optional [unhandledExceptionCallback] argument is invoked whenever an
* exception inside the isolate is unhandled. It can be seen as a big
* `try/catch` around everything that is executed inside the isolate. The
* callback should return `true` if it was able to handle the exception.
*/
external IsolateSink streamSpawnFunction(
void topLevelFunction(),
[bool unhandledExceptionCallback(IsolateUnhandledException e)]);

View file

@ -146,6 +146,80 @@ LibTest/async/StreamEventTransformer/handleData_A01_t01: Fail
LibTest/async/StreamEventTransformer/handleDone_A01_t01: Fail
LibTest/async/StreamEventTransformer/handleError_A01_t01: Fail
# co19 issue TODO(floitsch).
Language/12_Expressions/12_Spawning_an_Isolate_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateSink/add_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateSink/add_A01_t02: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateSink/add_A02_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateSink/close_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateSink/close_A01_t02: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateSink/close_A01_t03: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateSink/close_A01_t04: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateSink/operator_equality_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateStream/any_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateStream/asBroadcastStream_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateStream/contains_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateStream/first_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateStream/first_A02_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateStream/first_A02_t02: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateStream/isBroadcast_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateStream/isBroadcast_A01_t02: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateStream/isEmpty_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateStream/last_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateStream/last_A02_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateStream/length_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateStream/single_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateStream/single_A02_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/ReceivePort/close_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/ReceivePort/close_A02_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/ReceivePort/receive_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/ReceivePort/receive_A01_t03: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/ReceivePort/toSendPort_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/ReceivePort/toSendPort_A01_t03: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/SendPort/call_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/SendPort/hashCode_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/SendPort/operator_equality_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/SendPort/send_A01_t01: Pass
LibTest/isolate/SendPort/send_A02_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/SendPort/send_A02_t04: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/SendPort/send_A02_t05: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/SendPort/send_A02_t06: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/SendPort/send_A03_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/SendPort/send_A03_t02: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/spawnFunction_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/spawnFunction_A01_t02: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/spawnFunction_A01_t03: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/spawnFunction_A01_t04: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/spawnFunction_A01_t05: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/spawnFunction_A02_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/spawnFunction_A03_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/spawnFunction_A04_t02: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/spawnFunction_A04_t03: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/spawnUri_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/spawnUri_A01_t02: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/spawnUri_A01_t03: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/spawnUri_A01_t04: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/spawnUri_A01_t05: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/streamSpawnFunction_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/stream_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/port_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateSink/addError_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateSink/addError_A01_t02: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateStream/any_A02_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateStream/contains_A02_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/ReceivePort/receive_A01_t02: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/ReceivePort/toSendPort_A01_t02: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/SendPort/send_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/SendPort/send_A02_t02: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/SendPort/send_A02_t03: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/spawnFunction_A02_t02: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/spawnFunction_A04_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/spawnUri_A02_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/spawnUri_A02_t02: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/spawnUri_A02_t03: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/streamSpawnFunction_A02_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/streamSpawnFunction_A02_t02: Fail # Co19 issue TODO(floitsch)
#co19 issue 631
Language/12_Expressions/30_Identifier_Reference_A02_t01: Fail
Language/13_Statements/03_Variable_Declaration_A01_t09: Fail

View file

@ -217,6 +217,64 @@ LibTest/async/StreamEventTransformer/handleData_A01_t01: Fail # co19 issue 626
LibTest/async/StreamEventTransformer/handleDone_A01_t01: Fail # co19 issue 626
LibTest/async/StreamEventTransformer/handleError_A01_t01: Fail # co19 issue 626
Language/12_Expressions/12_Spawning_an_Isolate_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateSink/add_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateSink/add_A01_t02: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateSink/add_A02_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateSink/close_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateSink/close_A01_t02: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateSink/close_A01_t03: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateSink/close_A01_t04: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateSink/operator_equality_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateStream/any_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateStream/asBroadcastStream_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateStream/contains_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateStream/first_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateStream/first_A02_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateStream/first_A02_t02: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateStream/isBroadcast_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateStream/isBroadcast_A01_t02: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateStream/isEmpty_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateStream/last_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateStream/last_A02_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateStream/length_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateStream/single_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/IsolateStream/single_A02_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/ReceivePort/close_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/ReceivePort/close_A02_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/ReceivePort/receive_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/ReceivePort/receive_A01_t03: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/ReceivePort/toSendPort_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/ReceivePort/toSendPort_A01_t03: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/SendPort/call_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/SendPort/hashCode_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/SendPort/operator_equality_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/SendPort/send_A01_t01: Pass
LibTest/isolate/SendPort/send_A02_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/SendPort/send_A02_t04: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/SendPort/send_A02_t05: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/SendPort/send_A02_t06: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/SendPort/send_A03_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/SendPort/send_A03_t02: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/spawnFunction_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/spawnFunction_A01_t02: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/spawnFunction_A01_t03: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/spawnFunction_A01_t04: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/spawnFunction_A01_t05: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/spawnFunction_A02_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/spawnFunction_A03_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/spawnFunction_A04_t02: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/spawnFunction_A04_t03: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/spawnUri_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/spawnUri_A01_t02: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/spawnUri_A01_t03: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/spawnUri_A01_t04: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/spawnUri_A01_t05: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/streamSpawnFunction_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/stream_A01_t01: Fail # Co19 issue TODO(floitsch)
LibTest/isolate/isolate_api/port_A01_t01: Fail # Co19 issue TODO(floitsch)
Language/14_Libraries_and_Scripts/4_Scripts_A03_t03: MissingRuntimeError, OK # co19 issue 638
### CHECKED MODE FAILURES ###

View file

@ -3,7 +3,6 @@
# BSD-style license that can be found in the LICENSE file.
[ $compiler == dart2js && $runtime == jsshell ]
LibTest/isolate/isolate_api/spawnUri_A02_t01: Crash # TODO(ahe): Please triage this crash.
LibTest/core/List/sort_A01_t04: Fail, Pass, Timeout # Must be a bug in jsshell, test sometimes times out.
LibTest/core/RegExp/Pattern_semantics/splitQueryString_A02_t01: RuntimeError # co19-roll r607: Please triage this failure
@ -139,7 +138,6 @@ LibTest/core/int/isEven_A01_t01: RuntimeError, OK # co19 issue 277
LibTest/isolate/IsolateSink/add_A01_t01: CompileTimeError # Issue 13683
LibTest/isolate/SendPort/send_A02_t01: CompileTimeError # Issue 13683
LibTest/isolate/isolate_api/spawnUri_A02_t01: RuntimeError # Runtime error: Expect.throws() fails
LibTest/isolate/isolate_api/spawnUri_A01_t01: RuntimeError # Runtime error: UnsupportedError: Currently spawnUri is not supported without web workers.
LibTest/isolate/isolate_api/spawnUri_A01_t02: RuntimeError # Runtime error: UnsupportedError: Currently spawnUri is not supported without web workers.
LibTest/isolate/isolate_api/spawnUri_A01_t03: RuntimeError # Runtime error: UnsupportedError: Currently spawnUri is not supported without web workers.

View file

@ -64,7 +64,6 @@ LibTest/core/Symbol/Symbol_A01_t05: RuntimeError # co19-roll r607: Please triage
LibTest/typed_data/Float32x4/clamp_A01_t01: Pass, Fail # Issue 13106
[ $compiler == none && $runtime == vm ]
Language/14_Libraries_and_Scripts/4_Scripts_A03_t03: MissingRuntimeError, OK # co19 issue
LibTest/typed_data/Float32x4/reciprocalSqrt_A01_t01: Pass, Fail # Issue 13398
LibTest/typed_data/Float32x4/reciprocal_A01_t01: Pass, Fail # Issue 13398

View file

@ -10,11 +10,13 @@
library isolate2_negative_test;
import 'dart:isolate';
void entry() {
throw "foo";
void entry(SendPort replyTo) {
throw "foo"; /// 01: runtime error
replyTo.send("done");
}
main() {
SendPort port = spawnFunction(entry);
port.receive((msg) {});
var port = new ReceivePort();
Isolate.spawn(entry, port.sendPort);
port.first;
}

View file

@ -7,61 +7,61 @@ import 'dart:async';
import 'dart:isolate';
import 'dart:html';
oneshotTimerIsolate() {
port.receive((msg, replyTo) {
expect(msg, 'START');
new Timer(const Duration(milliseconds: 10), () {
oneshotTimerIsolate(message) {
var command = message[0];
var replyTo = message[1];
expect(command, 'START');
new Timer(const Duration(milliseconds: 10), () {
replyTo.send('DONE');
});
}
periodicTimerIsolate(message) {
var command = message[0];
var replyTo = message[1];
expect(command, 'START');
int counter = 0;
new Timer.periodic(const Duration(milliseconds: 10), (timer) {
if (counter == 3) {
counter = 1024;
timer.cancel();
// Wait some more time to be sure callback won't be invoked any
// more.
new Timer(const Duration(milliseconds: 30), () {
replyTo.send('DONE');
});
return;
}
assert(counter < 3);
counter++;
});
}
cancellingIsolate(message) {
var command = message[0];
var replyTo = message[1];
expect(command, 'START');
bool shot = false;
var oneshot;
var periodic;
periodic = new Timer.periodic(const Duration(milliseconds: 10), (timer) {
expect(shot, isFalse);
shot = true;
expect(timer, same(periodic));
periodic.cancel();
oneshot.cancel();
// Wait some more time to be sure callbacks won't be invoked any
// more.
new Timer(const Duration(milliseconds: 50), () {
replyTo.send('DONE');
});
});
}
periodicTimerIsolate() {
port.receive((msg, replyTo) {
expect(msg, 'START');
int counter = 0;
new Timer.periodic(const Duration(milliseconds: 10), (timer) {
if (counter == 3) {
counter = 1024;
timer.cancel();
// Wait some more time to be sure callback won't be invoked any
// more.
new Timer(const Duration(milliseconds: 30), () {
replyTo.send('DONE');
});
return;
}
assert(counter < 3);
counter++;
});
});
}
cancellingIsolate() {
port.receive((msg, replyTo) {
expect(msg, 'START');
bool shot = false;
var oneshot;
var periodic;
periodic = new Timer.periodic(const Duration(milliseconds: 10), (timer) {
expect(shot, isFalse);
shot = true;
expect(timer, same(periodic));
periodic.cancel();
oneshot.cancel();
// Wait some more time to be sure callbacks won't be invoked any
// more.
new Timer(const Duration(milliseconds: 50), () {
replyTo.send('DONE');
});
});
// We launch the oneshot timer after the periodic timer. Otherwise a
// (very long) context switch could make this test flaky: assume the
// oneshot timer is created first and then there is a 30ms context switch.
// when the periodic timer is scheduled it would execute after the oneshot.
oneshot = new Timer(const Duration(milliseconds: 30), () {
fail('Should never be invoked');
});
// We launch the oneshot timer after the periodic timer. Otherwise a
// (very long) context switch could make this test flaky: assume the
// oneshot timer is created first and then there is a 30ms context switch.
// when the periodic timer is scheduled it would execute after the oneshot.
oneshot = new Timer(const Duration(milliseconds: 30), () {
fail('Should never be invoked');
});
}
@ -69,15 +69,21 @@ main() {
useHtmlConfiguration();
test('one shot timer in pure isolate', () {
expect(spawnFunction(oneshotTimerIsolate).call('START'),
completion('DONE'));
var response = new ReceivePort();
var remote = Isolate.spawn(oneshotTimerIsolate,
['START', response.sendPort]);
expect(remote.then((_) => response.first), completion('DONE'));
});
test('periodic timer in pure isolate', () {
expect(spawnFunction(periodicTimerIsolate).call('START'),
completion('DONE'));
var response = new ReceivePort();
var remote = Isolate.spawn(periodicTimerIsolate,
['START', response.sendPort]);
expect(remote.then((_) => response.first), completion('DONE'));
});
test('cancellation in pure isolate', () {
expect(spawnFunction(cancellingIsolate).call('START'),
completion('DONE'));
var response = new ReceivePort();
var remote = Isolate.spawn(cancellingIsolate,
['START', response.sendPort]);
expect(remote.then((_) => response.first), completion('DONE'));
});
}

View file

@ -7,7 +7,10 @@ import 'dart:isolate' as isolate;
String responseFor(message) => 'response for $message';
void isolateEntry() {
void isolateEntry(isolate.SendPort initialReplyTo) {
var port = new isolate.ReceivePort();
initialReplyTo.send(port.sendPort);
bool wasThrown = false;
try {
window.alert('Test');
@ -22,28 +25,41 @@ void isolateEntry() {
// Check that convert library was loaded to isolate.
JSON.encode([1, 2, 3]);
isolate.port.receive((message, replyTo) {
replyTo.send(responseFor(message), null);
port.listen((message) {
var data = message[0];
var replyTo = message[1];
replyTo.send(responseFor(data));
});
}
Future sendReceive(isolate.SendPort port, msg) {
var response = new isolate.ReceivePort();
port.send([msg, response.sendPort]);
return response.first;
}
main() {
useHtmlConfiguration();
test('IsolateSpawn', () {
isolate.spawnFunction(isolateEntry);
var port = new isolate.ReceivePort();
isolate.Isolate.spawn(isolateEntry, port.sendPort);
port.close();
});
test('NonDOMIsolates', () {
var callback = expectAsync0((){});
var port = isolate.spawnFunction(isolateEntry);
final msg1 = 'foo';
final msg2 = 'bar';
port.call(msg1).then((response) {
guardAsync(() {
expect(response, equals(responseFor(msg1)));
port.call(msg2).then((response) {
guardAsync(() {
expect(response, equals(responseFor(msg2)));
callback();
var response = new isolate.ReceivePort();
var remote = isolate.Isolate.spawn(isolateEntry, response.sendPort);
response.first.then((port) {
final msg1 = 'foo';
final msg2 = 'bar';
sendReceive(port, msg1).then((response) {
guardAsync(() {
expect(response, equals(responseFor(msg1)));
sendReceive(port, msg2).then((response) {
guardAsync(() {
expect(response, equals(responseFor(msg2)));
callback();
});
});
});
});

View file

@ -8,24 +8,25 @@ import 'dart:isolate';
import 'package:unittest/unittest.dart';
import 'package:unittest/html_config.dart';
worker() {
port.receive((String uri, SendPort replyTo) {
try {
var url = Url.createObjectUrl(new Blob([''], 'application/javascript'));
Url.revokeObjectUrl(url);
replyTo.send('Hello from Worker');
} catch (e) {
replyTo.send('Error: $e');
}
port.close();
});
worker(message) {
var uri = message[0];
var replyTo = message[1];
try {
var url = Url.createObjectUrl(new Blob([''], 'application/javascript'));
Url.revokeObjectUrl(url);
replyTo.send('Hello from Worker');
} catch (e) {
replyTo.send('Error: $e');
}
}
main() {
useHtmlConfiguration();
test('Use Worker API in Worker', () {
spawnFunction(worker).call('').then(
expectAsync1((reply) => expect(reply, equals('Hello from Worker'))));
var response = new ReceivePort();
var remote = Isolate.spawn(worker, ['', response.sendPort]);
remote.then((_) => response.first)
.then(expectAsync1((reply) => expect(reply, equals('Hello from Worker'))));
});
}

View file

@ -1,39 +0,0 @@
// 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.
// Test that spawn works even when there are many script files in the page.
// This requires computing correctly the URL to the orignal script, so we can
// pass it to the web worker APIs.
library compute_this_script;
import 'dart:html';
import 'dart:isolate';
import 'package:unittest/unittest.dart';
import 'package:unittest/html_config.dart';
child() {
var sink;
stream.listen((msg) {
sink = msg;
}, onDone: () {
sink.add("done");
sink.close();
});
}
main() {
useHtmlConfiguration();
var script = new ScriptElement();
document.body.append(script);
test('spawn with other script tags in page', () {
var box = new MessageBox();
box.stream.listen(expectAsync1((msg) {
expect(msg, equals("done"));
}));
IsolateSink s = streamSpawnFunction(child);
s.add(box.sink);
s.close();
});
}

View file

@ -12,11 +12,10 @@ import 'dart:isolate';
import 'package:unittest/unittest.dart';
import 'package:unittest/html_config.dart';
child() {
port.receive((msg, reply) {
reply.send('re: $msg');
port.close();
});
child(var message) {
var data = message[0];
var reply = message[1];
reply.send('re: $data');
}
main() {
@ -25,12 +24,11 @@ main() {
document.body.append(script);
test('spawn with other script tags in page', () {
ReceivePort port = new ReceivePort();
port.receive(expectAsync2((msg, _) {
port.listen(expectAsync1((msg) {
expect(msg, equals('re: hi'));
port.close();
}));
SendPort s = spawnFunction(child);
s.send('hi', port.toSendPort());
Isolate.spawn(child, ['hi', port.sendPort]);
});
}

View file

@ -56,42 +56,55 @@ void VerifyObject(int index, var actual) {
expect(actual.length, expected.length);
}
pingPong() {
pingPong(SendPort initialReplyTo) {
var port = new ReceivePort();
initialReplyTo.send(port.sendPort);
initializeList();
int count = 0;
port.receive((var message, SendPort replyTo) {
if (message == -1) {
port.listen((var message) {
var data = message[0];
SendPort replyTo = message[1];
if (data == -1) {
port.close();
replyTo.send(count, null);
} else {
// Check if the received object is correct.
if (count < elements.length) {
VerifyObject(count, message);
VerifyObject(count, data);
}
// Bounce the received object back so that the sender
// can make sure that the object matches.
replyTo.send(message, null);
replyTo.send(data, null);
count++;
}
});
}
Future sendReceive(SendPort port, msg) {
ReceivePort response = new ReceivePort();
port.send([msg, response.sendPort]);
return response.first;
}
main() {
initializeList();
test("send objects and receive them back", () {
SendPort remote = spawnFunction(pingPong);
// Send objects and receive them back.
for (int i = 0; i < elements.length; i++) {
var sentObject = elements[i];
var idx = i;
remote.call(sentObject).then(expectAsync1((var receivedObject) {
VerifyObject(idx, receivedObject);
}));
}
ReceivePort response = new ReceivePort();
Isolate.spawn(pingPong, response.sendPort);
response.first.then((SendPort remote) {
// Send objects and receive them back.
for (int i = 0; i < elements.length; i++) {
var sentObject = elements[i];
var idx = i;
sendReceive(remote, sentObject).then(expectAsync1((var receivedObject) {
VerifyObject(idx, receivedObject);
}));
}
// Shutdown the MessageServer.
remote.call(-1).then(expectAsync1((int message) {
expect(message, elements.length);
}));
// Shutdown the MessageServer.
sendReceive(remote, -1).then(expectAsync1((int message) {
expect(message, elements.length);
}));
});
});
}

View file

@ -1,46 +0,0 @@
// 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.
library CountTest;
import '../../pkg/unittest/lib/unittest.dart';
import 'dart:isolate';
void countMessages() {
int count = 0;
IsolateSink replySink;
bool isFirst = true;
stream.listen((msg) {
if (isFirst) {
replySink = msg;
isFirst = false;
return;
}
replySink.add(count);
count++;
}, onDone: () {
expect(count, 10);
replySink.close();
});
}
void main() {
test("count 10 consecutive stream messages", () {
int count = 0;
MessageBox box = new MessageBox();
IsolateSink remote = streamSpawnFunction(countMessages);
remote.add(box.sink);
box.stream.listen(expectAsync1((remoteCount) {
expect(remoteCount, count);
count++;
if (count < 10) {
remote.add(null);
} else {
remote.close();
}
}, count: 10), onDone: expectAsync0(() {
expect(count, 10);
}));
remote.add(null);
});
}

View file

@ -6,47 +6,53 @@ library CountTest;
import '../../pkg/unittest/lib/unittest.dart';
import 'dart:isolate';
void countMessages() {
void countMessages(replyTo) {
int count = 0;
port.receive((int message, SendPort replyTo) {
var port = new ReceivePort();
replyTo.send(["init", port.sendPort]);
port.listen((int message) {
if (message == -1) {
expect(count, 10);
replyTo.send(-1, null);
replyTo.send(["done"]);
port.close();
return;
}
expect(message, count);
count++;
replyTo.send(message * 2, null);
expect(message, count);
replyTo.send(["count", message * 2]);
});
}
void main() {
test("count 10 consecutive messages", () {
int count = 0;
SendPort remote = spawnFunction(countMessages);
ReceivePort local = new ReceivePort();
SendPort reply = local.toSendPort();
local.receive(expectAsync2((int message, SendPort replyTo) {
if (message == -1) {
// [count] is '11' because when we sent '9' to [remote],
// the other isolate will send another message '18', that this
// isolate will receive. Then this isolate will send '10' to
// [remote] and increment [count]. Note that this last '10'
// message will not be received by the other isolate, since it
// received '-1' before.
expect(count, 11);
local.close();
return;
Isolate.spawn(countMessages, local.sendPort);
SendPort remote;
int count = 0;
var done = expectAsync0((){});
local.listen((msg) {
switch (msg[0]) {
case "init":
expect(remote, null);
remote = msg[1];
remote.send(++count);
break;
case "count":
expect(msg[1], count * 2);
if (count == 10) {
remote.send(-1);
} else {
remote.send(++count);
}
break;
case "done":
expect(count, 10);
local.close();
done();
break;
default:
fail("unreachable: ${msg[0]}");
}
expect(message, (count - 1) * 2);
remote.send(count++, reply);
if (count == 10) {
remote.send(-1, reply);
}
}, count: 11));
remote.send(count++, reply);
});
});
}

View file

@ -1,112 +0,0 @@
// 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.
// Dart test program for testing that isolates can communicate to isolates
// other than the main isolate.
library CrossIsolateMessageTest;
import 'dart:isolate';
import '../../pkg/unittest/lib/unittest.dart';
/*
* Everything starts in the main-isolate (in the main-method).
* The main isolate spawns two isolates: isolate1 (with entry point
* 'crossIsolate1') and isolate2 (with entry point 'crossIsolate2').
*
* The main-isolate creates a new message-box and sends its sink to both
* isolates. Whenever isolate1 or isolate2 send something to the main-isolate
* they will use this sink.
* Isolate2 stores the sink and replies with a new sink (sink2b) it created.
* Isolate1 stores the sink and waits for another message.
* Main receives isolate2's sink2b and sends it to isolate1.
* Isolate1 stores this sink as "otherIsolate" and send a new sink (sink1b) to
* the main isolate.
* Main receives sink1b and sents a message "fromMain, 42" to sink1b.
* isolate1 receives this message, modifies it (adding 58 to 42) and forwards
* it to isolate2 (otherIsolate).
* isolate2 receives the message, modifies it (adding 399), and sends it to
* the main isolate.
* The main-isolate receives it, verifies that the result is 499 and ends the
* test.
*/
void crossIsolate1() {
bool first = true;
IsolateSink mainIsolate;
var subscription = stream.listen((msg) {
if (first) {
first = false;
mainIsolate = msg;
return;
}
IsolateSink otherIsolate = msg;
MessageBox box = new MessageBox();
box.stream.single.then((msg) {
expect(msg[0], "fromMain");
otherIsolate.add(["fromIsolate1", msg[1] + 58]); // 100;
otherIsolate.close();
box.stream.close();
});
mainIsolate.add(['ready1', box.sink]);
stream.close();
});
}
void crossIsolate2() {
var subscription;
subscription = stream.listen((msg) {
IsolateSink mainIsolate = msg;
MessageBox box = new MessageBox();
box.stream.listen((msg) {
expect(msg[0], "fromIsolate1");
mainIsolate.add(["fromIsolate2", msg[1] + 399]); // 499;
mainIsolate.close();
box.stream.close();
});
mainIsolate.add(['ready2', box.sink]);
subscription.cancel();
});
}
main() {
test("share sink, and send message cross isolates ", () {
IsolateSink sink1 = streamSpawnFunction(crossIsolate1);
IsolateSink sink2 = streamSpawnFunction(crossIsolate2);
// Create a new sink and send it to isolate2.
MessageBox box = new MessageBox();
sink1.add(box.sink);
sink2.add(box.sink);
int msgNumber = 0;
bool isReady1 = false;
bool isReady2 = false;
bool hasSentMessage = false;
Function ready1 = expectAsync0(() => isReady1 = true);
Function ready2 = expectAsync0(() => isReady2 = true);
Function fromIsolate2 = expectAsync1((data) {
expect(data, 499);
});
IsolateSink sink1b;
IsolateSink sink2b;
box.stream.listen((msg) {
switch (msg[0]) {
case 'ready1': ready1(); sink1b = msg[1]; break;
case 'ready2':
ready2();
sink2b = msg[1];
sink1.add(sink2b);
break;
case 'fromIsolate2': fromIsolate2(msg[1]); break;
default: throw "bad message";
}
if (isReady1 && isReady2 && !hasSentMessage) {
hasSentMessage = true;
sink1b.add(["fromMain", 42]);
sink1b.close();
}
});
});
}

View file

@ -9,51 +9,49 @@ library CrossIsolateMessageTest;
import 'dart:isolate';
import '../../pkg/unittest/lib/unittest.dart';
void crossIsolate1() {
port.receive((msg, replyTo) {
SendPort otherIsolate = msg;
ReceivePort receivePort = new ReceivePort();
receivePort.receive((msg, replyTo) {
otherIsolate.send(msg + 58, null); // 100.
receivePort.close();
});
replyTo.send(['ready', receivePort.toSendPort()]);
port.close();
/*
* Everything starts in the main-isolate (in the main-method).
* The main isolate spawns two isolates: isolate1 (with entry point
* 'crossIsolate1') and isolate2 (with entry point 'crossIsolate2').
*
* The main isolate creates two isolates, isolate1 and isolate2.
* The second isolate is created with a send-port being listened on by
* isolate1. A message is passed along this from isolate2 to isolate1.
* Isolate1 then sends the result back to the main isolate for final checking.
*/
void crossIsolate1(SendPort mainIsolate) {
ReceivePort local = new ReceivePort();
mainIsolate.send(["ready1", local.sendPort]);
local.first.then((msg) {
// Message from crossIsolate2
expect(msg[0], "fromIsolate2");
mainIsolate.send(["fromIsolate1", msg[1] + 58]); // 100.
});
}
// crossIsolate2 is nearly the same as crossIsolate1, but contains a
// different constant.
void crossIsolate2() {
port.receive((msg, replyTo) {
SendPort mainIsolate = msg;
ReceivePort receivePort = new ReceivePort();
receivePort.receive((msg, replyTo) {
mainIsolate.send(msg + 399, null); // 499.
receivePort.close();
});
replyTo.send(['ready', receivePort.toSendPort()]);
port.close();
});
void crossIsolate2(SendPort toIsolate1) {
toIsolate1.send(["fromIsolate2", 42]);
}
main() {
test("share port, and send message cross isolates ", () {
SendPort port1 = spawnFunction(crossIsolate1);
SendPort port2 = spawnFunction(crossIsolate2);
// Create a new receive port and send it to isolate2.
ReceivePort myPort = new ReceivePort();
port2.call(myPort.toSendPort()).then(expectAsync1((msg) {
expect(msg[0], "ready");
// Send port of isolate2 to isolate1.
port1.call(msg[1]).then(expectAsync1((msg) {
expect(msg[0], "ready");
myPort.receive(expectAsync2((msg, replyTo) {
expect(msg, 499);
myPort.close();
}));
msg[1].send(42, null);
}));
}));
test("send message cross isolates ", () {
ReceivePort fromIsolate1 = new ReceivePort();
Isolate.spawn(crossIsolate1, fromIsolate1.sendPort);
var done = expectAsync0((){});
fromIsolate1.listen((msg) {
switch (msg[0]) {
case "ready1":
SendPort toIsolate1 = msg[1];
Isolate.spawn(crossIsolate2, toIsolate1);
break;
case "fromIsolate1":
expect(msg[1], 100);
fromIsolate1.close();
break;
default:
fail("unreachable! Tag: ${msg[0]}");
}
}, onDone: done);
});
}

View file

@ -1,45 +0,0 @@
// Copyright (c) 2013, 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 test;
import 'package:expect/expect.dart';
import 'dart:async';
import 'dart:isolate';
import "package:async_helper/async_helper.dart";
runTest() {
SendPort mainIsolate;
bool isFirst = true;
port.receive((msg, replyTo) {
if (isFirst) {
mainIsolate = msg;
isFirst = false;
throw new UnsupportedError("ignore exception");
}
Expect.equals("message 2", msg);
mainIsolate.send("received");
});
}
bool globalErrorHandler(IsolateUnhandledException e) {
return e.source is UnsupportedError && e.source.message == "ignore exception";
}
main() {
// Make sure this test doesn't last longer than 2 seconds.
var timer = new Timer(const Duration(seconds: 2), () { throw "failed"; });
var port = new ReceivePort();
SendPort otherIsolate = spawnFunction(runTest, globalErrorHandler);
otherIsolate.send(port.toSendPort());
otherIsolate.send("message 2");
asyncStart();
port.receive((msg, replyPort) {
Expect.equals("received", msg);
port.close();
timer.cancel();
asyncEnd();
});
}

View file

@ -1,53 +0,0 @@
// Copyright (c) 2013, 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 test;
import 'package:expect/expect.dart';
import 'dart:async';
import 'dart:isolate';
import "package:async_helper/async_helper.dart";
runTest() {
IsolateSink mainIsolate;
stream.listen((msg) {
mainIsolate = msg;
throw new UnsupportedError("ignore exception");
}, onDone: () {
mainIsolate.add("received done");
mainIsolate.close();
});
}
bool globalErrorHandler(IsolateUnhandledException e) {
var source = e.source;
return source is UnsupportedError && source.message == "ignore exception";
}
main() {
var keepRunningBox = new MessageBox();
// Make sure this test doesn't last longer than 2 seconds.
var timer = new Timer(const Duration(seconds: 2), () { throw "failed"; });
var box = new MessageBox();
IsolateSink otherIsolate = streamSpawnFunction(runTest, globalErrorHandler);
otherIsolate.add(box.sink);
// The previous event should have been handled entirely, but the current
// implementations don't guarantee that and might mix the done event with
// the handling of the previous event. We therefore delay the closing.
// Note: if the done is sent too early it won't lead to failing tests, but
// just won't make sure that the globalErrorHandler works.
asyncStart();
new Timer(const Duration(milliseconds: 10), () {
otherIsolate.close();
asyncEnd();
});
asyncStart();
box.stream.single.then((msg) {
Expect.equals("received done", msg);
timer.cancel();
keepRunningBox.stream.close();
asyncEnd();
});
}

View file

@ -1,47 +0,0 @@
// Copyright (c) 2013, 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 test;
import 'dart:async';
import 'dart:isolate';
var firstFunction;
var finishFunction;
void runFunctions() {
try {
firstFunction();
} catch (e) {
new Timer(Duration.ZERO, finishFunction);
rethrow;
}
}
void startTest(EventSink finishSink) {
firstFunction = () { throw new UnsupportedError("ignore exception"); };
finishFunction = () { finishSink.add("done"); finishSink.close(); };
new Timer(Duration.ZERO, runFunctions);
}
runTest() {
stream.single.then(startTest);
}
bool globalErrorHandler(IsolateUnhandledException e) {
return e.source is UnsupportedError && e.source.message == "ignore exception";
}
main() {
var box = new MessageBox();
var timer;
EventSink otherIsolate = streamSpawnFunction(runTest, globalErrorHandler);
otherIsolate.add(box.sink);
otherIsolate.close();
box.stream.single.then((msg) {
box.stream.close();
timer.cancel();
});
timer = new Timer(const Duration(seconds: 2), () { throw "failed"; });
}

View file

@ -1,43 +0,0 @@
// Copyright (c) 2013, 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 test;
import 'dart:async';
import 'dart:isolate';
var firstFunction;
var finishFunction;
void runFunctions() {
try {
firstFunction();
} catch (e) {
new Timer(Duration.ZERO, finishFunction);
rethrow;
}
}
void startTest(SendPort finishPort, replyPort) {
firstFunction = () { throw new UnsupportedError("ignore exception"); };
finishFunction = () { finishPort.send("done"); };
new Timer(Duration.ZERO, runFunctions);
}
runTest() {
port.receive(startTest);
}
bool globalErrorHandler(IsolateUnhandledException e) {
return e.source is UnsupportedError && e.source.message == "ignore exception";
}
main() {
var port = new ReceivePort();
var timer;
SendPort otherIsolate = spawnFunction(runTest, globalErrorHandler);
otherIsolate.send(port.toSendPort());
port.receive((msg, replyPort) { port.close(); timer.cancel(); });
timer = new Timer(const Duration(seconds: 2), () { throw "failed"; });
}

View file

@ -1,38 +0,0 @@
// 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.
library test;
import 'package:expect/expect.dart';
import 'dart:isolate';
import "package:async_helper/async_helper.dart";
funcFoo(x) => x + 2;
foo() {
stream.single.then((msg) {
IsolateSink sink = msg;
sink.add(499);
sink.close();
});
}
main() {
var box = new MessageBox();
var snd = streamSpawnFunction(foo);
var caught_exception = false;
try {
snd.add(funcFoo);
} catch (e) {
caught_exception = true;
}
snd.add(box.sink);
snd.close();
asyncStart();
box.stream.single.then((msg) {
Expect.equals(499, msg);
asyncEnd();
});
}

View file

@ -9,29 +9,37 @@ import "package:async_helper/async_helper.dart";
funcFoo(x) => x + 2;
echo() {
port.receive((msg, reply) {
reply.send("echoing ${msg(1)}}");
echo(sendPort) {
var port = new ReceivePort();
sendPort.send(port.sendPort);
port.listen((msg) {
sendPort.send("echoing ${msg(1)}}");
});
}
main() {
var snd = spawnFunction(echo);
ReceivePort port = new ReceivePort();
Future spawn = Isolate.spawn(echo, port.sendPort);
var caught_exception = false;
try {
snd.send(funcFoo, port.toSendPort());
} catch (e) {
caught_exception = true;
}
var stream = port.asBroadcastStream();
asyncStart();
stream.first.then((snd) {
try {
snd.send(funcFoo);
} catch (e) {
caught_exception = true;
}
if (caught_exception) {
port.close();
} else {
asyncStart();
port.receive((msg, reply) {
print("from worker ${msg}");
asyncEnd();
});
}
Expect.isTrue(caught_exception);
if (caught_exception) {
port.close();
} else {
asyncStart();
stream.first.then((msg) {
print("from worker ${msg}");
asyncEnd();
});
}
Expect.isTrue(caught_exception);
asyncEnd();
});
}

View file

@ -14,31 +14,26 @@ isolate3_negative_test: Skip # Issue 12587.
[ $analyzer ]
isolate2_negative_test: Fail
isolate_negative_test: Fail
isolate_import_negative_test: Fail
spawn_function_negative_test: Fail
spawn_uri_vm_negative_test: Fail
unresolved_ports_negative_test: Fail
mandel_isolate_test: Fail # issue 14452
[ $compiler == dart2js && $jscl ]
browser/*: SkipByDesign # Browser specific tests
illegal_msg_stream_test: RuntimeError # Issue 6750
[ $compiler == dart2js && $browser ]
illegal_msg_stream_test: Fail, Pass # Issue 6750
[ $compiler == dart2js && $runtime == drt ]
unresolved_ports_negative_test: Pass, Crash # Issue 10613
isolate_stress_test: Pass, Crash # Issue 14438
[ $compiler == dart2js ]
serialization_test: RuntimeError # Issue 1882, tries to access class TestingOnly declared in isolate_patch.dart
illegal_msg_test: RuntimeError # Issue 6750
stream_mangling_test: RuntimeError # Issue 9245
global_error_handler_test: Pass, RuntimeError # Issue 9012, Issue 9024
global_error_handler_stream_test: Pass, RuntimeError # Issue 9012, Issue 9024
global_error_handler2_test: Pass, RuntimeError # Issue 9012, Issue 9024
global_error_handler_stream2_test: Pass, RuntimeError # Issue 9012, Issue 9024
[ $compiler == dart2js && ($runtime == drt || $runtime == ff || $runtime == chrome || $runtime == chromeOnAndroid || $runtime == ie9 || $runtime == ie10 || $runtime == safari) ]
[ $compiler == dart2js && $runtime == ie9 ]
browser/typed_data_message_test: Fail # Issue 12624
[ $compiler == dart2js && $runtime == safari ]
@ -66,7 +61,6 @@ spawn_uri_test: Fail # Issue 12630
[ $compiler == dart2js && $runtime == none ]
spawn_function_negative_test: Fail # Issue 12628
unresolved_ports_negative_test: Fail # Issue 12628
stream_mangling_test: Pass # Issue 12628
isolate_negative_test: Fail # Issue 12628
serialization_test: Pass # Issue 12628
isolate_import_negative_test: Fail # Issue 12628
@ -75,7 +69,6 @@ illegal_msg_test: Pass # Issue 12628
[ $compiler == dart2js && $runtime == chromeOnAndroid ]
isolate_stress_test: Pass, Slow # TODO(kasperl): Please triage.
mandel_isolate_stream_test: Pass, Slow # TODO(kasperl): Please triage.
mandel_isolate_test: Pass, Timeout # TODO(kasperl): Please triage.
@ -84,15 +77,12 @@ mandel_isolate_test: Pass, Timeout # TODO(kasperl): Please triage.
[ $compiler == dart2js && $runtime == ff && ($system == windows || $system == linux) ]
mandel_isolate_test: Pass, Fail, Timeout # Issue 7952
mandel_isolate_stream_test: Pass, Fail, Timeout # Issue 7952
[ $compiler == dart2js && ( $runtime == ff || $runtime == safari || $runtime == drt || $runtime == chrome ) ]
isolate_stress_test: Pass, Slow # Issue 10697
[ $compiler == none && $runtime == drt ]
isolate_stress_test: Skip # Issue 12537
nested_spawn_stream2_test: Fail # Issue 13433
cross_isolate_message_stream_test: Fail # Issue 13433
[ $csp ]
spawn_uri_multi_test/none: Fail # http://dartbug.com/13454
@ -102,37 +92,24 @@ spawn_uri_test: Fail # http://dartbug.com/13454
spawn_uri_multi_test/none: RuntimeError # http://dartbug.com/13544
[ $compiler == none && $runtime == dartium ]
cross_isolate_message_stream_test: Fail # Issue 13719: Please triage this failure.
global_error_handler2_test: Fail # Issue 13719: Please triage this failure.
global_error_handler_stream2_test: Fail # Issue 13719: Please triage this failure.
nested_spawn_stream2_test: Fail # Issue 13719: Please triage this failure.
[ $compiler == none && ($runtime == drt || $runtime == dartium) ]
# Issue 13921: spawnFunction is not allowed on Dartium's DOM thread.
browser/compute_this_script_browser_stream_test: Fail
browser/compute_this_script_browser_test: Fail
browser/typed_data_message_test: Skip # 13961
count_stream_test: Fail
count_test: Fail
cross_isolate_message_test: Fail
global_error_handler2_test: Fail
global_error_handler_stream2_test: Fail
global_error_handler_stream_test: Fail
global_error_handler_test: Fail
illegal_msg_stream_test: Fail
illegal_msg_test: Fail
isolate_complex_messages_stream_test: Fail
isolate_complex_messages_test: Fail
isolate_stress_test: Fail
mandel_isolate_stream_test: Fail
mandel_isolate_test: Fail
message2_test: Fail
message_stream2_test: Fail
message_stream_test: Fail
message_test: Fail
mint_maker_test: Fail
nested_spawn2_test: Fail
nested_spawn_stream_test: Fail
nested_spawn_test: Fail
request_reply_test: Fail
spawn_function_custom_class_test: Fail

View file

@ -9,7 +9,7 @@ library isolate2_negative_test;
import 'dart:isolate';
import "package:async_helper/async_helper.dart";
void entry() {
void entry(msg) {
throw "foo";
}
@ -18,5 +18,5 @@ main() {
// anything back except an exception there is no asyncEnd().
// If the exception is not thrown this test will timeout.
asyncStart();
SendPort port = spawnFunction(entry);
Isolate.spawn(entry);
}

View file

@ -17,11 +17,9 @@ class TestClass {
num fld2;
}
void entry() {
port.receive((ignored, replyTo) {
var tmp = new TestClass.named(10);
replyTo.send(tmp, null);
});
void entry(SendPort replyTo) {
var tmp = new TestClass.named(10);
replyTo.send(tmp);
}
main() {
@ -29,7 +27,8 @@ main() {
void msg_callback(var message) {
// This test is a negative test and should not complete successfully.
}
SendPort port = spawnFunction(entry);
port.call("foo").then(expectAsync1(msg_callback));
ReceivePort response = new ReceivePort();
Isolate.spawn(entry, response.sendPort);
response.first.then(expectAsync1(msg_callback));
});
}

View file

@ -1,78 +0,0 @@
// 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.
// Dart test program for testing isolate communication with
// complex messages.
library IsolateComplexMessagesTest;
import 'dart:isolate';
import '../../pkg/unittest/lib/unittest.dart';
main() {
test("complex messages are serialized correctly", () {
var box = new MessageBox();
IsolateSink remote = streamSpawnFunction(logMessages);
remote.add(1);
remote.add("Hello");
remote.add("World");
remote.add(const [null, 1, 2, 3, 4]);
remote.add(const [1, 2.0, true, false, 0xffffffffff]);
remote.add(const ["Hello", "World", 0xffffffffff]);
remote.add(box.sink);
remote.close();
box.stream.single.then((message) {
expect(message, 7);
});
});
}
void logMessages() {
int count = 0;
IsolateSink replySink;
stream.listen((message) {
switch (count) {
case 0:
expect(message, 1);
break;
case 1:
expect(message, "Hello");
break;
case 2:
expect(message, "World");
break;
case 3:
expect(message.length, 5);
expect(message[0], null);
expect(message[1], 1);
expect(message[2], 2);
expect(message[3], 3);
expect(message[4], 4);
break;
case 4:
expect(message.length, 5);
expect(message[0], 1);
expect(message[1], 2.0);
expect(message[2], true);
expect(message[3], false);
expect(message[4], 0xffffffffff);
break;
case 5:
expect(message.length, 3);
expect(message[0], "Hello");
expect(message[1], "World");
expect(message[2], 0xffffffffff);
break;
case 6:
replySink = message;
break;
}
count++;
},
onDone: () {
replySink.add(count);
replySink.close();
});
}

View file

@ -11,28 +11,40 @@ import '../../pkg/unittest/lib/unittest.dart';
main() {
test("complex messages are serialized correctly", () {
SendPort remote = spawnFunction(logMessages);
remote.send(1, null);
remote.send("Hello", null);
remote.send("World", null);
remote.send(const [null, 1, 2, 3, 4], null);
remote.send(const [1, 2.0, true, false, 0xffffffffff], null);
remote.send(const ["Hello", "World", 0xffffffffff], null);
// Shutdown the LogRunner.
remote.call(-1).then(expectAsync1((int message) {
expect(message, 6);
}));
ReceivePort local = new ReceivePort();
Isolate.spawn(logMessages, local.sendPort);
var done = expectAsync0((){});
local.listen(expectAsync1((msg) {
switch (msg[0]) {
case "init":
var remote = msg[1];
remote.send(1, null);
remote.send("Hello", null);
remote.send("World", null);
remote.send(const [null, 1, 2, 3, 4], null);
remote.send(const [1, 2.0, true, false, 0xffffffffff], null);
remote.send(const ["Hello", "World", 0xffffffffff], null);
// Shutdown the LogRunner.
remote.send(-1);
break;
case "done":
local.close();
expect(msg[1], 6);
done();
}
}, count: 2));
});
}
void logMessages() {
void logMessages(mainPort) {
int count = 0;
port.receive((var message, SendPort replyTo) {
ReceivePort port = new ReceivePort();
mainPort.send(["init", port.sendPort]);
port.listen((var message) {
if (message == -1) {
port.close();
replyTo.send(count, null);
mainPort.send(["done", count]);
} else {
switch (count) {
case 0:

View file

@ -6,9 +6,9 @@ library IsolateImportNegativeTest;
// Omitting the following import is an error:
// import 'dart:isolate';
void entry() {}
void entry(msg) {}
main() {
spawnFunction(entry);
Isolate.spawn(entry);
}

View file

@ -9,16 +9,15 @@ import "package:expect/expect.dart";
import 'dart:isolate';
import '../../pkg/unittest/lib/unittest.dart';
void entry() {
port.receive((ignored, replyTo) {
replyTo.send("foo", null);
});
void entry(SendPort replyTo) {
replyTo.send("foo");
}
main() {
test("ensure isolate code is executed", () {
SendPort port = spawnFunction(entry);
port.call("foo").then(expectAsync1((message) {
ReceivePort response = new ReceivePort();
Isolate.spawn(entry, response.sendPort);
response.first.then(expectAsync1((message) {
expect("Expected fail", isTrue); // <=-------- Should fail here.
}));
});

View file

@ -12,11 +12,8 @@ import 'dart:isolate';
// TODO(12588): Remove this import when we have wrapper-less testing.
import 'dart:html';
worker() {
port.receive((String uri, SendPort replyTo) {
replyTo.send('Hello from Worker');
port.close();
});
worker(SendPort replyTo) {
replyTo.send('Hello from Worker');
}
main() {
@ -33,11 +30,12 @@ main() {
throw new Exception('Unexpected reply from worker: $reply');
}
if (++isolateCount > 200) {
port.close();
window.postMessage('unittest-suite-success', '*');
return;
}
spawnFunction(worker).call('').then(spawnMany);
ReceivePort response = new ReceivePort();
var remote = Isolate.spawn(worker, response.sendPort);
remote.then((_) => response.first).then(spawnMany);
print('isolateCount = $isolateCount');
}

View file

@ -1,155 +0,0 @@
// 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.
library MandelIsolateTest;
import 'dart:async';
import 'dart:isolate';
import 'dart:math';
import '../../pkg/unittest/lib/unittest.dart';
const TERMINATION_MESSAGE = -1;
const N = 100;
const ISOLATES = 20;
main() {
// Test is really slow in debug builds of the VM.
unittestConfiguration.timeout = const Duration(seconds: 480);
test("Render Mandelbrot in parallel", () {
final state = new MandelbrotState();
state._validated.future.then(expectAsync1((result) {
expect(result, isTrue);
}));
for (int i = 0; i < min(ISOLATES, N); i++) state.startClient(i);
});
}
class MandelbrotState {
MandelbrotState() {
_result = new List<List<int>>(N);
_lineProcessedBy = new List<LineProcessorClient>(N);
_sent = 0;
_missing = N;
_validated = new Completer<bool>();
}
void startClient(int id) {
assert(_sent < N);
final client = new LineProcessorClient(this, id);
client.processLine(_sent++);
}
void notifyProcessedLine(LineProcessorClient client, int y, List<int> line) {
assert(_result[y] == null);
_result[y] = line;
_lineProcessedBy[y] = client;
if (_sent != N) {
client.processLine(_sent++);
} else {
client.shutdown();
}
// If all lines have been computed, validate the result.
if (--_missing == 0) {
_printResult();
_validateResult();
}
}
void _validateResult() {
// TODO(ngeoffray): Implement this.
_validated.complete(true);
}
void _printResult() {
var output = new StringBuffer();
for (int i = 0; i < _result.length; i++) {
List<int> line = _result[i];
for (int j = 0; j < line.length; j++) {
if (line[j] < 10) output.write("0");
output.write(line[j]);
}
output.write("\n");
}
// print(output);
}
List<List<int>> _result;
List<LineProcessorClient> _lineProcessedBy;
int _sent;
int _missing;
Completer<bool> _validated;
}
class LineProcessorClient {
LineProcessorClient(MandelbrotState this._state, int this._id) {
_sink = streamSpawnFunction(processLines);
_box = new MessageBox();
_sink.add(_box.sink);
_box.stream.listen((List<int> message) {
_state.notifyProcessedLine(this, _currentLine, message);
});
}
void processLine(int y) {
_currentLine = y;
_sink.add(y);
}
void shutdown() {
_sink.close();
_box.stream.close();
}
MandelbrotState _state;
int _id;
IsolateSink _sink;
int _currentLine;
MessageBox _box;
}
List<int> processLine(int y) {
double inverseN = 2.0 / N;
double Civ = y * inverseN - 1.0;
List<int> result = new List<int>(N);
for (int x = 0; x < N; x++) {
double Crv = x * inverseN - 1.5;
double Zrv = Crv;
double Ziv = Civ;
double Trv = Crv * Crv;
double Tiv = Civ * Civ;
int i = 49;
do {
Ziv = (Zrv * Ziv) + (Zrv * Ziv) + Civ;
Zrv = Trv - Tiv + Crv;
Trv = Zrv * Zrv;
Tiv = Ziv * Ziv;
} while (((Trv + Tiv) <= 4.0) && (--i > 0));
result[x] = i;
}
return result;
}
void processLines() {
bool isFirst = true;
IsolateSink replyTo;
stream.listen((message) {
if (isFirst) {
isFirst = false;
replyTo = message;
return;
}
replyTo.add(processLine(message));
});
}

View file

@ -37,8 +37,10 @@ class MandelbrotState {
void startClient(int id) {
assert(_sent < N);
final client = new LineProcessorClient(this, id);
client.processLine(_sent++);
int line = _sent++;
LineProcessorClient.create(this, id).then((final client) {
client.processLine(line);
});
}
void notifyProcessedLine(LineProcessorClient client, int y, List<int> line) {
@ -86,24 +88,32 @@ class MandelbrotState {
class LineProcessorClient {
MandelbrotState _state;
int _id;
SendPort _port;
LineProcessorClient(MandelbrotState this._state, int this._id) {
_port = spawnFunction(processLines);
LineProcessorClient(this._state, this._id, this._port);
static Future<LineProcessorClient> create(MandelbrotState state, int id) {
ReceivePort reply = new ReceivePort();
return Isolate.spawn(processLines, reply.sendPort).then((_) {
return reply.first.then((port) {
return new LineProcessorClient(state, id, port);
});
});
}
void processLine(int y) {
_port.call(y).then((List<int> message) {
ReceivePort reply = new ReceivePort();
_port.send([y, reply.sendPort]);
reply.first.then((List<int> message) {
_state.notifyProcessedLine(this, y, message);
});
}
void shutdown() {
_port.send(TERMINATION_MESSAGE, null);
_port.send(TERMINATION_MESSAGE);
}
MandelbrotState _state;
int _id;
SendPort _port;
}
List<int> processLine(int y) {
@ -133,13 +143,16 @@ List<int> processLine(int y) {
return result;
}
void processLines() {
port.receive((message, SendPort replyTo) {
if (message == TERMINATION_MESSAGE) {
assert(replyTo == null);
port.close();
void processLines(SendPort replyPort) {
ReceivePort port = new ReceivePort();
port.listen((message) {
if (message != TERMINATION_MESSAGE) {
int line = message[0];
SendPort replyTo = message[1];
replyTo.send(processLine(line));
} else {
replyTo.send(processLine(message), null);
port.close();
}
});
replyPort.send(port.sendPort);
}

View file

@ -41,29 +41,36 @@ class MessageTest {
}
}
void pingPong() {
port.receive((var message, SendPort replyTo) {
if (message == -1) {
void pingPong(replyPort) {
ReceivePort port = new ReceivePort();
port.listen((message) {
if (message == null) {
port.close();
} else {
// Bounce the received object back so that the sender
// can make sure that the object matches.
replyTo.send(message, null);
message[1].send(message[0]);
}
});
replyPort.send(port.sendPort);
}
main() {
test("map is equal after it is sent back and forth", () {
SendPort remote = spawnFunction(pingPong);
Map m = new Map();
m[1] = "eins";
m[2] = "deux";
m[3] = "tre";
m[4] = "four";
remote.call(m).then(expectAsync1((var received) {
MessageTest.mapEqualsDeep(m, received);
remote.send(-1, null);
ReceivePort port = new ReceivePort();
Isolate.spawn(pingPong, port.sendPort);
port.first.then(expectAsync1((remote) {
Map m = new Map();
m[1] = "eins";
m[2] = "deux";
m[3] = "tre";
m[4] = "four";
ReceivePort replyPort = new ReceivePort();
remote.send([m, replyPort.sendPort]);
replyPort.first.then(expectAsync1((var received) {
MessageTest.mapEqualsDeep(m, received);
remote.send(null);
}));
}));
});
}

View file

@ -1,76 +0,0 @@
// 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.
// Dart test program for testing serialization of messages.
// VMOptions=--enable_type_checks --enable_asserts
library Message2Test;
import 'dart:isolate';
import '../../pkg/unittest/lib/unittest.dart';
// ---------------------------------------------------------------------------
// Message passing test 2.
// ---------------------------------------------------------------------------
class MessageTest {
static void mapEqualsDeep(Map expected, Map actual) {
expect(expected, isMap);
expect(actual, isMap);
expect(actual.length, expected.length);
testForEachMap(key, value) {
if (value is List) {
listEqualsDeep(value, actual[key]);
} else {
expect(actual[key], value);
}
}
expected.forEach(testForEachMap);
}
static void listEqualsDeep(List expected, List actual) {
for (int i = 0; i < expected.length; i++) {
if (expected[i] is List) {
listEqualsDeep(expected[i], actual[i]);
} else if (expected[i] is Map) {
mapEqualsDeep(expected[i], actual[i]);
} else {
expect(actual[i], expected[i]);
}
}
}
}
void pingPong() {
bool isFirst = true;
IsolateSink replyTo;
stream.listen((var message) {
if (isFirst) {
isFirst = false;
replyTo = message;
return;
}
// Bounce the received object back so that the sender
// can make sure that the object matches.
replyTo.add(message);
});
}
main() {
test("map is equal after it is sent back and forth", () {
IsolateSink remote = streamSpawnFunction(pingPong);
Map m = new Map();
m[1] = "eins";
m[2] = "deux";
m[3] = "tre";
m[4] = "four";
MessageBox box = new MessageBox();
remote.add(box.sink);
remote.add(m);
box.stream.listen(expectAsync1((var received) {
MessageTest.mapEqualsDeep(m, received);
remote.close();
box.stream.close();
}));
});
}

View file

@ -1,144 +0,0 @@
// 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.
// Dart test program for testing serialization of messages.
// VMOptions=--enable_type_checks --enable_asserts
library MessageTest;
import 'dart:isolate';
import '../../pkg/unittest/lib/unittest.dart';
// ---------------------------------------------------------------------------
// Message passing test.
// ---------------------------------------------------------------------------
class MessageTest {
static const List list1 = const ["Hello", "World", "Hello", 0xfffffffffff];
static const List list2 = const [null, list1, list1, list1, list1];
static const List list3 = const [list2, 2.0, true, false, 0xfffffffffff];
static const Map map1 = const {
"a=1" : 1, "b=2" : 2, "c=3" : 3,
};
static const Map map2 = const {
"list1" : list1, "list2" : list2, "list3" : list3,
};
static const List list4 = const [map1, map2];
static const List elms = const [
list1, list2, list3, list4,
];
static void VerifyMap(Map expected, Map actual) {
expect(expected, isMap);
expect(actual, isMap);
expect(actual.length, expected.length);
testForEachMap(key, value) {
if (value is List) {
VerifyList(value, actual[key]);
} else {
expect(actual[key], value);
}
}
expected.forEach(testForEachMap);
}
static void VerifyList(List expected, List actual) {
for (int i = 0; i < expected.length; i++) {
if (expected[i] is List) {
VerifyList(expected[i], actual[i]);
} else if (expected[i] is Map) {
VerifyMap(expected[i], actual[i]);
} else {
expect(actual[i], expected[i]);
}
}
}
static void VerifyObject(int index, var actual) {
var expected = elms[index];
expect(expected, isList);
expect(actual, isList);
expect(actual.length, expected.length);
VerifyList(expected, actual);
}
}
pingPong() {
int count = 0;
bool isFirst = true;
IsolateSink replyTo;
stream.listen((var message) {
if (isFirst) {
isFirst = false;
replyTo = message;
return;
}
// Check if the received object is correct.
if (count < MessageTest.elms.length) {
MessageTest.VerifyObject(count, message);
}
// Bounce the received object back so that the sender
// can make sure that the object matches.
replyTo.add(message);
count++;
}, onDone: () {
replyTo.add(count);
replyTo.close();
});
}
main() {
test("send objects and receive them back", () {
IsolateSink remote = streamSpawnFunction(pingPong);
MessageBox box = new MessageBox();
remote.add(box.sink);
// Send objects and receive them back.
for (int i = 0; i < MessageTest.elms.length; i++) {
var sentObject = MessageTest.elms[i];
// TODO(asiva): remove this local var idx once thew new for-loop
// semantics for closures is implemented.
var idx = i;
remote.add(sentObject);
}
// Send recursive objects and receive them back.
List local_list1 = ["Hello", "World", "Hello", 0xffffffffff];
List local_list2 = [null, local_list1, local_list1 ];
List local_list3 = [local_list2, 2.0, true, false, 0xffffffffff];
List sendObject = new List(5);
sendObject[0] = local_list1;
sendObject[1] = sendObject;
sendObject[2] = local_list2;
sendObject[3] = sendObject;
sendObject[4] = local_list3;
remote.add(sendObject);
// Shutdown the MessageServer.
remote.close();
int receivedCounter = 0;
box.stream.listen((message) {
if (receivedCounter < MessageTest.elms.length) {
MessageTest.VerifyObject(receivedCounter, message);
} else if (receivedCounter == MessageTest.elms.length) {
var replyObject = message;
expect(sendObject, isList);
expect(replyObject, isList);
expect(sendObject.length, equals(replyObject.length));
expect(replyObject[1], same(replyObject));
expect(replyObject[3], same(replyObject));
expect(replyObject[0], same(replyObject[2][1]));
expect(replyObject[0], same(replyObject[2][2]));
expect(replyObject[2], same(replyObject[4][0]));
expect(replyObject[0][0], same(replyObject[0][2]));
// Bigint literals are not canonicalized so do a == check.
expect(replyObject[0][3], equals(replyObject[4][4]));
} else {
// Reply from done.
expect(message, MessageTest.elms.length + 1);
}
receivedCounter++;
});
});
}

View file

@ -63,12 +63,15 @@ class MessageTest {
}
}
pingPong() {
pingPong(replyTo) {
ReceivePort port = new ReceivePort();
int count = 0;
port.receive((var message, SendPort replyTo) {
port.listen((pair) {
var message = pair[0];
var replyTo = pair[1];
if (message == -1) {
port.close();
replyTo.send(count, null);
replyTo.send(count);
} else {
// Check if the received object is correct.
if (count < MessageTest.elms.length) {
@ -76,53 +79,60 @@ pingPong() {
}
// Bounce the received object back so that the sender
// can make sure that the object matches.
replyTo.send(message, null);
replyTo.send(message);
count++;
}
});
replyTo.send(port.sendPort);
}
Future remoteCall(SendPort port, message) {
ReceivePort receivePort = new ReceivePort();
port.send([message, receivePort.sendPort]);
return receivePort.first;
}
main() {
test("send objects and receive them back", () {
SendPort remote = spawnFunction(pingPong);
// Send objects and receive them back.
for (int i = 0; i < MessageTest.elms.length; i++) {
var sentObject = MessageTest.elms[i];
// TODO(asiva): remove this local var idx once thew new for-loop
// semantics for closures is implemented.
var idx = i;
remote.call(sentObject).then(expectAsync1((var receivedObject) {
MessageTest.VerifyObject(idx, receivedObject);
}));
}
ReceivePort port = new ReceivePort();
Isolate.spawn(pingPong, port.sendPort);
port.first.then(expectAsync1((remote) {
// Send objects and receive them back.
for (int i = 0; i < MessageTest.elms.length; i++) {
var sentObject = MessageTest.elms[i];
remoteCall(remote, sentObject).then(expectAsync1((var receivedObject) {
MessageTest.VerifyObject(i, receivedObject);
}));
}
// Send recursive objects and receive them back.
List local_list1 = ["Hello", "World", "Hello", 0xffffffffff];
List local_list2 = [null, local_list1, local_list1 ];
List local_list3 = [local_list2, 2.0, true, false, 0xffffffffff];
List sendObject = new List(5);
sendObject[0] = local_list1;
sendObject[1] = sendObject;
sendObject[2] = local_list2;
sendObject[3] = sendObject;
sendObject[4] = local_list3;
remote.call(sendObject).then((var replyObject) {
expect(sendObject, isList);
expect(replyObject, isList);
expect(sendObject.length, equals(replyObject.length));
expect(replyObject[1], same(replyObject));
expect(replyObject[3], same(replyObject));
expect(replyObject[0], same(replyObject[2][1]));
expect(replyObject[0], same(replyObject[2][2]));
expect(replyObject[2], same(replyObject[4][0]));
expect(replyObject[0][0], same(replyObject[0][2]));
// Bigint literals are not canonicalized so do a == check.
expect(replyObject[0][3], equals(replyObject[4][4]));
});
// Send recursive objects and receive them back.
List local_list1 = ["Hello", "World", "Hello", 0xffffffffff];
List local_list2 = [null, local_list1, local_list1 ];
List local_list3 = [local_list2, 2.0, true, false, 0xffffffffff];
List sendObject = new List(5);
sendObject[0] = local_list1;
sendObject[1] = sendObject;
sendObject[2] = local_list2;
sendObject[3] = sendObject;
sendObject[4] = local_list3;
remoteCall(remote, sendObject).then((var replyObject) {
expect(sendObject, isList);
expect(replyObject, isList);
expect(sendObject.length, equals(replyObject.length));
expect(replyObject[1], same(replyObject));
expect(replyObject[3], same(replyObject));
expect(replyObject[0], same(replyObject[2][1]));
expect(replyObject[0], same(replyObject[2][2]));
expect(replyObject[2], same(replyObject[4][0]));
expect(replyObject[0][0], same(replyObject[0][2]));
// Bigint literals are not canonicalized so do a == check.
expect(replyObject[0][3], equals(replyObject[4][4]));
});
// Shutdown the MessageServer.
remote.call(-1).then(expectAsync1((int message) {
expect(message, MessageTest.elms.length + 1);
// Shutdown the MessageServer.
remoteCall(remote, -1).then(expectAsync1((int message) {
expect(message, MessageTest.elms.length + 1);
}));
}));
});
}

View file

@ -2,117 +2,84 @@
// 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.
// Things that should be "auto-generated" are between AUTO START and
// AUTO END (or just AUTO if it's a single line).
library MintMakerTest;
import 'dart:isolate';
import '../../pkg/unittest/lib/unittest.dart';
class Mint {
Mint() : registry_ = new Map<SendPort, Purse>() {
// AUTO START
Map<SendPort, Purse> _registry;
SendPort port;
Mint() : _registry = new Map<SendPort, Purse>() {
ReceivePort mintPort = new ReceivePort();
port = mintPort.toSendPort();
port = mintPort.sendPort;
serveMint(mintPort);
// AUTO END
}
// AUTO START
void serveMint(ReceivePort port) {
port.receive((var message, SendPort replyTo) {
int balance = message;
port.listen((message) {
int balance = message[0];
Purse purse = createPurse(balance);
replyTo.send([ purse.port ], null);
message[1].send(purse.port);
});
}
// AUTO END
Purse createPurse(int balance) {
Purse purse = new Purse(this, balance);
registry_[purse.port] = purse;
_registry[purse.port] = purse;
return purse;
}
Purse lookupPurse(SendPort port) {
return registry_[port];
return _registry[port];
}
Map<SendPort, Purse> registry_;
// AUTO
SendPort port;
}
// AUTO START
class MintWrapper {
MintWrapper(SendPort this.mint_) {}
SendPort _mint;
MintWrapper(SendPort this._mint) {}
void createPurse(int balance, handlePurse(PurseWrapper purse)) {
mint_.call(balance).then((var message) {
SendPort purse = message[0];
ReceivePort reply = new ReceivePort();
reply.first.then((SendPort purse) {
handlePurse(new PurseWrapper(purse));
});
_mint.send([balance, reply.sendPort]);
}
SendPort mint_;
}
// AUTO END
/*
One way this could look without the autogenerated code:
class Mint {
Mint() : registry_ = new Map<SendPort, Purse>() {
}
wrap Purse createPurse(int balance) {
Purse purse = new Purse(this, balance);
registry_[purse.port] = purse;
return purse;
}
Purse lookupPurse(SendPort port) {
return registry_[port];
}
Map<SendPort, Purse> registry_;
}
The other end of the port would use Wrapper<Mint> as the wrapper, or
Future<Mint> as a future for the wrapper.
*/
class Purse {
Purse(Mint this.mint, int this.balance) {
// AUTO START
Mint mint;
int balance;
SendPort port;
Purse(this.mint, this.balance) {
ReceivePort recipient = new ReceivePort();
port = recipient.toSendPort();
port = recipient.sendPort;
servePurse(recipient);
// AUTO END
}
// AUTO START
void servePurse(ReceivePort recipient) {
recipient.receive((var message, SendPort replyTo) {
recipient.listen((message) {
String command = message[0];
if (command == "balance") {
replyTo.send(queryBalance(), null);
SendPort replyTo = message.last;
replyTo.send(queryBalance());
} else if (command == "deposit") {
Purse source = mint.lookupPurse(message[2]);
deposit(message[1], source);
} else if (command == "sprout") {
SendPort replyTo = message.last;
Purse result = sproutPurse();
replyTo.send([ result.port ], null);
replyTo.send(result.port);
} else {
// TODO: Send an exception back.
replyTo.send("Exception: Command not understood", null);
throw UnsupportedError("Unsupported commend: $command");
}
});
}
// AUTO END
int queryBalance() { return balance; }
@ -124,64 +91,60 @@ class Purse {
balance += amount;
source.balance -= amount;
}
Mint mint;
int balance;
// AUTO
SendPort port;
}
// AUTO START
class PurseWrapper {
PurseWrapper(SendPort this.purse_) {}
SendPort _purse;
PurseWrapper(this._purse) {}
void _sendReceive(message, replyHandler(reply)) {
ReceivePort reply = new ReceivePort();
_purse.send([message, reply.sendPort]);
reply.first.then(replyHandler);
}
void queryBalance(handleBalance(int balance)) {
purse_.call([ "balance" ]).then((var message) {
int balance = message;
handleBalance(balance);
});
_sendReceive("balance", handleBalance);
}
void sproutPurse(handleSprouted(PurseWrapper sprouted)) {
purse_.call([ "sprout" ]).then((var message) {
SendPort sprouted = message[0];
_sendReceive("sprout", (SendPort sprouted) {
handleSprouted(new PurseWrapper(sprouted));
});
}
void deposit(PurseWrapper source, int amount) {
purse_.send([ "deposit", amount, source.purse_ ], null);
_purse.send([ "deposit", amount, source._purse ]);
}
SendPort purse_;
}
// AUTO END
// AUTO STATUS UNCLEAR!
mintMakerWrapper() {
port.receive((var message, SendPort replyTo) {
mintMakerWrapper(SendPort replyPort) {
ReceivePort receiver = new ReceivePort();
replyPort.send(receiver.sendPort);
receiver.listen((SendPort replyTo) {
Mint mint = new Mint();
replyTo.send([ mint.port ], null);
replyTo.send(mint.port);
});
}
class MintMakerWrapper {
MintMakerWrapper() {
port_ = spawnFunction(mintMakerWrapper);
final SendPort _port;
static Future<MintMakerWrapper> create() {
ReceivePort reply = new ReceivePort();
return Isolate.spawn(mintMakerWrapper, reply.sendPort).then((_) =>
reply.first.then((port) => new MintMakerWrapper._(port)));
}
MintMakerWrapper._(this._port);
void makeMint(handleMint(MintWrapper mint)) {
port_.call(null).then((var message) {
SendPort mint = message[0];
handleMint(new MintWrapper(mint));
});
ReceivePort reply = new ReceivePort();
reply.first.then((SendPort mint) { handleMint(new MintWrapper(mint)); });
_port.send(reply.sendPort);
}
SendPort port_;
}
_checkBalance(PurseWrapper wrapper, expected) {
@ -192,70 +155,24 @@ _checkBalance(PurseWrapper wrapper, expected) {
main() {
test("creating purse, deposit, and query balance", () {
MintMakerWrapper mintMaker = new MintMakerWrapper();
mintMaker.makeMint(expectAsync1((MintWrapper mint) {
mint.createPurse(100, expectAsync1((PurseWrapper purse) {
_checkBalance(purse, 100);
purse.sproutPurse(expectAsync1((PurseWrapper sprouted) {
_checkBalance(sprouted, 0);
MintMakerWrapper.create().then(expectAsync1((mintMaker) {
mintMaker.makeMint(expectAsync1((MintWrapper mint) {
mint.createPurse(100, expectAsync1((PurseWrapper purse) {
_checkBalance(purse, 100);
purse.sproutPurse(expectAsync1((PurseWrapper sprouted) {
_checkBalance(sprouted, 0);
_checkBalance(purse, 100);
sprouted.deposit(purse, 5);
_checkBalance(sprouted, 0 + 5);
_checkBalance(purse, 100 - 5);
sprouted.deposit(purse, 5);
_checkBalance(sprouted, 0 + 5);
_checkBalance(purse, 100 - 5);
sprouted.deposit(purse, 42);
_checkBalance(sprouted, 0 + 5 + 42);
_checkBalance(purse, 100 - 5 - 42);
sprouted.deposit(purse, 42);
_checkBalance(sprouted, 0 + 5 + 42);
_checkBalance(purse, 100 - 5 - 42);
}));
}));
}));
}));
});
/* This is an attempt to show how the above code could look like if we had
* better language support for asynchronous messages (deferred/asynccall).
* The static helper methods like createPurse and queryBalance would also
* have to be marked async.
void run(port) {
MintMakerWrapper mintMaker = spawnMintMaker();
deferred {
MintWrapper mint = asynccall mintMaker.createMint();
PurseWrapper purse = asynccall mint.createPurse(100);
expect(asynccall purse.queryBalance(), 100);
PurseWrapper sprouted = asynccall purse.sproutPurse();
expect(asynccall sprouted.queryBalance(), 0);
asynccall sprouted.deposit(purse, 5);
expect(asynccall sprouted.queryBalance(), 0 + 5);
expect(asynccall purse.queryBalance(), 100 - 5);
asynccall sprouted.deposit(purse, 42);
expect(asynccall sprouted.queryBalance(), 0 + 5 + 42);
expect(asynccall purse.queryBalance(), 100 - 5 - 42);
}
}
*/
/* And a version using futures and wrappers.
void run(port) {
Wrapper<MintMaker> mintMaker = spawnMintMaker();
Future<Mint> mint = mintMaker...createMint();
Future<Purse> purse = mint...createPurse(100);
expect(purse.queryBalance(), 100);
Future<Purse> sprouted = purse...sproutPurse();
expect(0, sprouted.queryBalance());
sprouted...deposit(purse, 5);
expect(sprouted.queryBalance(), 0 + 5);
expect(purse.queryBalance(), 100 - 5);
sprouted...deposit(purse, 42);
expect(sprouted.queryBalance(), 0 + 5 + 42);
expect(purse.queryBalance(), 100 - 5 - 42);
}
*/
}

Some files were not shown because too many files have changed in this diff Show more