Chromium Code Reviews| Index: sdk/lib/isolate/isolate.dart |
| diff --git a/sdk/lib/isolate/isolate.dart b/sdk/lib/isolate/isolate.dart |
| index 3cfc4fc3b8849e3ed11893c2d83301252d6cfd75..4fac17b1c33e9bbc824cd364e9b3d22dbf09a622 100644 |
| --- a/sdk/lib/isolate/isolate.dart |
| +++ b/sdk/lib/isolate/isolate.dart |
| @@ -16,8 +16,9 @@ library dart.isolate; |
| import "dart:async"; |
| -part "isolate_stream.dart"; |
| - |
| +/** |
| + * Thrown when an isolate cannot be created. |
| + */ |
| class IsolateSpawnException implements Exception { |
| const IsolateSpawnException(String this._s); |
| String toString() => "IsolateSpawnException: '$_s'"; |
| @@ -25,52 +26,140 @@ class IsolateSpawnException implements Exception { |
| } |
| /** |
| - * The initial ReceivePort available by default for this isolate. |
| + * This class should be part of dart:isolate. |
| * |
| - * This ReceivePort is created automatically |
| - * and is commonly used to establish |
| - * the first communication between isolates. |
| - * (See [spawnFunction] and [spawnUri].) |
| + * A capability is unique among all isolates and can be shared with |
| + * other isolates. |
|
Søren Gjesse
2013/09/27 07:04:11
Maybe say that instances of Capability are opaque
floitsch
2013/10/12 17:04:38
Done.
|
| */ |
| -ReceivePort get port => _Isolate.port; |
| +class Capability { |
| +} |
| /** |
| - * Creates and spawns an isolate |
| - * that shares the same code as the current isolate, |
| - * but that starts from the specified function. |
| + * An enum that enumeratos permissions that are required to control isolates. |
| * |
| - * 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. |
| + * Some control messages require capabilities to be accepted by the isolate. |
| + * The [Permission] enum gives these capabilities names. |
| */ |
| -SendPort spawnFunction(void topLevelFunction(), |
| - [bool unhandledExceptionCallback(IsolateUnhandledException e)]) |
| - => _Isolate.spawnFunction(topLevelFunction, unhandledExceptionCallback); |
| +class Permission { |
|
kasperl
2013/09/27 07:42:19
Not sure you're going to need this class. It feels
floitsch
2013/10/12 17:04:38
Yes, but I think there will be many Permissions.
|
| + final Symbol _permission; |
| + const Permission(this._permission); |
| + |
|
Søren Gjesse
2013/09/27 07:04:11
FULL_CONTROL premission?
floitsch
2013/10/12 17:04:38
Done.
|
| + // Mirror-modify basically allows everything, since we can just modify the |
| + // program to our liking. |
| + static const MIRROR_MODIFY = const Permission(#mirror_modify); |
| + static const MIRROR_INSPECT = const Permission(#mirror_inspect); |
| + static const SHUTDOWN = const Permission(#shutdown); |
| + // Allows to control resources (maybe even giving more than usual?). |
| + static const RESOURCE = const Permission(#resource); |
| +} |
| + |
| +class Isolate { |
| + /** |
| + * 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 illegal to pass a function closure. |
| + * |
| + * The entryPoint 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. |
| + */ |
| + static Future<Isolate> spawn(void entryPoint(message), var message, |
| + { startPaused, or, other, Arguments, we, will, find, useful }) { |
| + } |
| + |
| + /** |
| + * Creates and spawns an isolate that runs the code from the specified URI. |
| + * |
| + * The entry point of the spawned isolate is automatically set to |
| + * `main`. Otherwise similar to [spawn]. |
|
Søren Gjesse
2013/09/27 07:04:11
How about the arguments here vs. message above can
floitsch
2013/10/12 17:04:38
Yes. It is crucial to be able to send Sendports.
|
| + */ |
| + static Future<Isolate> spawnUri(Uri uri, var arguments, { named, args }) { |
| + |
| + } |
| + |
| + /** |
| + * Creates a new isolate instance controlling an existing isolate. |
| + * |
| + * The new instance controls the isolate that is controlled by the |
| + * argument [controlPort]. |
| + * |
| + * The given [permissions] map specifies what the returned instance can |
| + * do with the existing isolate. |
| + */ |
| + Isolate.fromControlPort(SendPort controlPort, |
| + Map<Permission, Capability> permissions) |
| + : _permissions = permissions, |
| + controlPort = controlPort; |
| + |
| + /** |
| + * Listening to this stream will install an error handler on the isolate. |
| + * |
| + * The installation of the error handler is an asynchronous operation. |
| + * If one wants to be sure to see all errors, one should start the isolate in |
| + * a paused state, start listening to the errors, and then only resume the |
| + * other isolate. |
| + */ |
| + Stream uncaughtErrors; |
| + |
| + /** |
| + * Pauses the isolate. |
|
Søren Gjesse
2013/09/27 07:04:11
How immediate is this pause? Pause when returning
floitsch
2013/10/12 17:04:38
There will be different ways to pause: either at t
|
| + */ |
| + Future pause() {} |
| + |
| + /** |
| + * Resumes the isolate. |
| + */ |
| + Future resume() {} |
| + |
| + Future kill() { |
|
Søren Gjesse
2013/09/27 07:04:11
Should there be a optional Capability argument to
floitsch
2013/10/12 17:04:38
Interesting idea. I will think about it.
|
| + // Proposed implementation: |
| + return controlPort.call([_someInternalObjectIdentifyingKillAction, |
| + _permissions[Permission.SHUTDOWN]]); |
| + } |
| + |
| + /** |
| + * Since this is an asynchronous operation the state might change before |
| + * we get a chance to act on it (if someone else has the capability to |
| + * resume the isolate). |
| + */ |
| + Future<bool> queryIsPaused() {} |
| + |
| + /// This id uniquely identifies the spawned isolate. |
|
Søren Gjesse
2013/09/27 07:04:11
"This id"?
floitsch
2013/10/12 17:04:38
Old comment. Updated.
|
| + final SendPort controlPort; |
|
Søren Gjesse
2013/09/27 07:04:11
I assume corresponding receive port is not directl
floitsch
2013/10/12 17:04:38
Correct.
|
| + |
| + final Map<Permission, Capability> _permissions; |
| + |
| + /** |
| + * Clones this Isolate but with limited permissions. |
|
Søren Gjesse
2013/09/27 07:04:11
By "clone" don't you mean just making a new refere
floitsch
2013/10/12 17:04:38
Correct.
|
| + * |
| + * When handing out isolates, one should always |
| + */ |
| + Map<Permission, Capability> extractPermissions( |
| + Iterable<Permission> permissions) { |
| + } |
| +} |
| /** |
| - * 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. |
| + * When a SendPort sends a message to a ReceivePort the receiving end receives |
| + * an instance of this class. |
| */ |
| -SendPort spawnUri(String uri) => _Isolate.spawnUri(uri); |
| +class IsolateMessage { |
|
kasperl
2013/09/27 07:42:19
I'm not too keen on wrapping all messages in new o
Ivan Posva
2013/09/30 02:59:41
Agree with Kasper, no extra wrapping.
floitsch
2013/10/12 17:04:38
Done.
|
| + final message; |
| + final SendPort replyPort; |
| + final SendPort sourceIsolate; // should we have this? |
| + |
| + void reply(msg, { replyTo }) { |
| + if (replyPort != null) replyPort.send(msg, replyTo: replyTo); |
| + } |
| + |
| + IsolateMessage._(this.message, this.replyPort, this.sourceIsolate); |
| +} |
| /** |
| - * 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 |
| @@ -99,7 +188,7 @@ abstract class SendPort { |
| * message. Previously they were translated to the corresponding send port |
| * before being transmitted. |
| */ |
| - void send(var message, [SendPort replyTo]); |
| + void send(var message, { SendPort replyTo }); |
|
kasperl
2013/09/27 07:42:19
I think we should drop the replyTo argument (and l
Ivan Posva
2013/09/30 02:59:41
I do not see how the replyTo port is accessed on t
floitsch
2013/10/12 17:04:38
It would have been in the IsolateMessage.
But gone
|
| /** |
| * Sends a message to this send port and returns a [Future] of the reply. |
| @@ -107,6 +196,8 @@ abstract class SendPort { |
| * 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. |
| + * |
| + * The [Future] extracts the message from the [IsolateMessage]. |
|
kasperl
2013/09/27 07:42:19
I don't like IsolateMessage in this context either
floitsch
2013/10/12 17:04:38
call is gone.
|
| */ |
| Future call(var message); |
| @@ -128,14 +219,19 @@ abstract class SendPort { |
| * Together with [SendPort], the only means of |
| * communication between isolates. |
| * |
| - * [ReceivePort]s have a [:toSendPort:] method |
| + * [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, they are |
| * dispatched to the callback that has been registered on the receive port. |
| * |
| * A [ReceivePort] may have many [SendPort]s. |
| */ |
| -abstract class ReceivePort { |
| +// TODO(floitsch): should the ReceivePort be a broadcast stream or not? |
| +// Broadcast stream: allows multiple listeners. May drop messages if nobody |
| +// is listening. |
| +// Non broadcast stream: one listener only. Buffers messages is nobody listens. |
| +// I vote for non-broadcast. |
|
kasperl
2013/09/27 07:42:19
Non-broadcast gives us the option to add broadcast
floitsch
2013/10/12 17:04:38
Non-broadcast it is.
|
| +abstract class ReceivePort implements Stream<IsolateMessage> { |
| /** |
| * Opens a long-lived port for receiving messages. The returned port |
| @@ -144,10 +240,13 @@ abstract class ReceivePort { |
| external factory ReceivePort(); |
| /** |
| - * Sets up a callback function for receiving pending or future |
| - * messages on this receive port. |
| + * Inherited from [Stream]. |
| */ |
| - void receive(void callback(var message, SendPort replyTo)); |
| + StreamSubscription<IsolateMessage> listen( |
| + void callback(IsolateMessage message), |
| + { void onError(e) , |
| + void onDone(), |
| + bool cancelOnError }); |
| /** |
| * Closes this receive port immediately. Pending messages will not |
| @@ -159,11 +258,9 @@ abstract class ReceivePort { |
| 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; |
| } |
| /** |
| @@ -207,6 +304,7 @@ abstract class _Isolate { |
| * used to show both the error message and the stack trace for unhandled |
| * exceptions. |
| */ |
| +// TODO(floitsch): probably going to remove and replace with something else. |
| class IsolateUnhandledException implements Exception { |
| /** Message being handled when exception occurred. */ |
| final message; |