OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 /// A library for compiling Dart code and manipulating analyzer parse trees. | 5 /// A library for compiling Dart code and manipulating analyzer parse trees. |
6 library pub.dart; | 6 library pub.dart; |
7 | 7 |
8 import 'dart:async'; | 8 import 'dart:async'; |
9 import 'dart:isolate'; | 9 import 'dart:isolate'; |
10 | 10 |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
85 /// [code] should be the contents of a Dart entrypoint. It may contain imports; | 85 /// [code] should be the contents of a Dart entrypoint. It may contain imports; |
86 /// they will be resolved in the same context as the host isolate. | 86 /// they will be resolved in the same context as the host isolate. |
87 /// | 87 /// |
88 /// Returns a Future that will resolve to a [SendPort] that will communicate to | 88 /// Returns a Future that will resolve to a [SendPort] that will communicate to |
89 /// the spawned isolate once it's spawned. If the isolate fails to spawn, the | 89 /// the spawned isolate once it's spawned. If the isolate fails to spawn, the |
90 /// Future will complete with an error. | 90 /// Future will complete with an error. |
91 Future<SendPort> runInIsolate(String code) { | 91 Future<SendPort> runInIsolate(String code) { |
92 return withTempDir((dir) { | 92 return withTempDir((dir) { |
93 var dartPath = path.join(dir, 'runInIsolate.dart'); | 93 var dartPath = path.join(dir, 'runInIsolate.dart'); |
94 writeTextFile(dartPath, code, dontLogContents: true); | 94 writeTextFile(dartPath, code, dontLogContents: true); |
95 var bufferPort = spawnFunction(_isolateBuffer); | 95 var port = new ReceivePort(); |
96 return bufferPort.call(path.toUri(dartPath).toString()).then((response) { | 96 var initialMessage = [path.toUri(dartPath).toString(), port.sendPort]; |
97 if (response.first == 'error') { | 97 var isolate = Isolate.spawn(_isolateBuffer, initialMessage); |
98 return new Future.error( | 98 return isolate.then((_) { |
99 new CrossIsolateException.deserialize(response.last)); | 99 return port.first.then((response) { |
100 } | 100 if (response.first == 'error') { |
| 101 return new Future.error( |
| 102 new CrossIsolateException.deserialize(response.last)); |
| 103 } |
101 | 104 |
102 return response.last; | 105 return response.last; |
| 106 }); |
103 }); | 107 }); |
104 }); | 108 }); |
105 } | 109 } |
106 | 110 |
107 // TODO(nweiz): remove this when issue 12617 is fixed. | 111 // TODO(nweiz): remove this when issue 12617 is fixed. |
108 /// A function used as a buffer between the host isolate and [spawnUri]. | 112 /// A function used as a buffer between the host isolate and [spawnUri]. |
109 /// | 113 /// |
110 /// [spawnUri] synchronously loads the file and its imports, which can deadlock | 114 /// [spawnUri] synchronously loads the file and its imports, which can deadlock |
111 /// the host isolate if there's an HTTP import pointing at a server in the host. | 115 /// the host isolate if there's an HTTP import pointing at a server in the host. |
112 /// Adding an additional isolate in the middle works around this. | 116 /// Adding an additional isolate in the middle works around this. |
113 void _isolateBuffer() { | 117 void _isolateBuffer(initialMessage) { |
114 port.receive((uri, replyTo) { | 118 var uri = initialMessage[0]; |
115 try { | 119 var replyTo = initialMessage[1]; |
116 replyTo.send(['success', spawnUri(uri)]); | 120 try { |
117 } catch (e, stack) { | 121 // TODO(floitsch): If we do it right we shouldn't need to have a try/catch |
| 122 // and a catchError. |
| 123 Isolate.spawnUri(Uri.parse(uri), [], replyTo).catchError((e, stack) { |
118 replyTo.send(['error', CrossIsolateException.serialize(e, stack)]); | 124 replyTo.send(['error', CrossIsolateException.serialize(e, stack)]); |
119 } | 125 }); |
120 }); | 126 } catch (e, stack) { |
| 127 replyTo.send(['error', CrossIsolateException.serialize(e, stack)]); |
| 128 } |
121 } | 129 } |
122 | 130 |
123 /// An exception that was originally raised in another isolate. | 131 /// An exception that was originally raised in another isolate. |
124 /// | 132 /// |
125 /// Exception objects can't cross isolate boundaries in general, so this class | 133 /// Exception objects can't cross isolate boundaries in general, so this class |
126 /// wraps as much information as can be consistently serialized. | 134 /// wraps as much information as can be consistently serialized. |
127 class CrossIsolateException implements Exception { | 135 class CrossIsolateException implements Exception { |
128 /// The name of the type of exception thrown. | 136 /// The name of the type of exception thrown. |
129 /// | 137 /// |
130 /// This is the return value of [error.runtimeType.toString()]. Keep in mind | 138 /// This is the return value of [error.runtimeType.toString()]. Keep in mind |
(...skipping 29 matching lines...) Expand all Loading... |
160 if (stack == null) stack = getAttachedStackTrace(error); | 168 if (stack == null) stack = getAttachedStackTrace(error); |
161 return { | 169 return { |
162 'type': error.runtimeType.toString(), | 170 'type': error.runtimeType.toString(), |
163 'message': getErrorMessage(error), | 171 'message': getErrorMessage(error), |
164 'stack': stack == null ? null : stack.toString() | 172 'stack': stack == null ? null : stack.toString() |
165 }; | 173 }; |
166 } | 174 } |
167 | 175 |
168 String toString() => "$message\n$stackTrace"; | 176 String toString() => "$message\n$stackTrace"; |
169 } | 177 } |
OLD | NEW |