mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 16:41:07 +00:00
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:
parent
d66aab045d
commit
6a72655d1b
|
@ -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", () {
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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', () {
|
||||
|
|
|
@ -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", () {
|
||||
|
|
|
@ -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 "
|
||||
|
|
|
@ -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.';
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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", () {
|
||||
|
|
|
@ -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", () {
|
||||
|
|
|
@ -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 "
|
||||
|
|
|
@ -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 '
|
||||
|
|
|
@ -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 '
|
||||
|
|
|
@ -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', () {
|
||||
|
|
|
@ -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 "
|
||||
|
|
|
@ -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', () {
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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 "
|
||||
|
|
|
@ -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', () {
|
||||
|
|
|
@ -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 '
|
||||
|
|
|
@ -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 '
|
||||
|
|
|
@ -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 "
|
||||
|
|
|
@ -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 "
|
||||
|
|
|
@ -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', () {
|
||||
|
|
|
@ -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', () {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
|
|
@ -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'));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
});
|
||||
}
|
|
@ -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);
|
||||
});
|
||||
|
||||
}
|
|
@ -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';
|
||||
}
|
|
@ -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");
|
||||
});
|
||||
|
||||
}
|
|
@ -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) \
|
||||
|
|
|
@ -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";
|
||||
|
||||
|
|
|
@ -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()));
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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") \
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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']));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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$"))));
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -29269,6 +29269,8 @@ class _JsDeserializer extends _Deserializer {
|
|||
}
|
||||
}
|
||||
|
||||
class SendPortSync {}
|
||||
|
||||
// The receiver is JS.
|
||||
class _JsSendPortSync implements SendPortSync {
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
||||
|
|
|
@ -6,6 +6,6 @@ part of dart.io;
|
|||
|
||||
class _EventHandler {
|
||||
external static void _sendData(Object sender,
|
||||
ReceivePort receivePort,
|
||||
RawReceivePort receivePort,
|
||||
int data);
|
||||
}
|
||||
|
|
|
@ -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(); });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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: '
|
||||
|
|
|
@ -6,6 +6,5 @@
|
|||
'sources': [
|
||||
'isolate.dart',
|
||||
# The above file needs to be first as it lists the parts below.
|
||||
'isolate_stream.dart',
|
||||
],
|
||||
}
|
||||
|
|
|
@ -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)]);
|
|
@ -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
|
||||
|
|
|
@ -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 ###
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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'));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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'))));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
}
|
|
@ -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]);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
}
|
|
@ -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();
|
||||
});
|
||||
}
|
|
@ -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"; });
|
||||
}
|
|
@ -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"; });
|
||||
}
|
|
@ -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();
|
||||
});
|
||||
}
|
|
@ -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();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
}
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
}));
|
||||
});
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
});
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}));
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}));
|
||||
});
|
||||
}
|
|
@ -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++;
|
||||
});
|
||||
});
|
||||
}
|
|
@ -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);
|
||||
}));
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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
Loading…
Reference in a new issue