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 import "dart:collection" show HashMap; | 5 import "dart:collection" show HashMap; |
6 | 6 |
7 patch class ReceivePort { | 7 patch class ReceivePort { |
8 /* patch */ factory ReceivePort() = _ReceivePortImpl; | 8 /* patch */ factory ReceivePort() = _ReceivePortImpl; |
9 | 9 |
10 /* patch */ factory ReceivePort.fromRawReceivePort(RawReceivePort rawPort) = | 10 /* patch */ factory ReceivePort.fromRawReceivePort(RawReceivePort rawPort) = |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
70 /// The callback that has been registered through `scheduleImmediate`. | 70 /// The callback that has been registered through `scheduleImmediate`. |
71 ImmediateCallback _pendingImmediateCallback; | 71 ImmediateCallback _pendingImmediateCallback; |
72 | 72 |
73 /// The closure that should be used as scheduleImmediateClosure, when the VM | 73 /// The closure that should be used as scheduleImmediateClosure, when the VM |
74 /// is responsible for the event loop. | 74 /// is responsible for the event loop. |
75 void _isolateScheduleImmediate(void callback()) { | 75 void _isolateScheduleImmediate(void callback()) { |
76 assert(_pendingImmediateCallback == null); | 76 assert(_pendingImmediateCallback == null); |
77 _pendingImmediateCallback = callback; | 77 _pendingImmediateCallback = callback; |
78 } | 78 } |
79 | 79 |
| 80 void _runPendingImmediateCallback() { |
| 81 if (_pendingImmediateCallback != null) { |
| 82 var callback = _pendingImmediateCallback; |
| 83 _pendingImmediateCallback = null; |
| 84 callback(); |
| 85 } |
| 86 } |
| 87 |
80 /// The embedder can execute this function to get hold of | 88 /// The embedder can execute this function to get hold of |
81 /// [_isolateScheduleImmediate] above. | 89 /// [_isolateScheduleImmediate] above. |
82 Function _getIsolateScheduleImmediateClosure() { | 90 Function _getIsolateScheduleImmediateClosure() { |
83 return _isolateScheduleImmediate; | 91 return _isolateScheduleImmediate; |
84 } | 92 } |
85 | 93 |
86 class _RawReceivePortImpl implements RawReceivePort { | 94 class _RawReceivePortImpl implements RawReceivePort { |
87 factory _RawReceivePortImpl() native "RawReceivePortImpl_factory"; | 95 factory _RawReceivePortImpl() native "RawReceivePortImpl_factory"; |
88 | 96 |
89 close() { | 97 close() { |
(...skipping 23 matching lines...) Expand all Loading... |
113 var result = _handlerMap[id]; | 121 var result = _handlerMap[id]; |
114 return result; | 122 return result; |
115 } | 123 } |
116 | 124 |
117 // Called from the VM to dispatch to the handler. | 125 // Called from the VM to dispatch to the handler. |
118 static void _handleMessage(Function handler, var message) { | 126 static void _handleMessage(Function handler, var message) { |
119 // TODO(floitsch): this relies on the fact that any exception aborts the | 127 // TODO(floitsch): this relies on the fact that any exception aborts the |
120 // VM. Once we have non-fatal global exceptions we need to catch errors | 128 // VM. Once we have non-fatal global exceptions we need to catch errors |
121 // so that we can run the immediate callbacks. | 129 // so that we can run the immediate callbacks. |
122 handler(message); | 130 handler(message); |
123 if (_pendingImmediateCallback != null) { | 131 _runPendingImmediateCallback(); |
124 var callback = _pendingImmediateCallback; | |
125 _pendingImmediateCallback = null; | |
126 callback(); | |
127 } | |
128 } | 132 } |
129 | 133 |
130 // Call into the VM to close the VM maintained mappings. | 134 // Call into the VM to close the VM maintained mappings. |
131 _closeInternal() native "RawReceivePortImpl_closeInternal"; | 135 _closeInternal() native "RawReceivePortImpl_closeInternal"; |
132 | 136 |
133 void set handler(Function value) { | 137 void set handler(Function value) { |
134 _handlerMap[this._get_id()] = value; | 138 _handlerMap[this._get_id()] = value; |
135 } | 139 } |
136 | 140 |
137 // TODO(iposva): Ideally keep this map in the VM. | 141 // TODO(iposva): Ideally keep this map in the VM. |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
174 typedef _MainFunction(); | 178 typedef _MainFunction(); |
175 typedef _MainFunctionArgs(args); | 179 typedef _MainFunctionArgs(args); |
176 typedef _MainFunctionArgsMessage(args, message); | 180 typedef _MainFunctionArgsMessage(args, message); |
177 | 181 |
178 /** | 182 /** |
179 * Takes the real entry point as argument and invokes it with the initial | 183 * Takes the real entry point as argument and invokes it with the initial |
180 * message. | 184 * message. |
181 * | 185 * |
182 * The initial startup message is received through the control port. | 186 * The initial startup message is received through the control port. |
183 */ | 187 */ |
184 void _startIsolate(Function entryPoint, bool isSpawnUri) { | 188 void _startIsolate(SendPort parentPort, |
185 // This port keeps the isolate alive until the initial startup message has | 189 Function entryPoint, |
186 // been received. | 190 List<String> args, |
187 var keepAlivePort = new RawReceivePort(); | 191 var message, |
| 192 bool isSpawnUri, |
| 193 RawReceivePort controlPort, |
| 194 List capabilities) { |
| 195 if (controlPort != null) { |
| 196 controlPort.handler = (_) {}; // Nobody home on the control port. |
| 197 } |
| 198 if (parentPort != null) { |
| 199 // Build a message to our parent isolate providing access to the |
| 200 // current isolate's control port and capabilities. |
| 201 // |
| 202 // TODO(floitsch): Send an error message if we can't find the entry point. |
| 203 var readyMessage = new List(2); |
| 204 readyMessage[0] = controlPort.sendPort; |
| 205 readyMessage[1] = capabilities; |
188 | 206 |
189 ignoreHandler(message) { | 207 // Out of an excess of paranoia we clear the capabilities from the |
190 // Messages on the current Isolate's control port are dropped after the | 208 // stack. Not really necessary. |
191 // initial startup message has been received. | 209 capabilities = null; |
| 210 parentPort.send(readyMessage); |
192 } | 211 } |
| 212 assert(capabilities == null); |
193 | 213 |
194 isolateStartHandler(message) { | 214 if (isSpawnUri) { |
195 // We received the initial startup message. Ignore all further messages and | 215 if (entryPoint is _MainFunctionArgsMessage) { |
196 // close the port which kept this isolate alive. | 216 entryPoint(args, message); |
197 Isolate._self.handler = ignoreHandler; | 217 } else if (entryPoint is _MainFunctionArgs) { |
198 keepAlivePort.close(); | 218 entryPoint(args); |
199 | 219 } else { |
200 SendPort replyTo = message[0]; | 220 entryPoint(); |
201 if (replyTo != null) { | |
202 // TODO(floitsch): don't send ok-message if we can't find the entry point. | |
203 replyTo.send("started"); | |
204 } | 221 } |
205 if (isSpawnUri) { | 222 } else { |
206 assert(message.length == 3); | 223 entryPoint(message); |
207 List<String> args = message[1]; | |
208 var isolateMessage = message[2]; | |
209 if (entryPoint is _MainFunctionArgsMessage) { | |
210 entryPoint(args, isolateMessage); | |
211 } else if (entryPoint is _MainFunctionArgs) { | |
212 entryPoint(args); | |
213 } else { | |
214 entryPoint(); | |
215 } | |
216 } else { | |
217 assert(message.length == 2); | |
218 var entryMessage = message[1]; | |
219 entryPoint(entryMessage); | |
220 } | |
221 } | 224 } |
222 | 225 _runPendingImmediateCallback(); |
223 Isolate._self.handler = isolateStartHandler; | |
224 } | 226 } |
225 | 227 |
226 patch class Isolate { | 228 patch class Isolate { |
227 /* patch */ static Future<Isolate> spawn( | 229 /* patch */ static Future<Isolate> spawn( |
228 void entryPoint(message), var message, { bool paused: false }) { | 230 void entryPoint(message), var message, { bool paused: false }) { |
229 // `paused` isn't handled yet. | 231 // `paused` isn't handled yet. |
| 232 RawReceivePort readyPort; |
230 try { | 233 try { |
231 // The VM will invoke [_startIsolate] with entryPoint as argument. | 234 // The VM will invoke [_startIsolate] with entryPoint as argument. |
232 List spawnData = _spawnFunction(entryPoint); | 235 readyPort = new RawReceivePort(); |
233 assert(spawnData.length == 3); | 236 _spawnFunction(readyPort.sendPort, entryPoint, message); |
234 SendPort controlPort = spawnData[0]; | |
235 RawReceivePort readyPort = new RawReceivePort(); | |
236 controlPort.send([readyPort.sendPort, message]); | |
237 Completer completer = new Completer<Isolate>.sync(); | 237 Completer completer = new Completer<Isolate>.sync(); |
238 readyPort.handler = (readyMessage) { | 238 readyPort.handler = (readyMessage) { |
239 assert(readyMessage == 'started'); | |
240 readyPort.close(); | 239 readyPort.close(); |
| 240 assert(readyMessage is List); |
| 241 assert(readyMessage.length == 2); |
| 242 SendPort controlPort = readyMessage[0]; |
| 243 List capabilities = readyMessage[1]; |
241 completer.complete(new Isolate(controlPort, | 244 completer.complete(new Isolate(controlPort, |
242 pauseCapability: spawnData[1], | 245 pauseCapability: capabilities[0], |
243 terminateCapability: spawnData[2])); | 246 terminateCapability: capabilities[1])); |
244 }; | 247 }; |
245 return completer.future; | 248 return completer.future; |
246 } catch (e, st) { | 249 } catch (e, st) { |
| 250 if (readyPort != null) { |
| 251 readyPort.close(); |
| 252 } |
247 return new Future<Isolate>.error(e, st); | 253 return new Future<Isolate>.error(e, st); |
248 }; | 254 }; |
249 } | 255 } |
250 | 256 |
251 /* patch */ static Future<Isolate> spawnUri( | 257 /* patch */ static Future<Isolate> spawnUri( |
252 Uri uri, List<String> args, var message, { bool paused: false }) { | 258 Uri uri, List<String> args, var message, { bool paused: false }) { |
253 // `paused` isn't handled yet. | 259 // `paused` isn't handled yet. |
| 260 RawReceivePort readyPort; |
254 try { | 261 try { |
255 // The VM will invoke [_startIsolate] and not `main`. | 262 // The VM will invoke [_startIsolate] and not `main`. |
256 List spawnData = _spawnUri(uri.toString()); | 263 readyPort = new RawReceivePort(); |
257 assert(spawnData.length == 3); | 264 _spawnUri(readyPort.sendPort, uri.toString(), args, message); |
258 SendPort controlPort = spawnData[0]; | |
259 RawReceivePort readyPort = new RawReceivePort(); | |
260 controlPort.send([readyPort.sendPort, args, message]); | |
261 Completer completer = new Completer<Isolate>.sync(); | 265 Completer completer = new Completer<Isolate>.sync(); |
262 readyPort.handler = (readyMessage) { | 266 readyPort.handler = (readyMessage) { |
263 assert(readyMessage == 'started'); | |
264 readyPort.close(); | 267 readyPort.close(); |
| 268 assert(readyMessage is List); |
| 269 assert(readyMessage.length == 2); |
| 270 SendPort controlPort = readyMessage[0]; |
| 271 List capabilities = readyMessage[1]; |
265 completer.complete(new Isolate(controlPort, | 272 completer.complete(new Isolate(controlPort, |
266 pauseCapability: spawnData[1], | 273 pauseCapability: capabilities[0], |
267 terminateCapability: spawnData[2])); | 274 terminateCapability: capabilities[1])); |
268 }; | 275 }; |
269 return completer.future; | 276 return completer.future; |
270 } catch (e, st) { | 277 } catch (e, st) { |
| 278 if (readyPort != null) { |
| 279 readyPort.close(); |
| 280 } |
271 return new Future<Isolate>.error(e, st); | 281 return new Future<Isolate>.error(e, st); |
272 }; | 282 }; |
273 return completer.future; | 283 return completer.future; |
274 } | 284 } |
275 | 285 |
276 static final RawReceivePort _self = _mainPort; | |
277 static RawReceivePort get _mainPort native "Isolate_mainPort"; | |
278 | |
279 // TODO(iposva): Cleanup to have only one definition. | 286 // TODO(iposva): Cleanup to have only one definition. |
280 // These values need to be kept in sync with the class IsolateMessageHandler | 287 // These values need to be kept in sync with the class IsolateMessageHandler |
281 // in vm/isolate.cc. | 288 // in vm/isolate.cc. |
282 static const _PAUSE = 1; | 289 static const _PAUSE = 1; |
283 static const _RESUME = 2; | 290 static const _RESUME = 2; |
284 | 291 |
285 static List _spawnFunction(Function topLevelFunction) | 292 static SendPort _spawnFunction(SendPort readyPort, Function topLevelFunction, |
| 293 var message) |
286 native "Isolate_spawnFunction"; | 294 native "Isolate_spawnFunction"; |
287 | 295 |
288 static List _spawnUri(String uri) native "Isolate_spawnUri"; | 296 static SendPort _spawnUri(SendPort readyPort, String uri, |
| 297 List<String> args, var message) |
| 298 native "Isolate_spawnUri"; |
289 | 299 |
290 static void _sendOOB(port, msg) native "Isolate_sendOOB"; | 300 static void _sendOOB(port, msg) native "Isolate_sendOOB"; |
291 | 301 |
292 /* patch */ void _pause(Capability resumeCapability) { | 302 /* patch */ void _pause(Capability resumeCapability) { |
293 var msg = new List(4) | 303 var msg = new List(4) |
294 ..[0] = 0 // Make room for OOM message type. | 304 ..[0] = 0 // Make room for OOM message type. |
295 ..[1] = _PAUSE | 305 ..[1] = _PAUSE |
296 ..[2] = pauseCapability | 306 ..[2] = pauseCapability |
297 ..[3] = resumeCapability; | 307 ..[3] = resumeCapability; |
298 _sendOOB(controlPort, msg); | 308 _sendOOB(controlPort, msg); |
(...skipping 29 matching lines...) Expand all Loading... |
328 } | 338 } |
329 | 339 |
330 /* patch */ void addErrorListener(SendPort port) { | 340 /* patch */ void addErrorListener(SendPort port) { |
331 throw new UnsupportedError("addErrorListener"); | 341 throw new UnsupportedError("addErrorListener"); |
332 } | 342 } |
333 | 343 |
334 /* patch */ void removeErrorListener(SendPort port) { | 344 /* patch */ void removeErrorListener(SendPort port) { |
335 throw new UnsupportedError("removeErrorListener"); | 345 throw new UnsupportedError("removeErrorListener"); |
336 } | 346 } |
337 } | 347 } |
OLD | NEW |