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

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

Issue 8431028: Implement async file API on top of isolates. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Fix type mismatch. Created 9 years, 1 month 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/file.dart ('k') | runtime/lib/array.dart » ('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) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, 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 class _FileInputStream implements FileInputStream { 5 class _FileInputStream implements FileInputStream {
6 _FileInputStream(File file) { 6 _FileInputStream(File file) {
7 _file = new File(file.name); 7 _file = new File(file.name);
8 _file.openSync(); 8 _file.openSync();
9 } 9 }
10 10
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
107 return true; 107 return true;
108 } else { 108 } else {
109 throw "FileOutputStream: write error"; 109 throw "FileOutputStream: write error";
110 } 110 }
111 } 111 }
112 112
113 File _file; 113 File _file;
114 } 114 }
115 115
116 116
117 class _FileOperationIsolate extends Isolate {
118 static int EXISTS = 0;
119 static int OPEN = 1;
120 static int CLOSE = 2;
121 static int READ_BYTE = 3;
122 static int READ_LIST = 4;
123 static int WRITE_BYTE = 5;
124 static int WRITE_LIST = 6;
125 static int WRITE_STRING = 7;
126 static int POSITION = 8;
127 static int LENGTH = 9;
128 static int FLUSH = 10;
129 static int EXIT = 11;
130
131 _FileOperationIsolate() : super.heavy();
132
133 void handleOperation(Map message, SendPort ignored) {
134 switch (message["type"]) {
135 case EXISTS:
136 message["reply"].send(_File._exists(message["name"]),
137 port.toSendPort());
138 break;
139 case OPEN:
140 var name = message["name"];
141 var writable = message["writable"];
142 message["reply"].send(_File._open(name, writable),
143 port.toSendPort());
144 break;
145 case CLOSE:
146 message["reply"].send(_File._close(message["id"]),
147 port.toSendPort());
148 break;
149 case READ_BYTE:
150 message["reply"].send(_File._readByte(message["id"]),
151 port.toSendPort());
152 break;
153 case READ_LIST:
154 var replyPort = message["reply"];
155 var bytes = message["bytes"];
156 var offset = message["offset"];
157 var length = message["length"];
158 var id = message["id"];
159 if (bytes == 0) {
160 replyPort.send(0, port.toSendPort());
161 return;
162 }
163 int index = _File._checkReadWriteListArguments(length, offset, bytes);
164 if (index != 0) {
165 replyPort.send("index out of range in readList: $index",
166 port.toSendPort());
167 return;
168 }
169 var buffer = new List(bytes);
170 var result = { "read": _File._readList(id, buffer, 0, bytes),
171 "buffer": buffer };
172 replyPort.send(result, port.toSendPort());
173 break;
174 case WRITE_BYTE:
175 message["reply"].send(_File._writeByte(message["id"], message["value"]),
176 port.toSendPort());
177 break;
178 case WRITE_LIST:
179 var replyPort = message["reply"];
180 var buffer = message["buffer"];
181 var bytes = message["bytes"];
182 var offset = message["offset"];
183 var id = message["id"];
184 if (bytes == 0) {
185 replyPort.send(0, port.toSendPort());
186 return;
187 }
188 int index =
189 _File._checkReadWriteListArguments(buffer.length, offset, bytes);
190 if (index != 0) {
191 replyPort.send("index out of range in writeList: $index",
192 port.toSendPort());
193 return;
194 }
195 var result = _File._writeList(id, buffer, offset, bytes);
196 replyPort.send(result, port.toSendPort());
197 break;
198 case WRITE_STRING:
199 var id = message["id"];
200 var string = message["string"];
201 message["reply"].send(_File._writeString(id, string),
202 port.toSendPort());
203 break;
204 case POSITION:
205 message["reply"].send(_File._position(message["id"]),
206 port.toSendPort());
207 break;
208 case LENGTH:
209 message["reply"].send(_File._length(message["id"]),
210 port.toSendPort());
211 break;
212 case FLUSH:
213 message["reply"].send(_File._flush(message["id"]),
214 port.toSendPort());
215 break;
216 case EXIT:
217 port.close();
218 return;
219 }
220 port.receive(handleOperation);
221 }
222
223 void main() {
224 port.receive(handleOperation);
225 }
226 }
227
228
229 class _FileOperationScheduler {
230 _FileOperationScheduler() : _queue = new Queue();
231
232 void schedule(SendPort port) {
233 assert(_isolate != null);
234 if (_queue.isEmpty()) {
235 port.send({ "type": _FileOperationIsolate.EXIT });
236 _isolate = null;
237 } else {
238 port.send(_queue.removeFirst());
239 }
240 }
241
242 void scheduleWrap(void callback(result, ignored)) {
243 return (result, replyTo) {
244 callback(result, replyTo);
245 schedule(replyTo);
246 };
247 }
248
249 void enqueue(Map params, void callback(result, ignored)) {
250 ReceivePort replyPort = new ReceivePort.singleShot();
251 replyPort.receive(scheduleWrap(callback));
252 params["reply"] = replyPort.toSendPort();
253 _queue.addLast(params);
254 if (_isolate == null) {
255 _isolate = new _FileOperationIsolate();
256 _isolate.spawn().then((port) {
257 schedule(port);
258 });
259 }
260 }
261
262 bool noPendingWrite() {
263 int queuedWrites = 0;
264 _queue.forEach((map) {
265 if (_isWriteOperation(map["type"])) {
266 queuedWrites++;
267 }
268 });
269 return queuedWrites == 0;
270 }
271
272 bool _isWriteOperation(int type) {
273 return (type == _FileOperationIsolate.WRITE_BYTE) ||
274 (type == _FileOperationIsolate.WRITE_LIST) ||
275 (type == _FileOperationIsolate.WRITE_STRING);
276 }
277
278 Queue<Map> _queue;
279 _FileOperationIsolate _isolate;
280 }
281
282
117 // Class for encapsulating the native implementation of files. 283 // Class for encapsulating the native implementation of files.
118 class _File implements File { 284 class _File implements File {
119 // Constructor for file. 285 // Constructor for file.
120 _File(String this._name); 286 _File(String this._name)
287 : _scheduler = new _FileOperationScheduler(),
288 _asyncUsed = false;
289
290 static bool _exists(String name) native "File_Exists";
291 static int _open(String name, bool writable) native "File_Open";
292 static int _close(int id) native "File_Close";
293 static int _readByte(int id) native "File_ReadByte";
294 static int _readList(int id, List<int> buffer, int offset, int bytes)
295 native "File_ReadList";
296 static int _writeByte(int id, int value) native "File_WriteByte";
297 static int _writeList(int id, List<int> buffer, int offset, int bytes)
298 native "File_WriteList";
299 static int _writeString(int id, String string) native "File_WriteString";
300 static int _position(int id) native "File_Position";
301 static int _length(int id) native "File_Length";
302 static int _flush(int id) native "File_Flush";
303
304 static int _checkReadWriteListArguments(int length, int offset, int bytes) {
305 if (offset < 0) return offset;
306 if (bytes < 0) return bytes;
307 if ((offset + bytes) > length) return offset + bytes;
308 return 0;
309 }
121 310
122 void exists() { 311 void exists() {
312 _asyncUsed = true;
313 var handler =
314 (_existsHandler != null) ? _existsHandler : (result) => null;
315 Map params = {
316 "type": _FileOperationIsolate.EXISTS,
317 "name": _name
318 };
319 _scheduler.enqueue(params, (result, ignored) { _existsHandler(result); });
320 }
321
322 bool existsSync() {
323 if (_asyncUsed) {
324 throw new FileIOException(
325 "Mixed use of synchronous and asynchronous API");
326 }
327 return _exists(_name);
328 }
329
330 void create() {
331 _asyncUsed = true;
123 throw "Unimplemented"; 332 throw "Unimplemented";
124 } 333 }
125 334
126 bool existsSync() { 335 void createSync() {
127 return _fileExists(_name); 336 if (_asyncUsed) {
128 } 337 throw new FileIOException(
129 338 "Mixed use of synchronous and asynchronous API");
130 bool _fileExists(String name) native "File_Exists"; 339 }
131
132 void create() {
133 throw "Unimplemented"; 340 throw "Unimplemented";
134 } 341 }
135 342
136 void createSync() {
137 throw "Unimplemented";
138 }
139
140 void open([bool writable = false]) { 343 void open([bool writable = false]) {
141 throw "Unimplemented"; 344 _asyncUsed = true;
345 var handler = (_openHandler != null) ? _openHandler : () => null;
346 var handleOpenResult = (result, ignored) {
347 if (result != 0) {
348 _id = result;
349 handler();
350 } else if (_errorHandler != null) {
351 _errorHandler("Cannot open file: $_name");
352 }
353 };
354 Map params = {
355 "type": _FileOperationIsolate.OPEN,
356 "name": _name,
357 "writable": writable
358 };
359 _scheduler.enqueue(params, handleOpenResult);
142 } 360 }
143 361
144 void openSync([bool writable = false]) { 362 void openSync([bool writable = false]) {
145 if (!_openFile(_name, writable)) { 363 if (_asyncUsed) {
364 throw new FileIOException(
365 "Mixed use of synchronous and asynchronous API");
366 }
367 _id = _open(_name, writable);
368 if (_id == 0) {
146 throw new FileIOException("Cannot open file: $_name"); 369 throw new FileIOException("Cannot open file: $_name");
147 } 370 }
148 } 371 }
149 372
150 bool _openFile(String name, bool writable) native "File_OpenFile";
151
152 void close() { 373 void close() {
153 throw "Unimplemented"; 374 _asyncUsed = true;
375 var handler = (_closeHandler != null) ? _closeHandler : () => null;
376 var handleOpenResult = (result, ignored) {
377 if (result != -1) {
378 _id = result;
379 handler();
380 } else if (_errorHandler != null) {
381 _errorHandler("Cannot open file: $_name");
382 }
383 };
384 Map params = {
385 "type": _FileOperationIsolate.CLOSE,
386 "id": _id
387 };
388 _scheduler.enqueue(params, handleOpenResult);
154 } 389 }
155 390
156 void closeSync() { 391 void closeSync() {
157 _close(); 392 if (_asyncUsed) {
158 } 393 throw new FileIOException(
159 394 "Mixed use of synchronous and asynchronous API");
160 int _close() native "File_Close"; 395 }
396 _id = _close(_id);
397 if (_id == -1) {
398 throw new FileIOException("Cannot close file: $_name");
399 }
400 }
161 401
162 void readByte() { 402 void readByte() {
163 throw "Unimplemented"; 403 _asyncUsed = true;
404 var handler =
405 (_readByteHandler != null) ? _readByteHandler : (byte) => null;
406 var handleReadByteResult = (result, ignored) {
407 if (result != -1) {
408 handler(result);
409 } else if (_errorHandler != null) {
410 _errorHandler("readByte failed");
411 }
412 };
413 Map params = {
414 "type": _FileOperationIsolate.READ_BYTE,
415 "id": _id
416 };
417 _scheduler.enqueue(params, handleReadByteResult);
164 } 418 }
165 419
166 int readByteSync() { 420 int readByteSync() {
167 int result = _readByte(); 421 if (_asyncUsed) {
168 if (result == -1) { 422 throw new FileIOException(
169 throw new FileIOException("Error: readByte failed"); 423 "Mixed use of synchronous and asynchronous API");
170 } 424 }
171 return result; 425 int result = _readByte(_id);
172 } 426 if (result == -1) {
173 427 throw new FileIOException("readByte failed");
174 int _readByte() native "File_ReadByte"; 428 }
429 return result;
430 }
175 431
176 void readList(List<int> buffer, int offset, int bytes) { 432 void readList(List<int> buffer, int offset, int bytes) {
177 throw "Unimplemented"; 433 _asyncUsed = true;
434 var handler =
435 (_readListHandler != null) ? _readListHandler : (result) => null;
436 var handleReadListResult = (result, ignored) {
437 if (result is Map && result["read"] != -1) {
438 var read = result["read"];
439 buffer.setRange(offset, read, result["buffer"]);
440 handler(read);
441 return;
442 }
443 if (_errorHandler != null) {
444 _errorHandler(result is String ? result : "readList failed");
445 }
446 };
447 Map params = {
448 "type": _FileOperationIsolate.READ_LIST,
449 "length": buffer.length,
450 "offset": offset,
451 "bytes": bytes,
452 "id": _id
453 };
454 _scheduler.enqueue(params, handleReadListResult);
178 } 455 }
179 456
180 int readListSync(List<int> buffer, int offset, int bytes) { 457 int readListSync(List<int> buffer, int offset, int bytes) {
181 if (bytes == 0) { 458 if (_asyncUsed) {
182 return 0; 459 throw new FileIOException(
183 } 460 "Mixed use of synchronous and asynchronous API");
184 if (offset < 0) { 461 }
185 throw new IndexOutOfRangeException(offset); 462 if (bytes == 0) return 0;
186 } 463 int index = _checkReadWriteListArguments(buffer.length, offset, bytes);
187 if (bytes < 0) { 464 if (index != 0) {
188 throw new IndexOutOfRangeException(bytes); 465 throw new IndexOutOfRangeException(index);
189 } 466 }
190 if ((offset + bytes) > buffer.length) { 467 int result = _readList(_id, buffer, offset, bytes);
191 throw new IndexOutOfRangeException(offset + bytes); 468 if (result == -1) {
192 } 469 throw new FileIOException("readList failed");
193 int result = _readList(buffer, offset, bytes); 470 }
194 if (result == -1) { 471 return result;
195 throw new FileIOException("Error: readList failed"); 472 }
196 } 473
197 return result; 474 void _checkPendingWrites() {
198 } 475 if (_scheduler.noPendingWrite() && _noPendingWriteHandler != null) {
199 476 _noPendingWriteHandler();
200 int _readList(List<int> buffer, int offset, int bytes) native "File_ReadList"; 477 }
478 }
201 479
202 void writeByte(int value) { 480 void writeByte(int value) {
203 throw "Unimplemented"; 481 _asyncUsed = true;
482 var handleReadByteResult = (result, ignored) {
483 if (result == -1 &&_errorHandler != null) {
484 _errorHandler("writeByte failed");
485 return;
486 }
487 _checkPendingWrites();
488 };
489 Map params = {
490 "type": _FileOperationIsolate.WRITE_BYTE,
491 "value": value,
492 "id": _id
493 };
494 _scheduler.enqueue(params, handleReadByteResult);
204 } 495 }
205 496
206 int writeByteSync(int value) { 497 int writeByteSync(int value) {
207 int result = _writeByte(value); 498 if (_asyncUsed) {
208 if (result == -1) { 499 throw new FileIOException(
209 throw new FileIOException("Error: writeByte failed"); 500 "Mixed use of synchronous and asynchronous API");
210 } 501 }
211 return result; 502 int result = _writeByte(_id, value);
212 } 503 if (result == -1) {
213 504 throw new FileIOException("writeByte failed");
214 int _writeByte(int value) native "File_WriteByte"; 505 }
215 506 return result;
216 int writeList(List<int> buffer, int offset, int bytes) { 507 }
217 throw "Unimplemented"; 508
509 void writeList(List<int> buffer, int offset, int bytes) {
510 _asyncUsed = true;
511 var handleWriteListResult = (result, ignored) {
512 if (result is !String && result != -1) {
513 if (result < bytes) {
514 writeList(buffer, offset + result, bytes - result);
515 } else {
516 _checkPendingWrites();
517 }
518 return;
519 }
520 if (_errorHandler != null) {
521 _errorHandler(result is String ? result : "writeList failed");
522 }
523 };
524 Map params = {
525 "type": _FileOperationIsolate.WRITE_LIST,
526 "buffer": buffer,
527 "offset": offset,
528 "bytes": bytes,
529 "id": _id
530 };
531 _scheduler.enqueue(params, handleWriteListResult);
218 } 532 }
219 533
220 int writeListSync(List<int> buffer, int offset, int bytes) { 534 int writeListSync(List<int> buffer, int offset, int bytes) {
221 if (bytes == 0) { 535 if (_asyncUsed) {
222 return 0; 536 throw new FileIOException(
223 } 537 "Mixed use of synchronous and asynchronous API");
224 if (offset < 0) { 538 }
225 throw new IndexOutOfRangeException(offset); 539 if (bytes == 0) return 0;
226 } 540 int index = _checkReadWriteListArguments(buffer.length, offset, bytes);
227 if (bytes < 0) { 541 if (index != 0) {
228 throw new IndexOutOfRangeException(bytes); 542 throw new IndexOutOfRangeException(index);
229 } 543 }
230 if ((offset + bytes) > buffer.length) { 544 int result = _writeList(_id, buffer, offset, bytes);
231 throw new IndexOutOfRangeException(offset + bytes); 545 if (result == -1) {
232 } 546 throw new FileIOException("writeList failed");
233 int result = _writeList(buffer, offset, bytes); 547 }
234 if (result == -1) { 548 return result;
235 throw new FileIOException("Error: writeList failed"); 549 }
236 } 550
237 return result; 551 void writeString(String string) {
238 } 552 _asyncUsed = true;
239 553 var handleWriteStringResult = (result, ignored) {
240 int _writeList(List<int> buffer, int offset, int bytes) 554 if (result == -1 &&_errorHandler != null) {
241 native "File_WriteList"; 555 _errorHandler("writeString failed");
242 556 return;
243 int writeString(String string) { 557 }
244 throw "Unimplemented"; 558 if (result < string.length) {
559 writeString(string.substring(result));
560 } else {
561 _checkPendingWrites();
562 }
563 };
564 Map params = {
565 "type": _FileOperationIsolate.WRITE_STRING,
566 "string": string,
567 "id": _id
568 };
569 _scheduler.enqueue(params, handleWriteStringResult);
245 } 570 }
246 571
247 int writeStringSync(String string) { 572 int writeStringSync(String string) {
248 int result = _writeString(string); 573 if (_asyncUsed) {
574 throw new FileIOException(
575 "Mixed use of synchronous and asynchronous API");
576 }
577 int result = _writeString(_id, string);
249 if (result == -1) { 578 if (result == -1) {
250 throw new FileIOException("Error: writeString failed"); 579 throw new FileIOException("Error: writeString failed");
251 } 580 }
252 return result; 581 return result;
253 } 582 }
254 583
255 int _writeString(String string) native "File_WriteString"; 584 void position() {
256 585 _asyncUsed = true;
257 int position() { 586 var handler = (_positionHandler != null) ? _positionHandler : (pos) => null;
258 throw "Unimplemented"; 587 var handlePositionResult = (result, ignored) {
588 if (result == -1 && _errorHandler != null) {
589 _errorHandler("position failed");
590 return;
591 }
592 handler(result);
593 };
594 Map params = {
595 "type": _FileOperationIsolate.POSITION,
596 "id": _id
597 };
598 _scheduler.enqueue(params, handlePositionResult);
259 } 599 }
260 600
261 int positionSync() { 601 int positionSync() {
262 int result = _position; 602 if (_asyncUsed) {
263 if (result == -1) { 603 throw new FileIOException(
264 throw new FileIOException("Error: get position failed"); 604 "Mixed use of synchronous and asynchronous API");
265 } 605 }
266 return result; 606 int result = _position(_id);
267 } 607 if (result == -1) {
268 608 throw new FileIOException("position failed");
269 int get _position() native "File_Position"; 609 }
270 610 return result;
271 int length() { 611 }
272 throw "Unimplemented"; 612
613 void length() {
614 _asyncUsed = true;
615 var handler = (_lengthHandler != null) ? _lengthHandler : (pos) => null;
616 var handleLengthResult = (result, ignored) {
617 if (result == -1 && _errorHandler != null) {
618 _errorHandler("length failed");
619 return;
620 }
621 handler(result);
622 };
623 Map params = {
624 "type": _FileOperationIsolate.LENGTH,
625 "id": _id
626 };
627 _scheduler.enqueue(params, handleLengthResult);
273 } 628 }
274 629
275 int lengthSync() { 630 int lengthSync() {
276 int result = _length; 631 if (_asyncUsed) {
277 if (result == -1) { 632 throw new FileIOException(
278 throw new FileIOException("Error: get length failed"); 633 "Mixed use of synchronous and asynchronous API");
279 } 634 }
280 return result; 635 int result = _length(_id);
281 } 636 if (result == -1) {
282 637 throw new FileIOException("length failed");
283 int get _length() native "File_Length"; 638 }
639 return result;
640 }
284 641
285 void flush() { 642 void flush() {
286 throw "Unimplemented"; 643 _asyncUsed = true;
644 var handler = (_flushHandler != null) ? _flushHandler : (pos) => null;
645 var handleFlushResult = (result, ignored) {
646 if (result == -1 && _errorHandler != null) {
647 _errorHandler("flush failed");
648 return;
649 }
650 handler();
651 };
652 Map params = {
653 "type": _FileOperationIsolate.FLUSH,
654 "id": _id
655 };
656 _scheduler.enqueue(params, handleFlushResult);
287 } 657 }
288 658
289 void flushSync() { 659 void flushSync() {
290 int result = _flush(); 660 if (_asyncUsed) {
291 if (result == -1) { 661 throw new FileIOException(
292 throw new FileIOException("Error: flush failed"); 662 "Mixed use of synchronous and asynchronous API");
293 } 663 }
294 } 664 int result = _flush(_id);
295 665 if (result == -1) {
296 int _flush() native "File_Flush"; 666 throw new FileIOException("flush failed");
667 }
668 }
297 669
298 InputStream openInputStream() { 670 InputStream openInputStream() {
299 return new _FileInputStream(this); 671 return new _FileInputStream(this);
300 } 672 }
301 673
302 OutputStream openOutputStream() { 674 OutputStream openOutputStream() {
303 return new _FileOutputStream(this); 675 return new _FileOutputStream(this);
304 } 676 }
305 677
306 String get name() { 678 String get name() {
(...skipping 21 matching lines...) Expand all
328 } 700 }
329 701
330 void set readListHandler(void handler(int read)) { 702 void set readListHandler(void handler(int read)) {
331 _readListHandler = handler; 703 _readListHandler = handler;
332 } 704 }
333 705
334 void set noPendingWriteHandler(void handler()) { 706 void set noPendingWriteHandler(void handler()) {
335 _noPendingWriteHandler = handler; 707 _noPendingWriteHandler = handler;
336 } 708 }
337 709
710 void set positionHandler(void handler(int pos)) {
711 _positionHandler = handler;
712 }
713
714 void set lengthHandler(void handler(int length)) {
715 _lengthHandler = handler;
716 }
717
718 void set flushHandler(void handler()) {
719 _flushHandler = handler;
720 }
721
338 void set errorHandler(void handler(String error)) { 722 void set errorHandler(void handler(String error)) {
339 _errorHandler = handler; 723 _errorHandler = handler;
340 } 724 }
341 725
342 String _name; 726 String _name;
343 int _id; 727 int _id;
728 bool _asyncUsed;
729
730 _FileOperationScheduler _scheduler;
344 731
345 var _existsHandler; 732 var _existsHandler;
346 var _createHandler; 733 var _createHandler;
347 var _openHandler; 734 var _openHandler;
348 var _closeHandler; 735 var _closeHandler;
349 var _readByteHandler; 736 var _readByteHandler;
350 var _readListHandler; 737 var _readListHandler;
351 var _noPendingWriteHandler; 738 var _noPendingWriteHandler;
739 var _positionHandler;
740 var _lengthHandler;
741 var _flushHandler;
352 var _errorHandler; 742 var _errorHandler;
353 } 743 }
OLDNEW
« no previous file with comments | « runtime/bin/file.dart ('k') | runtime/lib/array.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698