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 import "dart:collection" show HashMap; |
18 | 19 |
19 part "isolate_stream.dart"; | 20 /** |
20 | 21 * Thrown when an isolate cannot be created. |
| 22 */ |
21 class IsolateSpawnException implements Exception { | 23 class IsolateSpawnException implements Exception { |
| 24 // TODO(floitsch): clean up spawn exception. |
22 const IsolateSpawnException(String this._s); | 25 const IsolateSpawnException(String this._s); |
23 String toString() => "IsolateSpawnException: '$_s'"; | 26 String toString() => "IsolateSpawnException: '$_s'"; |
24 final String _s; | 27 final String _s; |
25 } | 28 } |
26 | 29 |
27 /** | 30 class Isolate { |
28 * The initial ReceivePort available by default for this isolate. | 31 |
29 * | 32 final SendPort _controlPort; |
30 * This ReceivePort is created automatically | 33 |
31 * and is commonly used to establish | 34 Isolate._fromControlPort(SendPort controlPort) |
32 * the first communication between isolates. | 35 : this._controlPort = controlPort; |
33 * (See [spawnFunction] and [spawnUri].) | 36 |
34 */ | 37 /** |
35 ReceivePort get port => _Isolate.port; | 38 * Creates and spawns an isolate that shares the same code as the current |
| 39 * isolate. |
| 40 * |
| 41 * The argument [entryPoint] specifies the entry point of the spawned |
| 42 * isolate. It must be a static top-level function or a static method that |
| 43 * takes no arguments. It is not allowed to pass a function closure. |
| 44 * |
| 45 * The entry-point function is invoked with the initial [message]. |
| 46 * Usually the initial [message] contains a [SendPort] so |
| 47 * that the spawner and spawnee can communicate with each other. |
| 48 * |
| 49 * Returns a future that will complete with an [Isolate] instance. The |
| 50 * isolate instance can be used to control the spawned isolate. |
| 51 */ |
| 52 external static Future<Isolate> spawn(void entryPoint(message), var message); |
| 53 |
| 54 /** |
| 55 * Creates and spawns an isolate that runs the code from the library with |
| 56 * the specified URI. |
| 57 * |
| 58 * The isolate starts executing the top-level `main` function of the library |
| 59 * with the given URI. |
| 60 * |
| 61 * The target `main` may have one of the four following signatures: |
| 62 * |
| 63 * * `main()` |
| 64 * * `main(args)` |
| 65 * * `main(args, message)` |
| 66 * |
| 67 * When present, the argument `message` is set to the initial [message]. |
| 68 * When present, the argument `args` is set to the provided [args] list. |
| 69 * |
| 70 * Returns a future that will complete with an [Isolate] instance. The |
| 71 * isolate instance can be used to control the spawned isolate. |
| 72 */ |
| 73 external static Future<Isolate> spawnUri( |
| 74 Uri uri, List<String> args, var message); |
| 75 } |
36 | 76 |
37 /** | 77 /** |
38 * Creates and spawns an isolate | 78 * Sends messages to its [ReceivePort]s. |
39 * that shares the same code as the current isolate, | |
40 * but that starts from the specified function. | |
41 * | |
42 * The [topLevelFunction] argument must be | |
43 * a static top-level function or a static method that takes no | |
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 */ | |
58 SendPort spawnFunction(void topLevelFunction(), | |
59 [bool unhandledExceptionCallback(IsolateUnhandledException e)]) | |
60 => _Isolate.spawnFunction(topLevelFunction, unhandledExceptionCallback); | |
61 | |
62 /** | |
63 * Creates and spawns an isolate that runs the code from the specified URI. | |
64 * | |
65 * As with [spawnFunction], | |
66 * the child isolate has a default [ReceivePort], | |
67 * and this function returns a [SendPort] derived from it. | |
68 */ | |
69 SendPort spawnUri(String uri) => _Isolate.spawnUri(uri); | |
70 | |
71 /** | |
72 * Together with [ReceivePort], | |
73 * the only means of communication between isolates. | |
74 * | 79 * |
75 * [SendPort]s are created from [ReceivePort]s. Any message sent through | 80 * [SendPort]s are created from [ReceivePort]s. Any message sent through |
76 * a [SendPort] is delivered to its respective [ReceivePort]. There might be | 81 * a [SendPort] is delivered to its respective [ReceivePort]. There might be |
77 * many [SendPort]s for the same [ReceivePort]. | 82 * many [SendPort]s for the same [ReceivePort]. |
78 * | 83 * |
79 * [SendPort]s can be transmitted to other isolates. | 84 * [SendPort]s can be transmitted to other isolates. |
80 */ | 85 */ |
81 abstract class SendPort { | 86 abstract class SendPort { |
82 | 87 |
83 /** | 88 /** |
84 * Sends an asynchronous [message] to this send port. The message is copied to | 89 * 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 | 90 * the receiving isolate. |
86 * the receiver to facilitate exchanging sequences of messages. | |
87 * | 91 * |
88 * The content of [message] can be: primitive values (null, num, bool, double, | 92 * 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 | 93 * String), instances of [SendPort], and lists and maps whose elements are any |
90 * of these. List and maps are also allowed to be cyclic. | 94 * of these. List and maps are also allowed to be cyclic. |
91 * | 95 * |
92 * In the special circumstances when two isolates share the same code and are | 96 * 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 | 97 * 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 | 98 * 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 | 99 * process). This is currently only supported by the dartvm. For now, the |
96 * dart2js compiler only supports the restricted messages described above. | 100 * dart2js compiler only supports the restricted messages described above. |
97 * | 101 * |
98 * Deprecation note: it is no longer valid to transmit a [ReceivePort] in a | 102 * The second argument [replyTo] is deprecated and its value is ignored. |
99 * message. Previously they were translated to the corresponding send port | |
100 * before being transmitted. | |
101 */ | 103 */ |
102 void send(var message, [SendPort replyTo]); | 104 void send(var message, [SendPort replyTo]); |
103 | 105 |
104 /** | 106 /** |
105 * 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 | |
107 * 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 | |
109 * future. | |
110 */ | |
111 Future call(var message); | |
112 | |
113 /** | |
114 * Tests whether [other] is a [SendPort] pointing to the same | 107 * Tests whether [other] is a [SendPort] pointing to the same |
115 * [ReceivePort] as this one. | 108 * [ReceivePort] as this one. |
116 */ | 109 */ |
117 bool operator==(var other); | 110 bool operator==(var other); |
118 | 111 |
119 /** | 112 /** |
120 * Returns an immutable hash code for this send port that is | 113 * Returns an immutable hash code for this send port that is |
121 * consistent with the == operator. | 114 * consistent with the == operator. |
122 */ | 115 */ |
123 int get hashCode; | 116 int get hashCode; |
124 | |
125 } | 117 } |
126 | 118 |
127 /** | 119 /** |
128 * Together with [SendPort], the only means of | 120 * Together with [SendPort], the only means of communication between isolates. |
129 * communication between isolates. | |
130 * | 121 * |
131 * [ReceivePort]s have a [:toSendPort:] method | 122 * [ReceivePort]s have a `sendport` getter which returns a [SendPort]. |
132 * which returns a [SendPort]. Any message that is sent through this [SendPort] | 123 * Any message that is sent through this [SendPort] |
133 * is delivered to the [ReceivePort] it has been created from. There, they are | 124 * is delivered to the [ReceivePort] it has been created from. There, the |
134 * dispatched to the callback that has been registered on the receive port. | 125 * message is dispatched to its listener. |
| 126 * |
| 127 * A [ReceivePort] is a non-broadcast stream. This means that it buffers |
| 128 * incoming messages until a listener is registered. Only one listener can |
| 129 * receive messages. See [Stream.asBroadcastStream] for transforming the port |
| 130 * to a broadcast stream. |
135 * | 131 * |
136 * A [ReceivePort] may have many [SendPort]s. | 132 * A [ReceivePort] may have many [SendPort]s. |
137 */ | 133 */ |
138 abstract class ReceivePort { | 134 abstract class ReceivePort implements Stream { |
139 | 135 |
140 /** | 136 /** |
141 * Opens a long-lived port for receiving messages. The returned port | 137 * Opens a long-lived port for receiving messages. |
142 * must be explicitly closed through [ReceivePort.close]. | 138 * |
| 139 * A [ReceivePort] is a non-broadcast stream. This means that it buffers |
| 140 * incoming messages until a listener is registered. Only one listener can |
| 141 * receive messages. See [Stream.asBroadcastStream] for transforming the port |
| 142 * to a broadcast stream. |
| 143 * |
| 144 * A receive port is closed by canceling its subscription. |
143 */ | 145 */ |
144 external factory ReceivePort(); | 146 external factory ReceivePort(); |
145 | 147 |
146 /** | 148 /** |
147 * Sets up a callback function for receiving pending or future | 149 * Creates a [ReceivePort] from a [RawReceivePort]. |
148 * messages on this receive port. | 150 * |
| 151 * The handler of the given [rawPort] is overwritten during the construction |
| 152 * of the result. |
149 */ | 153 */ |
150 void receive(void callback(var message, SendPort replyTo)); | 154 external factory ReceivePort.fromRawReceivePort(RawReceivePort rawPort); |
151 | 155 |
152 /** | 156 /** |
153 * Closes this receive port immediately. Pending messages will not | 157 * Inherited from [Stream]. |
154 * be processed and it is impossible to re-open the port. Single-shot | 158 * |
155 * reply ports, such as those created through [SendPort.call], are | 159 * Note that all named arguments are ignored since a ReceivePort will never |
156 * automatically closed when the reply has been received. Multiple | 160 * receive an error, or done message. |
157 * invocations of [close] are allowed but ignored. | 161 */ |
| 162 StreamSubscription listen(void onData(var message), |
| 163 { Function onError, |
| 164 void onDone(), |
| 165 bool cancelOnError }); |
| 166 |
| 167 /** |
| 168 * Closes `this`. |
| 169 * |
| 170 * If the stream has not been canceled yet, adds a close-event to the event |
| 171 * queue and discards any further incoming messages. |
| 172 * |
| 173 * If the stream has already been canceled this method has no effect. |
158 */ | 174 */ |
159 void close(); | 175 void close(); |
160 | 176 |
161 /** | 177 /** |
162 * Creates a new send port that sends to this receive port. It is legal to | 178 * Returns a send port that sends to this receive port. |
163 * create several [SendPort]s from the same [ReceivePort]. | |
164 */ | 179 */ |
165 SendPort toSendPort(); | 180 SendPort get sendPort; |
| 181 } |
166 | 182 |
| 183 abstract class RawReceivePort { |
| 184 /** |
| 185 * Opens a long-lived port for receiving messages. |
| 186 * |
| 187 * A [RawReceivePort] is low level and does not work with [Zone]s. It |
| 188 * can not be paused. The data-handler must be set before the first |
| 189 * event is received. |
| 190 */ |
| 191 external factory RawReceivePort([void handler(event)]); |
| 192 |
| 193 /** |
| 194 * Sets the handler that is invoked for every incoming message. |
| 195 * |
| 196 * The handler is invoked in the root-zone ([Zone.ROOT]). |
| 197 */ |
| 198 void set handler(Function newHandler); |
| 199 |
| 200 /** |
| 201 * Closes the port. |
| 202 * |
| 203 * After a call to this method any incoming message is silently dropped. |
| 204 */ |
| 205 void close(); |
167 } | 206 } |
168 | 207 |
169 /** | 208 /** |
170 * [SendPortSync]s are created from [ReceivePortSync]s. Any message sent through | 209 * [SendPortSync]s are created from [ReceivePortSync]s. Any message sent through |
171 * a [SendPortSync] is delivered to its respective [ReceivePortSync]. There | 210 * a [SendPortSync] is delivered to its respective [ReceivePortSync]. There |
172 * might be many [SendPortSync]s for the same [ReceivePortSync]. | 211 * might be many [SendPortSync]s for the same [ReceivePortSync]. |
173 * | 212 * |
174 * [SendPortSync]s can be transmitted to other isolates. | 213 * [SendPortSync]s can be transmitted to other isolates. |
| 214 * |
| 215 * *DEPRECATED*. |
175 */ | 216 */ |
| 217 @deprecated |
176 abstract class SendPortSync { | 218 abstract class SendPortSync { |
177 /** | 219 /** |
178 * Sends a synchronous message to this send port and returns the result. | 220 * Sends a synchronous message to this send port and returns the result. |
179 */ | 221 */ |
180 callSync(var message); | 222 callSync(var message); |
181 | 223 |
182 /** | 224 /** |
183 * Tests whether [other] is a [SendPortSync] pointing to the same | 225 * Tests whether [other] is a [SendPortSync] pointing to the same |
184 * [ReceivePortSync] as this one. | 226 * [ReceivePortSync] as this one. |
185 */ | 227 */ |
186 bool operator==(var other); | 228 bool operator==(var other); |
187 | 229 |
188 /** | 230 /** |
189 * Returns an immutable hash code for this send port that is | 231 * Returns an immutable hash code for this send port that is |
190 * consistent with the == operator. | 232 * consistent with the == operator. |
191 */ | 233 */ |
192 int get hashCode; | 234 int get hashCode; |
193 } | 235 } |
194 | 236 |
195 // The VM doesn't support accessing external globals in the same library. We | |
196 // therefore create this wrapper class. | |
197 // TODO(6997): Don't go through static class for external variables. | |
198 abstract class _Isolate { | |
199 external static ReceivePort get port; | |
200 external static SendPort spawnFunction(void topLevelFunction(), | |
201 [bool unhandledExceptionCallback(IsolateUnhandledException e)]); | |
202 external static SendPort spawnUri(String uri); | |
203 } | |
204 | |
205 /** | 237 /** |
206 * Wraps unhandled exceptions thrown during isolate execution. It is | 238 * Wraps unhandled exceptions thrown during isolate execution. It is |
207 * used to show both the error message and the stack trace for unhandled | 239 * used to show both the error message and the stack trace for unhandled |
208 * exceptions. | 240 * exceptions. |
209 */ | 241 */ |
210 class IsolateUnhandledException implements Exception { | 242 // TODO(floitsch): probably going to remove and replace with something else. |
| 243 class _IsolateUnhandledException implements Exception { |
211 /** Message being handled when exception occurred. */ | 244 /** Message being handled when exception occurred. */ |
212 final message; | 245 final message; |
213 | 246 |
214 /** Wrapped exception. */ | 247 /** Wrapped exception. */ |
215 final source; | 248 final source; |
216 | 249 |
217 /** Trace for the wrapped exception. */ | 250 /** Trace for the wrapped exception. */ |
218 final Object stackTrace; | 251 final Object stackTrace; |
219 | 252 |
220 const IsolateUnhandledException(this.message, this.source, this.stackTrace); | 253 const _IsolateUnhandledException(this.message, this.source, this.stackTrace); |
221 | 254 |
222 String toString() { | 255 String toString() { |
223 return 'IsolateUnhandledException: exception while handling message: ' | 256 return 'IsolateUnhandledException: exception while handling message: ' |
224 '${message} \n ' | 257 '${message} \n ' |
225 '${source.toString().replaceAll("\n", "\n ")}\n' | 258 '${source.toString().replaceAll("\n", "\n ")}\n' |
226 'original stack trace:\n ' | 259 'original stack trace:\n ' |
227 '${stackTrace.toString().replaceAll("\n","\n ")}'; | 260 '${stackTrace.toString().replaceAll("\n","\n ")}'; |
228 } | 261 } |
229 } | 262 } |
OLD | NEW |