3dced243b3
- Find main in the exported names of the root library. - Unify how the main function is called from spawnUri and the initial isolate. Review URL: https://codereview.chromium.org//48713013 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@29865 260f80e4-7a28-3924-810f-c04153c831b5
251 lines
7.4 KiB
Dart
251 lines
7.4 KiB
Dart
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
patch class ReceivePort {
|
|
/* 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 extends Stream implements ReceivePort {
|
|
_ReceivePortImpl() : this.fromRawReceivePort(new RawReceivePort());
|
|
|
|
_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 get sendPort {
|
|
return new _SendPortImpl(_id);
|
|
}
|
|
|
|
/**** Internal implementation details ****/
|
|
// 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 _RawReceivePortImpl._internal(id);
|
|
}
|
|
|
|
_RawReceivePortImpl._internal(int id) : _id = id {
|
|
_portMap[id] = this;
|
|
}
|
|
|
|
// 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(
|
|
_RawReceivePortImpl port, int replyId, var message) {
|
|
assert(port != null);
|
|
port._handler(message);
|
|
}
|
|
|
|
// Call into the VM to close the VM maintained mappings.
|
|
static _closeInternal(int id) native "RawReceivePortImpl_closeInternal";
|
|
|
|
void set handler(Function newHandler) {
|
|
this._handler = newHandler;
|
|
}
|
|
|
|
final int _id;
|
|
Function _handler;
|
|
|
|
// id to RawReceivePort mapping.
|
|
static final Map _portMap = new HashMap();
|
|
}
|
|
|
|
|
|
class _SendPortImpl implements SendPort {
|
|
/*--- public interface ---*/
|
|
void send(var message) {
|
|
_sendInternal(_id, 0, message);
|
|
}
|
|
|
|
bool operator==(var other) {
|
|
return (other is _SendPortImpl) && _id == other._id;
|
|
}
|
|
|
|
int get hashCode {
|
|
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 ---*/
|
|
const _SendPortImpl(int id) : _id = id;
|
|
|
|
// _SendPortImpl._create is called from the VM when a new SendPort instance is
|
|
// needed by the VM code.
|
|
static SendPort _create(int id) {
|
|
return new _SendPortImpl(id);
|
|
}
|
|
|
|
// Forward the implementation of sending messages to the VM. Only port ids
|
|
// are being handed to the VM.
|
|
// TODO(14731): Remove replyId argument.
|
|
static _sendInternal(int sendId, int replyId, var message)
|
|
native "SendPortImpl_sendInternal_";
|
|
|
|
final int _id;
|
|
}
|
|
|
|
typedef _MainFunction();
|
|
typedef _MainFunctionArgs(args);
|
|
typedef _MainFunctionArgsMessage(args, message);
|
|
|
|
/**
|
|
* Takes the real entry point as argument and invokes it with the initial
|
|
* message.
|
|
*
|
|
* The initial startup message is received through the control port.
|
|
*/
|
|
void _startIsolate(Function entryPoint, bool isSpawnUri) {
|
|
// This port keeps the isolate alive until the initial startup message has
|
|
// been received.
|
|
var keepAlivePort = new RawReceivePort();
|
|
|
|
ignoreHandler(message) {
|
|
// Messages on the current Isolate's control port are dropped after the
|
|
// initial startup message has been received.
|
|
}
|
|
|
|
isolateStartHandler(message) {
|
|
// We received the initial startup message. Ignore all further messages and
|
|
// close the port which kept this isolate alive.
|
|
Isolate._self.handler = ignoreHandler;
|
|
keepAlivePort.close();
|
|
|
|
SendPort replyTo = message[0];
|
|
if (replyTo != null) {
|
|
// 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);
|
|
}
|
|
}
|
|
|
|
Isolate._self.handler = isolateStartHandler;
|
|
}
|
|
|
|
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(14718): we want errors to go into the returned future.
|
|
rethrow;
|
|
};
|
|
return completer.future;
|
|
}
|
|
|
|
/* 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.toString());
|
|
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(14718): we want errors to go into the returned future.
|
|
rethrow;
|
|
};
|
|
return completer.future;
|
|
}
|
|
|
|
static final RawReceivePort _self = _mainPort;
|
|
static RawReceivePort get _mainPort native "Isolate_mainPort";
|
|
|
|
static SendPort _spawnFunction(Function topLevelFunction)
|
|
native "Isolate_spawnFunction";
|
|
|
|
static SendPort _spawnUri(String uri) native "Isolate_spawnUri";
|
|
}
|