Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(433)

Side by Side Diff: runtime/bin/directory_impl.dart

Issue 9310082: Run all directory async operations on a separate thread using native ports (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Adderssed review comments from ager@ (and rebased) Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/bin/directory.cc ('k') | runtime/bin/directory_posix.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 // Used for holding error code and error message for failed OS system calls. 6 // Used for holding error code and error message for failed OS system calls.
7 class _OSStatus { 7 class _OSStatus {
8 int _errorCode; 8 int _errorCode;
9 String _errorMessage; 9 String _errorMessage;
10 } 10 }
11 11
12 12
13 class _DirectoryListingIsolate extends Isolate {
14
15 _DirectoryListingIsolate() : super.heavy();
16
17 void main() {
18 port.receive((message, replyTo) {
19 bool started = _list(message['dir'],
20 message['recursive'],
21 message['dirPort'],
22 message['filePort'],
23 message['donePort'],
24 message['errorPort']);
25 replyTo.send(started);
26 port.close();
27 });
28 }
29
30 bool _list(String dir,
31 bool recursive,
32 SendPort dirPort,
33 SendPort filePort,
34 SendPort donePort,
35 SendPort errorPort) native "Directory_List";
36 }
37
38
39 class _DirectoryOperation {
40 abstract void execute(ReceivePort port);
41
42 void set replyPort(SendPort port) {
43 _replyPort = port;
44 }
45
46 SendPort _replyPort;
47 }
48
49
50 class _DirExitOperation extends _DirectoryOperation {
51 void execute(ReceivePort port) {
52 port.close();
53 }
54 }
55
56
57 class _DirExistsOperation extends _DirectoryOperation {
58 _DirExistsOperation(String this._path);
59
60 void execute(ReceivePort port) {
61 _replyPort.send(_Directory._exists(_path), port.toSendPort());
62 }
63
64 String _path;
65 }
66
67
68 class _DirCreateOperation extends _DirectoryOperation {
69 _DirCreateOperation(String this._path);
70
71 void execute(ReceivePort port) {
72 _replyPort.send(_Directory._create(_path), port.toSendPort());
73 }
74
75 String _path;
76 }
77
78
79 class _DirCreateTempOperation extends _DirectoryOperation {
80 _DirCreateTempOperation(String this._path);
81
82 void execute(ReceivePort port) {
83 var status = new _OSStatus();
84 var result = _Directory._createTemp(_path, status);
85 if (result == null) {
86 _replyPort.send(status, port.toSendPort());
87 } else {
88 _replyPort.send(result, port.toSendPort());
89 }
90 }
91
92 String _path;
93 }
94
95
96 class _DirDeleteOperation extends _DirectoryOperation {
97 _DirDeleteOperation(String this._path, bool this._recursive);
98
99 void execute(ReceivePort port) {
100 _replyPort.send(_Directory._delete(_path, _recursive), port.toSendPort());
101 }
102
103 String _path;
104 bool _recursive;
105 }
106
107
108 class _DirectoryOperationIsolate extends Isolate {
109 _DirectoryOperationIsolate() : super.heavy();
110
111 void handleOperation(_DirectoryOperation message, SendPort ignored) {
112 message.execute(port);
113 port.receive(handleOperation);
114 }
115
116 void main() {
117 port.receive(handleOperation);
118 }
119 }
120
121
122 class _DirectoryOperationScheduler {
123 _DirectoryOperationScheduler() : _queue = new Queue();
124
125 void schedule(SendPort port) {
126 assert(_isolate != null);
127 if (_queue.isEmpty()) {
128 port.send(new _DirExitOperation());
129 _isolate = null;
130 } else {
131 port.send(_queue.removeFirst());
132 }
133 }
134
135 void scheduleWrap(void callback(result, ignored)) {
136 return (result, replyTo) {
137 callback(result, replyTo);
138 schedule(replyTo);
139 };
140 }
141
142 void enqueue(_DirectoryOperation operation, void callback(result, ignored)) {
143 ReceivePort replyPort = new ReceivePort.singleShot();
144 replyPort.receive(scheduleWrap(callback));
145 operation.replyPort = replyPort.toSendPort();
146 _queue.addLast(operation);
147 if (_isolate == null) {
148 _isolate = new _DirectoryOperationIsolate();
149 _isolate.spawn().then((port) {
150 schedule(port);
151 });
152 }
153 }
154
155 Queue<_DirectoryOperation> _queue;
156 _DirectoryOperationIsolate _isolate;
157 }
158
159
160 class _Directory implements Directory { 13 class _Directory implements Directory {
14 static final kCreateRequest = 0;
15 static final kDeleteRequest = 1;
16 static final kExistsRequest = 2;
17 static final kCreateTempRequest = 3;
18 static final kListRequest = 4;
161 19
162 _Directory(String this._path) 20 _Directory(String this._path);
163 : _scheduler = new _DirectoryOperationScheduler();
164 21
165 static String _createTemp(String template, 22 static String _createTemp(String template,
166 _OSStatus status) native "Directory_CreateTemp"; 23 _OSStatus status) native "Directory_CreateTemp";
167 static int _exists(String path) native "Directory_Exists"; 24 static int _exists(String path) native "Directory_Exists";
168 static bool _create(String path) native "Directory_Create"; 25 static bool _create(String path) native "Directory_Create";
169 static bool _delete(String path, bool recursive) native "Directory_Delete"; 26 static bool _delete(String path, bool recursive) native "Directory_Delete";
27 static SendPort _newServicePort() native "Directory_NewServicePort";
170 28
171 void exists() { 29 void exists() {
172 var operation = new _DirExistsOperation(_path); 30 if (_directoryService == null) {
173 _scheduler.enqueue(operation, (result, ignored) { 31 _directoryService = _newServicePort();
32 }
33 List request = new List(2);
34 request[0] = kExistsRequest;
35 request[1] = _path;
36 _directoryService.call(request).receive((result, replyTo) {
174 var handler = 37 var handler =
175 (_existsHandler != null) ? _existsHandler : (result) => null; 38 (_existsHandler != null) ? _existsHandler : (result) => null;
176 if (result < 0) { 39 if (result < 0) {
177 if (_errorHandler != null) { 40 if (_errorHandler != null) {
178 _errorHandler("Diretory exists test failed: $_path"); 41 _errorHandler("Diretory exists test failed: $_path");
179 } 42 }
180 } else { 43 } else {
181 handler(result == 1); 44 handler(result == 1);
182 } 45 }
183 }); 46 });
184 } 47 }
185 48
186 bool existsSync() { 49 bool existsSync() {
187 int exists = _exists(_path); 50 int exists = _exists(_path);
188 if (exists < 0) { 51 if (exists < 0) {
189 throw new DirectoryException("Diretory exists test failed: $_path"); 52 throw new DirectoryException("Diretory exists test failed: $_path");
190 } 53 }
191 return (exists == 1); 54 return (exists == 1);
192 } 55 }
193 56
194 void create() { 57 void create() {
195 var operation = new _DirCreateOperation(_path); 58 if (_directoryService == null) {
196 _scheduler.enqueue(operation, (result, ignored) { 59 _directoryService = _newServicePort();
197 var handler = (_createHandler != null) ? _createHandler : () => null; 60 }
61 List request = new List(2);
62 request[0] = kCreateRequest;
63 request[1] = _path;
64 _directoryService.call(request).receive((result, replyTo) {
198 if (result) { 65 if (result) {
199 handler(); 66 if (_createHandler != null) _createHandler();
200 } else if (_errorHandler != null) { 67 } else if (_errorHandler != null) {
201 _errorHandler("Directory creation failed: $_path"); 68 _errorHandler("Directory creation failed: $_path");
202 } 69 }
203 }); 70 });
204 } 71 }
205 72
206 void createSync() { 73 void createSync() {
207 if (!_create(_path)) { 74 if (!_create(_path)) {
208 throw new DirectoryException("Directory creation failed: $_path"); 75 throw new DirectoryException("Directory creation failed: $_path");
209 } 76 }
210 } 77 }
211 78
212 void createTemp() { 79 void createTemp() {
213 var operation = new _DirCreateTempOperation(_path); 80 if (_directoryService == null) {
214 _scheduler.enqueue(operation, (result, ignored) { 81 _directoryService = _newServicePort();
215 var handler = 82 }
216 (_createTempHandler != null) ? _createTempHandler : () => null; 83 List request = new List(2);
217 if (result is !_OSStatus) { 84 request[0] = kCreateTempRequest;
85 request[1] = _path;
86 _directoryService.call(request).receive((result, replyTo) {
87 if (result is !List) {
218 _path = result; 88 _path = result;
219 handler(); 89 if (_createTempHandler != null) _createTempHandler();
220 } else if (_errorHandler !== null) { 90 } else if (_errorHandler != null) {
221 _errorHandler("Could not create temporary directory [$_path]: " + 91 _errorHandler("Could not create temporary directory [$_path]: " +
222 "${result._errorMessage}"); 92 "${result[1]}");
223 } 93 }
224 }); 94 });
225 } 95 }
226 96
227 void createTempSync() { 97 void createTempSync() {
228 var status = new _OSStatus(); 98 var status = new _OSStatus();
229 var result = _createTemp(path, status); 99 var result = _createTemp(path, status);
230 if (result != null) { 100 if (result != null) {
231 _path = result; 101 _path = result;
232 } else { 102 } else {
233 throw new DirectoryException( 103 throw new DirectoryException(
234 "Could not create temporary directory [$_path]: " + 104 "Could not create temporary directory [$_path]: " +
235 "${status._errorMessage}", 105 "${status._errorMessage}",
236 status._errorCode); 106 status._errorCode);
237 } 107 }
238 } 108 }
239 109
240 void delete([bool recursive = false]) { 110 void delete([bool recursive = false]) {
241 var operation = new _DirDeleteOperation(_path, recursive); 111 if (_directoryService == null) {
242 _scheduler.enqueue(operation, (result, ignored) { 112 _directoryService = _newServicePort();
243 var handler = (_deleteHandler != null) ? _deleteHandler : () => null; 113 }
114 List request = new List(3);
115 request[0] = kDeleteRequest;
116 request[1] = _path;
117 request[2] = recursive;
118 _directoryService.call(request).receive((result, replyTo) {
244 if (result) { 119 if (result) {
245 handler(); 120 if (_deleteHandler != null) _deleteHandler();
246 } else if (_errorHandler != null) { 121 } else if (_errorHandler != null) {
247 if (recursive) { 122 if (recursive) {
248 _errorHandler("Recursive directory deletion failed: $_path"); 123 _errorHandler("Recursive directory deletion failed: $_path");
249 } else { 124 } else {
250 _errorHandler("Non-recursive directory deletion failed: $_path"); 125 _errorHandler("Non-recursive directory deletion failed: $_path");
251 } 126 }
252 } 127 }
253 }); 128 });
254 } 129 }
255 130
256 void deleteSync([bool recursive = false]) { 131 void deleteSync([bool recursive = false]) {
257 if (!_delete(_path, recursive)) { 132 if (!_delete(_path, recursive)) {
258 throw new DirectoryException("Directory deletion failed: $_path"); 133 throw new DirectoryException("Directory deletion failed: $_path");
259 } 134 }
260 } 135 }
261 136
262 void list([bool recursive = false]) { 137 void list([bool recursive = false]) {
263 new _DirectoryListingIsolate().spawn().then((port) { 138 final int kListDirectory = 0;
264 // Build a map of parameters to the directory listing isolate. 139 final int kListFile = 1;
265 Map listingParameters = new Map(); 140 final int kListError = 2;
266 listingParameters['dir'] = _path; 141 final int kListDone = 3;
267 listingParameters['recursive'] = recursive;
268 142
269 // Setup ports to receive messages from listing. 143 List request = new List(3);
270 // TODO(ager): Do not explicitly transform to send ports when 144 request[0] = kListRequest;
271 // implicit conversions are implemented. 145 request[1] = _path;
272 ReceivePort dirPort; 146 request[2] = recursive;
273 ReceivePort filePort; 147 ReceivePort responsePort = new ReceivePort();
274 ReceivePort donePort; 148 // Use a separate directory service port for each listing as
275 ReceivePort errorPort; 149 // listing operations on the same directory can run in parallel.
276 if (_dirHandler !== null) { 150 _newServicePort().send(request, responsePort.toSendPort());
277 dirPort = new ReceivePort(); 151 responsePort.receive((message, replyTo) {
278 dirPort.receive((String dir, ignored) { 152 if (message is !List || message[0] is !int) {
279 _dirHandler(dir); 153 responsePort.close();
280 }); 154 if (_errorHandler != null) _errorHandler("Internal error");
281 listingParameters['dirPort'] = dirPort.toSendPort(); 155 return;
282 } 156 }
283 if (_fileHandler !== null) { 157 switch (message[0]) {
284 filePort = new ReceivePort(); 158 case kListDirectory:
285 filePort.receive((String file, ignored) { 159 if (_dirHandler != null) _dirHandler(message[1]);
286 _fileHandler(file); 160 break;
287 }); 161 case kListFile:
288 listingParameters['filePort'] = filePort.toSendPort(); 162 if (_fileHandler != null) _fileHandler(message[1]);
163 break;
164 case kListError:
165 if (_errorHandler != null) _errorHandler(message[1]);
166 break;
167 case kListDone:
168 responsePort.close();
169 if (_doneHandler != null) _doneHandler(message[1]);
170 break;
289 } 171 }
290 if (_doneHandler !== null) {
291 donePort = new ReceivePort.singleShot();
292 donePort.receive((bool completed, ignored) {
293 _doneHandler(completed);
294 });
295 listingParameters['donePort'] = donePort.toSendPort();
296 }
297 if (_errorHandler !== null) {
298 errorPort = new ReceivePort.singleShot();
299 errorPort.receive((String error, ignored) {
300 _errorHandler(error);
301 });
302 listingParameters['errorPort'] = errorPort.toSendPort();
303 }
304
305 // Close ports when listing is done.
306 ReceivePort closePortsPort = new ReceivePort();
307 closePortsPort.receive((message, replyTo) {
308 if (!message) {
309 errorPort.toSendPort().send(
310 "Failed to list directory: $_path recursive: $recursive");
311 donePort.toSendPort().send(false);
312 } else {
313 _closePort(errorPort);
314 _closePort(donePort);
315 }
316 _closePort(dirPort);
317 _closePort(filePort);
318 _closePort(closePortsPort);
319 });
320
321 // Send the listing parameters to the isolate.
322 port.send(listingParameters, closePortsPort.toSendPort());
323 }); 172 });
324 } 173 }
325 174
326 void set dirHandler(void dirHandler(String dir)) { 175 void set dirHandler(void dirHandler(String dir)) {
327 _dirHandler = dirHandler; 176 _dirHandler = dirHandler;
328 } 177 }
329 178
330 void set fileHandler(void fileHandler(String file)) { 179 void set fileHandler(void fileHandler(String file)) {
331 _fileHandler = fileHandler; 180 _fileHandler = fileHandler;
332 } 181 }
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
366 var _dirHandler; 215 var _dirHandler;
367 var _fileHandler; 216 var _fileHandler;
368 var _doneHandler; 217 var _doneHandler;
369 var _existsHandler; 218 var _existsHandler;
370 var _createHandler; 219 var _createHandler;
371 var _createTempHandler; 220 var _createTempHandler;
372 var _deleteHandler; 221 var _deleteHandler;
373 var _errorHandler; 222 var _errorHandler;
374 223
375 String _path; 224 String _path;
376 _DirectoryOperationScheduler _scheduler; 225 SendPort _directoryService;
377 } 226 }
OLDNEW
« no previous file with comments | « runtime/bin/directory.cc ('k') | runtime/bin/directory_posix.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698