OLD | NEW |
---|---|
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * Concurrent programming using _isolates_: | 6 * Concurrent programming using _isolates_: |
7 * independent workers that are similar to threads | 7 * independent workers that are similar to threads |
8 * but don't share memory, | 8 * but don't share memory, |
9 * communicating only via messages. | 9 * communicating only via messages. |
10 * | 10 * |
11 * See also: | 11 * See also: |
12 * [dart:isolate - Concurrency with Isolates](https://www.dartlang.org/docs/dart -up-and-running/contents/ch03.html#ch03-dartisolate---concurrency-with-isolates) | 12 * [dart:isolate - Concurrency with Isolates](https://www.dartlang.org/docs/dart -up-and-running/contents/ch03.html#ch03-dartisolate---concurrency-with-isolates) |
13 * in the library tour. | 13 * in the library tour. |
14 */ | 14 */ |
15 library dart.isolate; | 15 library dart.isolate; |
16 | 16 |
17 import "dart:async"; | 17 import "dart:async"; |
18 | 18 |
19 part "isolate_stream.dart"; | 19 /** |
20 | 20 * Thrown when an isolate cannot be created. |
21 */ | |
21 class IsolateSpawnException implements Exception { | 22 class IsolateSpawnException implements Exception { |
22 const IsolateSpawnException(String this._s); | 23 const IsolateSpawnException(String this._s); |
23 String toString() => "IsolateSpawnException: '$_s'"; | 24 String toString() => "IsolateSpawnException: '$_s'"; |
24 final String _s; | 25 final String _s; |
25 } | 26 } |
26 | 27 |
27 /** | 28 /** |
28 * The initial ReceivePort available by default for this isolate. | 29 * This class should be part of dart:isolate. |
29 * | 30 * |
30 * This ReceivePort is created automatically | 31 * A capability is unique among all isolates and can be shared with |
31 * and is commonly used to establish | 32 * 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.
| |
32 * the first communication between isolates. | |
33 * (See [spawnFunction] and [spawnUri].) | |
34 */ | 33 */ |
35 ReceivePort get port => _Isolate.port; | 34 class Capability { |
35 } | |
36 | 36 |
37 /** | 37 /** |
38 * Creates and spawns an isolate | 38 * An enum that enumeratos permissions that are required to control isolates. |
39 * that shares the same code as the current isolate, | |
40 * but that starts from the specified function. | |
41 * | 39 * |
42 * The [topLevelFunction] argument must be | 40 * Some control messages require capabilities to be accepted by the isolate. |
43 * a static top-level function or a static method that takes no | 41 * The [Permission] enum gives these capabilities names. |
44 * arguments. It is illegal to pass a function closure. | |
45 * | |
46 * When any isolate starts (even the main script of the application), a default | |
47 * [ReceivePort] is created for it. This port is available from the top-level | |
48 * getter [port] defined in this library. | |
49 * | |
50 * This function returns a [SendPort] derived from | |
51 * the child isolate's default port. | |
52 * | |
53 * The optional [unhandledExceptionCallback] argument is invoked whenever an | |
54 * exception inside the isolate is unhandled. It can be seen as a big | |
55 * `try/catch` around everything that is executed inside the isolate. The | |
56 * callback should return `true` if it was able to handle the exception. | |
57 */ | 42 */ |
58 SendPort spawnFunction(void topLevelFunction(), | 43 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.
| |
59 [bool unhandledExceptionCallback(IsolateUnhandledException e)]) | 44 final Symbol _permission; |
60 => _Isolate.spawnFunction(topLevelFunction, unhandledExceptionCallback); | 45 const Permission(this._permission); |
46 | |
Søren Gjesse
2013/09/27 07:04:11
FULL_CONTROL premission?
floitsch
2013/10/12 17:04:38
Done.
| |
47 // Mirror-modify basically allows everything, since we can just modify the | |
48 // program to our liking. | |
49 static const MIRROR_MODIFY = const Permission(#mirror_modify); | |
50 static const MIRROR_INSPECT = const Permission(#mirror_inspect); | |
51 static const SHUTDOWN = const Permission(#shutdown); | |
52 // Allows to control resources (maybe even giving more than usual?). | |
53 static const RESOURCE = const Permission(#resource); | |
54 } | |
55 | |
56 class Isolate { | |
57 /** | |
58 * Creates and spawns an isolate that shares the same code as the current | |
59 * isolate. | |
60 * | |
61 * The argument [entryPoint] specifies the entry point of the spawned | |
62 * isolate. It must be a static top-level function or a static method that | |
63 * takes no arguments. It is illegal to pass a function closure. | |
64 * | |
65 * The entryPoint function is invoked with the initial [message]. | |
66 * Usually the initial [message] contains a [SendPort] so | |
67 * that the spawner and spawnee can communicate with each other. | |
68 */ | |
69 static Future<Isolate> spawn(void entryPoint(message), var message, | |
70 { startPaused, or, other, Arguments, we, will, find, useful }) { | |
71 } | |
72 | |
73 /** | |
74 * Creates and spawns an isolate that runs the code from the specified URI. | |
75 * | |
76 * The entry point of the spawned isolate is automatically set to | |
77 * `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.
| |
78 */ | |
79 static Future<Isolate> spawnUri(Uri uri, var arguments, { named, args }) { | |
80 | |
81 } | |
82 | |
83 /** | |
84 * Creates a new isolate instance controlling an existing isolate. | |
85 * | |
86 * The new instance controls the isolate that is controlled by the | |
87 * argument [controlPort]. | |
88 * | |
89 * The given [permissions] map specifies what the returned instance can | |
90 * do with the existing isolate. | |
91 */ | |
92 Isolate.fromControlPort(SendPort controlPort, | |
93 Map<Permission, Capability> permissions) | |
94 : _permissions = permissions, | |
95 controlPort = controlPort; | |
96 | |
97 /** | |
98 * Listening to this stream will install an error handler on the isolate. | |
99 * | |
100 * The installation of the error handler is an asynchronous operation. | |
101 * If one wants to be sure to see all errors, one should start the isolate in | |
102 * a paused state, start listening to the errors, and then only resume the | |
103 * other isolate. | |
104 */ | |
105 Stream uncaughtErrors; | |
106 | |
107 /** | |
108 * 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
| |
109 */ | |
110 Future pause() {} | |
111 | |
112 /** | |
113 * Resumes the isolate. | |
114 */ | |
115 Future resume() {} | |
116 | |
117 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.
| |
118 // Proposed implementation: | |
119 return controlPort.call([_someInternalObjectIdentifyingKillAction, | |
120 _permissions[Permission.SHUTDOWN]]); | |
121 } | |
122 | |
123 /** | |
124 * Since this is an asynchronous operation the state might change before | |
125 * we get a chance to act on it (if someone else has the capability to | |
126 * resume the isolate). | |
127 */ | |
128 Future<bool> queryIsPaused() {} | |
129 | |
130 /// 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.
| |
131 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.
| |
132 | |
133 final Map<Permission, Capability> _permissions; | |
134 | |
135 /** | |
136 * 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.
| |
137 * | |
138 * When handing out isolates, one should always | |
139 */ | |
140 Map<Permission, Capability> extractPermissions( | |
141 Iterable<Permission> permissions) { | |
142 } | |
143 } | |
61 | 144 |
62 /** | 145 /** |
63 * Creates and spawns an isolate that runs the code from the specified URI. | 146 * When a SendPort sends a message to a ReceivePort the receiving end receives |
64 * | 147 * an instance of this class. |
65 * As with [spawnFunction], | |
66 * the child isolate has a default [ReceivePort], | |
67 * and this function returns a [SendPort] derived from it. | |
68 */ | 148 */ |
69 SendPort spawnUri(String uri) => _Isolate.spawnUri(uri); | 149 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.
| |
150 final message; | |
151 final SendPort replyPort; | |
152 final SendPort sourceIsolate; // should we have this? | |
153 | |
154 void reply(msg, { replyTo }) { | |
155 if (replyPort != null) replyPort.send(msg, replyTo: replyTo); | |
156 } | |
157 | |
158 IsolateMessage._(this.message, this.replyPort, this.sourceIsolate); | |
159 } | |
70 | 160 |
71 /** | 161 /** |
72 * Together with [ReceivePort], | 162 * Sends messages to its [ReceivePort]s. |
73 * the only means of communication between isolates. | |
74 * | 163 * |
75 * [SendPort]s are created from [ReceivePort]s. Any message sent through | 164 * [SendPort]s are created from [ReceivePort]s. Any message sent through |
76 * a [SendPort] is delivered to its respective [ReceivePort]. There might be | 165 * a [SendPort] is delivered to its respective [ReceivePort]. There might be |
77 * many [SendPort]s for the same [ReceivePort]. | 166 * many [SendPort]s for the same [ReceivePort]. |
78 * | 167 * |
79 * [SendPort]s can be transmitted to other isolates. | 168 * [SendPort]s can be transmitted to other isolates. |
80 */ | 169 */ |
81 abstract class SendPort { | 170 abstract class SendPort { |
82 | 171 |
83 /** | 172 /** |
84 * Sends an asynchronous [message] to this send port. The message is copied to | 173 * Sends an asynchronous [message] to this send port. The message is copied to |
85 * the receiving isolate. If specified, the [replyTo] port will be provided to | 174 * the receiving isolate. If specified, the [replyTo] port will be provided to |
86 * the receiver to facilitate exchanging sequences of messages. | 175 * the receiver to facilitate exchanging sequences of messages. |
87 * | 176 * |
88 * The content of [message] can be: primitive values (null, num, bool, double, | 177 * The content of [message] can be: primitive values (null, num, bool, double, |
89 * String), instances of [SendPort], and lists and maps whose elements are any | 178 * String), instances of [SendPort], and lists and maps whose elements are any |
90 * of these. List and maps are also allowed to be cyclic. | 179 * of these. List and maps are also allowed to be cyclic. |
91 * | 180 * |
92 * In the special circumstances when two isolates share the same code and are | 181 * In the special circumstances when two isolates share the same code and are |
93 * running in the same process (e.g. isolates created via [spawnFunction]), it | 182 * running in the same process (e.g. isolates created via [spawnFunction]), it |
94 * is also possible to send object instances (which would be copied in the | 183 * is also possible to send object instances (which would be copied in the |
95 * process). This is currently only supported by the dartvm. For now, the | 184 * process). This is currently only supported by the dartvm. For now, the |
96 * dart2js compiler only supports the restricted messages described above. | 185 * dart2js compiler only supports the restricted messages described above. |
97 * | 186 * |
98 * Deprecation note: it is no longer valid to transmit a [ReceivePort] in a | 187 * Deprecation note: it is no longer valid to transmit a [ReceivePort] in a |
99 * message. Previously they were translated to the corresponding send port | 188 * message. Previously they were translated to the corresponding send port |
100 * before being transmitted. | 189 * before being transmitted. |
101 */ | 190 */ |
102 void send(var message, [SendPort replyTo]); | 191 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
| |
103 | 192 |
104 /** | 193 /** |
105 * Sends a message to this send port and returns a [Future] of the reply. | 194 * Sends a message to this send port and returns a [Future] of the reply. |
106 * Basically, this internally creates a new receive port, sends a | 195 * Basically, this internally creates a new receive port, sends a |
Ivan Posva
2013/09/30 02:59:41
This internal description is too detailed and we a
floitsch
2013/10/12 17:04:38
call is gone.
| |
107 * message to this send port with replyTo set to such receive port, and, when | 196 * message to this send port with replyTo set to such receive port, and, when |
108 * a reply is received, it closes the receive port and completes the returned | 197 * a reply is received, it closes the receive port and completes the returned |
109 * future. | 198 * future. |
199 * | |
200 * 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.
| |
110 */ | 201 */ |
111 Future call(var message); | 202 Future call(var message); |
112 | 203 |
113 /** | 204 /** |
114 * Tests whether [other] is a [SendPort] pointing to the same | 205 * Tests whether [other] is a [SendPort] pointing to the same |
115 * [ReceivePort] as this one. | 206 * [ReceivePort] as this one. |
116 */ | 207 */ |
117 bool operator==(var other); | 208 bool operator==(var other); |
118 | 209 |
119 /** | 210 /** |
120 * Returns an immutable hash code for this send port that is | 211 * Returns an immutable hash code for this send port that is |
121 * consistent with the == operator. | 212 * consistent with the == operator. |
122 */ | 213 */ |
123 int get hashCode; | 214 int get hashCode; |
124 | 215 |
125 } | 216 } |
126 | 217 |
127 /** | 218 /** |
128 * Together with [SendPort], the only means of | 219 * Together with [SendPort], the only means of |
129 * communication between isolates. | 220 * communication between isolates. |
130 * | 221 * |
131 * [ReceivePort]s have a [:toSendPort:] method | 222 * [ReceivePort]s have a `sendport` getter |
132 * which returns a [SendPort]. Any message that is sent through this [SendPort] | 223 * which returns a [SendPort]. Any message that is sent through this [SendPort] |
133 * is delivered to the [ReceivePort] it has been created from. There, they are | 224 * is delivered to the [ReceivePort] it has been created from. There, they are |
134 * dispatched to the callback that has been registered on the receive port. | 225 * dispatched to the callback that has been registered on the receive port. |
135 * | 226 * |
136 * A [ReceivePort] may have many [SendPort]s. | 227 * A [ReceivePort] may have many [SendPort]s. |
137 */ | 228 */ |
138 abstract class ReceivePort { | 229 // TODO(floitsch): should the ReceivePort be a broadcast stream or not? |
230 // Broadcast stream: allows multiple listeners. May drop messages if nobody | |
231 // is listening. | |
232 // Non broadcast stream: one listener only. Buffers messages is nobody listens. | |
233 // 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.
| |
234 abstract class ReceivePort implements Stream<IsolateMessage> { | |
139 | 235 |
140 /** | 236 /** |
141 * Opens a long-lived port for receiving messages. The returned port | 237 * Opens a long-lived port for receiving messages. The returned port |
142 * must be explicitly closed through [ReceivePort.close]. | 238 * must be explicitly closed through [ReceivePort.close]. |
143 */ | 239 */ |
144 external factory ReceivePort(); | 240 external factory ReceivePort(); |
145 | 241 |
146 /** | 242 /** |
147 * Sets up a callback function for receiving pending or future | 243 * Inherited from [Stream]. |
148 * messages on this receive port. | |
149 */ | 244 */ |
150 void receive(void callback(var message, SendPort replyTo)); | 245 StreamSubscription<IsolateMessage> listen( |
246 void callback(IsolateMessage message), | |
247 { void onError(e) , | |
248 void onDone(), | |
249 bool cancelOnError }); | |
151 | 250 |
152 /** | 251 /** |
153 * Closes this receive port immediately. Pending messages will not | 252 * Closes this receive port immediately. Pending messages will not |
154 * be processed and it is impossible to re-open the port. Single-shot | 253 * be processed and it is impossible to re-open the port. Single-shot |
155 * reply ports, such as those created through [SendPort.call], are | 254 * reply ports, such as those created through [SendPort.call], are |
156 * automatically closed when the reply has been received. Multiple | 255 * automatically closed when the reply has been received. Multiple |
157 * invocations of [close] are allowed but ignored. | 256 * invocations of [close] are allowed but ignored. |
158 */ | 257 */ |
159 void close(); | 258 void close(); |
160 | 259 |
161 /** | 260 /** |
162 * Creates a new send port that sends to this receive port. It is legal to | 261 * Returns a send port that sends to this receive port. |
163 * create several [SendPort]s from the same [ReceivePort]. | |
164 */ | 262 */ |
165 SendPort toSendPort(); | 263 SendPort get sendPort; |
166 | |
167 } | 264 } |
168 | 265 |
169 /** | 266 /** |
170 * [SendPortSync]s are created from [ReceivePortSync]s. Any message sent through | 267 * [SendPortSync]s are created from [ReceivePortSync]s. Any message sent through |
171 * a [SendPortSync] is delivered to its respective [ReceivePortSync]. There | 268 * a [SendPortSync] is delivered to its respective [ReceivePortSync]. There |
172 * might be many [SendPortSync]s for the same [ReceivePortSync]. | 269 * might be many [SendPortSync]s for the same [ReceivePortSync]. |
173 * | 270 * |
174 * [SendPortSync]s can be transmitted to other isolates. | 271 * [SendPortSync]s can be transmitted to other isolates. |
175 */ | 272 */ |
176 abstract class SendPortSync { | 273 abstract class SendPortSync { |
(...skipping 23 matching lines...) Expand all Loading... | |
200 external static SendPort spawnFunction(void topLevelFunction(), | 297 external static SendPort spawnFunction(void topLevelFunction(), |
201 [bool unhandledExceptionCallback(IsolateUnhandledException e)]); | 298 [bool unhandledExceptionCallback(IsolateUnhandledException e)]); |
202 external static SendPort spawnUri(String uri); | 299 external static SendPort spawnUri(String uri); |
203 } | 300 } |
204 | 301 |
205 /** | 302 /** |
206 * Wraps unhandled exceptions thrown during isolate execution. It is | 303 * Wraps unhandled exceptions thrown during isolate execution. It is |
207 * used to show both the error message and the stack trace for unhandled | 304 * used to show both the error message and the stack trace for unhandled |
208 * exceptions. | 305 * exceptions. |
209 */ | 306 */ |
307 // TODO(floitsch): probably going to remove and replace with something else. | |
210 class IsolateUnhandledException implements Exception { | 308 class IsolateUnhandledException implements Exception { |
211 /** Message being handled when exception occurred. */ | 309 /** Message being handled when exception occurred. */ |
212 final message; | 310 final message; |
213 | 311 |
214 /** Wrapped exception. */ | 312 /** Wrapped exception. */ |
215 final source; | 313 final source; |
216 | 314 |
217 /** Trace for the wrapped exception. */ | 315 /** Trace for the wrapped exception. */ |
218 final Object stackTrace; | 316 final Object stackTrace; |
219 | 317 |
220 const IsolateUnhandledException(this.message, this.source, this.stackTrace); | 318 const IsolateUnhandledException(this.message, this.source, this.stackTrace); |
221 | 319 |
222 String toString() { | 320 String toString() { |
223 return 'IsolateUnhandledException: exception while handling message: ' | 321 return 'IsolateUnhandledException: exception while handling message: ' |
224 '${message} \n ' | 322 '${message} \n ' |
225 '${source.toString().replaceAll("\n", "\n ")}\n' | 323 '${source.toString().replaceAll("\n", "\n ")}\n' |
226 'original stack trace:\n ' | 324 'original stack trace:\n ' |
227 '${stackTrace.toString().replaceAll("\n","\n ")}'; | 325 '${stackTrace.toString().replaceAll("\n","\n ")}'; |
228 } | 326 } |
229 } | 327 } |
OLD | NEW |