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

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

Issue 9474004: Make FileInputStream and FileOutputStream actually asynchronous. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Remove accidental edit Created 8 years, 9 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
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 class _FileInputStream extends _BaseDataInputStream implements InputStream { 5 class _FileInputStream extends _BaseDataInputStream implements InputStream {
6 _FileInputStream(RandomAccessFile this._file, int this._length) { 6 _FileInputStream(String name) {
7 _streamMarkedClosed = true; 7 _file = new File(name);
8 _checkScheduleCallbacks(); 8 _data = [];
9 _position = 0;
10 _file.errorHandler = (String s) {
11 if (_clientErrorHandler != null) {
12 _clientErrorHandler();
13 }
14 };
15 _file.open();
16 _file.openHandler = (openedFile) {
17 _readDataFromFile(openedFile);
18 };
9 } 19 }
10 20
11 _FileInputStream.fromStdio(int fd) { 21 _FileInputStream.fromStdio(int fd) {
12 assert(fd == 0); 22 assert(fd == 0);
13 _file = _File._openStdioSync(fd); 23 _file = _File._openStdioSync(fd);
14 _length = _file.lengthSync(); 24 _data = [];
15 _streamMarkedClosed = true; 25 _position = 0;
16 _checkScheduleCallbacks(); 26 _readDataFromFile(_file);
27 }
28
29 void _readDataFromFile(RandomAccessFile openedFile) {
30 openedFile.errorHandler = (String s) {
31 if (_clientErrorHandler != null) {
32 _clientErrorHandler();
33 }
34 };
35 openedFile.length();
Søren Gjesse 2012/02/28 07:40:25 What is length when the file is stdin?
Søren Gjesse 2012/02/28 08:10:26 This is correct. I forgot that the constructor _Fi
36 openedFile.lengthHandler = (length) {
37 var contents = new ByteArray(length);
38 if (length != 0) {
39 openedFile.readList(contents, 0, length);
40 openedFile.readListHandler = (read) {
41 if (read != length) {
42 if (_clientErrorHandler != null) {
43 _clientErrorHandler();
44 }
45 _streamMarkedClosed = true;
46 _checkScheduleCallbacks();
47 } else {
48 _data = contents;
49 _streamMarkedClosed = true;
50 _checkScheduleCallbacks();
51 }
52 openedFile.close();
53 };
54 } else {
55 _streamMarkedClosed = true;
56 _checkScheduleCallbacks();
57 openedFile.close();
58 }
59 };
17 } 60 }
18 61
19 int available() { 62 int available() {
20 return _closed ? 0 : _length - _file.positionSync(); 63 return _closed ? 0 : _data.length - _position;
21 } 64 }
22 65
23 void pipe(OutputStream output, [bool close = true]) { 66 void pipe(OutputStream output, [bool close = true]) {
24 _pipe(this, output, close: close); 67 _pipe(this, output, close: close);
25 } 68 }
26 69
27 List<int> _read(int bytesToRead) { 70 List<int> _read(int bytesToRead) {
28 ByteArray result = new ByteArray(bytesToRead); 71 ByteArray result = new ByteArray(bytesToRead);
29 int bytesRead = _file.readListSync(result, 0, bytesToRead); 72 result.setRange(0, bytesToRead, _data, _position);
30 if (bytesRead < bytesToRead) { 73 _position += bytesToRead;
31 ByteArray buffer = new ByteArray(bytesRead);
32 buffer.setRange(0, bytesRead, result);
33 result = buffer;
34 }
35 _checkScheduleCallbacks(); 74 _checkScheduleCallbacks();
36 return result; 75 return result;
37 } 76 }
38 77
39 int _readInto(List<int> buffer, int offset, int len) { 78 int _readInto(List<int> buffer, int offset, int len) {
40 int result = _file.readListSync(buffer, offset, len); 79 buffer.setRange(offset, len, _data, _position);
80 _position += len;
41 _checkScheduleCallbacks(); 81 _checkScheduleCallbacks();
42 return result; 82 return len;
43 } 83 }
44 84
45 void _close() { 85 void _close() {
46 if (_closed) return; 86 if (_closed) return;
47 _file.closeSync();
48 _closed = true; 87 _closed = true;
49 } 88 }
50 89
51 RandomAccessFile _file; 90 File _file;
52 int _length; 91 List<int> _data;
92 int _position;
53 bool _closed = false; 93 bool _closed = false;
54 } 94 }
55 95
56 96
57 class _FileOutputStream implements OutputStream { 97 class _FileOutputStream implements OutputStream {
58 _FileOutputStream(this._file); 98 _FileOutputStream(String name, int mode) {
99 _pendingOperations = new List<List<int>>();
100 var f = new File(name);
101 f.open(mode);
102 f.openHandler = (openedFile) {
103 _file = openedFile;
104 _setupFileHandlers();
105 _processPendingOperations();
106 };
107 f.errorHandler = (e) {
108 if (_errorHandler != null) _errorHandler();
109 };
110 }
59 111
60 _FileOutputStream.fromStdio(int fd) { 112 _FileOutputStream.fromStdio(int fd) {
61 assert(1 <= fd && fd <= 2); 113 assert(1 <= fd && fd <= 2);
62 _file = _File._openStdioSync(fd); 114 _file = _File._openStdioSync(fd);
115 _setupFileHandlers();
116 }
117
118
119 void _setupFileHandlers() {
120 _file.errorHandler = (e) {
121 if (_errorHandler != null) _errorHandler();
122 };
123 _file.noPendingWriteHandler = () {
124 if (!_streamMarkedClosed && _noPendingWriteHandler != null) {
125 _noPendingWriteHandler();
126 }
127 };
128 _file.closeHandler = () {
129 if (_closeHandler != null) _closeHandler();
130 };
63 } 131 }
64 132
65 bool write(List<int> buffer, [bool copyBuffer = false]) { 133 bool write(List<int> buffer, [bool copyBuffer = false]) {
66 bool result = _write(buffer, 0, buffer.length); 134 var data = buffer;
67 if (result) { 135 if (copyBuffer) {
68 _checkScheduleCallbacks(); 136 var length = buffer.length;
137 data = new ByteArray(length);
138 data.setRange(0, length, buffer, 0);
69 } 139 }
70 return result; 140 if (_file == null) {
141 _pendingOperations.add(data);
142 } else {
143 _write(data, 0, data.length);
144 }
145 return false;
Søren Gjesse 2012/02/28 07:40:25 We should probably revisit whether write and write
Mads Ager (google) 2012/02/28 08:21:00 Agreed, we probably should.
71 } 146 }
72 147
73 bool writeFrom(List<int> buffer, [int offset = 0, int len]) { 148 bool writeFrom(List<int> buffer, [int offset = 0, int len]) {
74 bool result = _write( 149 // A copy is required by the interface.
75 buffer, offset, (len == null) ? buffer.length - offset : len); 150 var length = buffer.length - offset;
76 if (result) { 151 if (len != null) {
77 _checkScheduleCallbacks(); 152 if (len > length) throw new IndexOutOfRangeException(len);
153 length = len;
78 } 154 }
79 return result; 155 var copy = new ByteArray(length);
156 copy.setRange(0, length, buffer, offset);
157 return write(copy);
80 } 158 }
81 159
82 void close() { 160 void close() {
83 if (_scheduledNoPendingWriteCallback != null) { 161 if (_file == null) {
84 _scheduledNoPendingWriteCallback.cancel(); 162 _pendingOperations.add(null);
85 } 163 } else {
86 if (!_streamMarkedClosed) { 164 if (!_streamMarkedClosed) {
87 _file.closeSync(); 165 _file.close();
88 _streamMarkedClosed = true; 166 _streamMarkedClosed = true;
89 _checkScheduleCallbacks(); 167 }
90 } 168 }
91 } 169 }
92 170
93 void set noPendingWriteHandler(void callback()) { 171 void set noPendingWriteHandler(void callback()) {
94 _noPendingWriteHandler = callback; 172 _noPendingWriteHandler = callback;
95 _checkScheduleCallbacks();
96 } 173 }
97 174
98 void set closeHandler(void callback()) { 175 void set closeHandler(void callback()) {
99 _closeHandler = callback; 176 _closeHandler = callback;
100 _checkScheduleCallbacks();
101 } 177 }
102 178
103 void set errorHandler(void callback()) { 179 void set errorHandler(void callback()) {
104 // TODO(sgjesse): How to handle this? 180 _errorHandler = callback;
105 } 181 }
106 182
107 bool _write(List<int> buffer, int offset, int len) { 183 void _processPendingOperations() {
108 int bytesWritten = _file.writeListSync(buffer, offset, len); 184 _pendingOperations.forEach((buffer) {
109 if (bytesWritten == len) { 185 (buffer != null) ? write(buffer) : close();
110 return true; 186 });
111 } else { 187 _pendingOperations = null;
112 throw "FileOutputStream: write error";
113 }
114 } 188 }
115 189
116 void _checkScheduleCallbacks() { 190 void _write(List<int> buffer, int offset, int len) {
117 void issueNoPendingWriteCallback(Timer timer) { 191 _file.writeList(buffer, offset, len);
118 _scheduledNoPendingWriteCallback = null;
119 if (_noPendingWriteHandler !== null) {
120 _noPendingWriteHandler();
121 _checkScheduleCallbacks();
122 }
123 }
124
125 void issueCloseCallback(Timer timer) {
126 if (_closeHandler !== null) _closeHandler();
127 }
128
129 // Schedule no pending write callbacks if the stream is not yet
130 // closed and close callback if it is closing.
131 if (!_closeCallbackCalled) {
132 if (_scheduledNoPendingWriteCallback == null) {
133 _scheduledNoPendingWriteCallback =
134 new Timer(issueNoPendingWriteCallback, 0);
135 }
136 if (_streamMarkedClosed && _scheduledCloseCallback == null) {
137 _scheduledCloseCallback = new Timer(issueCloseCallback, 0);
138 }
139 }
140 } 192 }
141 193
142 RandomAccessFile _file; 194 RandomAccessFile _file;
143 195
144 // When this is set to true the stream is marked closed. When a 196 // When this is set to true the stream is marked closed. When a
145 // stream is marked closed no more data can be written. 197 // stream is marked closed no more data can be written.
146 bool _streamMarkedClosed = false; 198 bool _streamMarkedClosed = false;
147 199
148 // When this is set to true the close callback has been called and 200 // When this is set to true the close callback has been called and
149 // the stream is fully closed. 201 // the stream is fully closed.
150 bool _closeCallbackCalled = false; 202 bool _closeCallbackCalled = false;
151 203
152 Timer _scheduledNoPendingWriteCallback; 204 // List of pending writes that were issued before the underlying
153 Timer _scheduledCloseCallback; 205 // file was successfully opened.
206 List<List<int>> _pendingOperations;
207
154 Function _noPendingWriteHandler; 208 Function _noPendingWriteHandler;
155 Function _closeHandler; 209 Function _closeHandler;
210 Function _errorHandler;
156 } 211 }
157 212
158 213
159 // Helper class containing static file helper methods. 214 // Helper class containing static file helper methods.
160 class _FileUtils { 215 class _FileUtils {
161 static final kExistsRequest = 0; 216 static final kExistsRequest = 0;
162 static final kCreateRequest = 1; 217 static final kCreateRequest = 1;
163 static final kDeleteRequest = 2; 218 static final kDeleteRequest = 2;
164 static final kOpenRequest = 3; 219 static final kOpenRequest = 3;
165 static final kFullPathRequest = 4; 220 static final kFullPathRequest = 4;
(...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after
454 throw new FileIOException( 509 throw new FileIOException(
455 "Mixed use of synchronous and asynchronous API"); 510 "Mixed use of synchronous and asynchronous API");
456 } 511 }
457 String result = _FileUtils.checkedFullPath(_name); 512 String result = _FileUtils.checkedFullPath(_name);
458 if (result == null) { 513 if (result == null) {
459 throw new FileIOException("fullPath failed"); 514 throw new FileIOException("fullPath failed");
460 } 515 }
461 return result; 516 return result;
462 } 517 }
463 518
464 void openInputStream() { 519 void openInputStream() {
Søren Gjesse 2012/02/28 07:40:25 So you kept the Sync/non Sync versions for now?
Mads Ager (google) 2012/02/28 08:21:00 Yes, I will do a follow-up change today to get rid
465 _asyncUsed = true; 520 _asyncUsed = true;
466 // Create a new file object to handle the opening of the file for 521 // Create a new file object to handle the opening of the file for
467 // creating an input stream. Currently the file input stream uses 522 // creating an input stream. Currently the file input stream uses
468 // synchronous calls on the opened file so we need to open it 523 // synchronous calls on the opened file so we need to open it
469 // synchronously. 524 // synchronously.
470 File file = new File(this._name); 525 new Timer((t) {
471 file.errorHandler = (String error) { 526 if (_inputStreamHandler != null) {
472 if (_errorHandler != null) _errorHandler(error); 527 _inputStreamHandler(new _FileInputStream(_name));
473 }; 528 }
474 RandomAccessFile openedFile = file.openSync(); 529 }, 0);
475 InputStream stream =
476 new _FileInputStream(openedFile, openedFile.lengthSync());
477 new Timer(
478 (Timer ignore) {
479 if (_inputStreamHandler != null) _inputStreamHandler(stream);
480 }, 0);
481 } 530 }
482 531
483 InputStream openInputStreamSync() { 532 InputStream openInputStreamSync() {
484 if (_asyncUsed) { 533 return new _FileInputStream(_name);
485 throw new FileIOException(
486 "Mixed use of synchronous and asynchronous API");
487 }
488 RandomAccessFile openedFile = openSync();
489 return new _FileInputStream(openedFile, openedFile.lengthSync());
490 } 534 }
491 535
492 void openOutputStream([FileMode mode = FileMode.WRITE]) { 536 void openOutputStream([FileMode mode = FileMode.WRITE]) {
493 _asyncUsed = true; 537 _asyncUsed = true;
494 if (mode != FileMode.WRITE && 538 if (mode != FileMode.WRITE &&
495 mode != FileMode.APPEND) { 539 mode != FileMode.APPEND) {
496 throw new FileIOException( 540 throw new FileIOException(
497 "Wrong FileMode. Use FileMode.WRITE or FileMode.APPEND"); 541 "Wrong FileMode. Use FileMode.WRITE or FileMode.APPEND");
498 } 542 }
499 // Create a new file object to handle the opening of the file for 543 OutputStream stream = new _FileOutputStream(_name, mode);
500 // creating an input stream. Currently the file input stream uses
501 // synchronous calls on the opened file so we need to open it
502 // synchronously.
503 File file = new File(this._name);
504 file.errorHandler = (String error) {
505 if (_errorHandler != null) _errorHandler(error);
506 };
507 RandomAccessFile openedFile = file.openSync(mode);
508 OutputStream stream = new _FileOutputStream(openedFile);
509 new Timer( 544 new Timer(
510 (Timer ignore) { 545 (Timer ignore) {
511 if (_outputStreamHandler != null) _outputStreamHandler(stream); 546 if (_outputStreamHandler != null) _outputStreamHandler(stream);
512 }, 0); 547 }, 0);
513 } 548 }
514 549
515 OutputStream openOutputStreamSync([FileMode mode = FileMode.WRITE]) { 550 OutputStream openOutputStreamSync([FileMode mode = FileMode.WRITE]) {
516 if (_asyncUsed) { 551 if (_asyncUsed) {
517 throw new FileIOException( 552 throw new FileIOException(
518 "Mixed use of synchronous and asynchronous API"); 553 "Mixed use of synchronous and asynchronous API");
519 } 554 }
520 if (mode != FileMode.WRITE && 555 if (mode != FileMode.WRITE &&
521 mode != FileMode.APPEND) { 556 mode != FileMode.APPEND) {
522 throw new FileIOException( 557 throw new FileIOException(
523 "Wrong FileMode. Use FileMode.WRITE or FileMode.APPEND"); 558 "Wrong FileMode. Use FileMode.WRITE or FileMode.APPEND");
524 } 559 }
525 RandomAccessFile openedFile = openSync(mode); 560 return new _FileOutputStream(_name, mode);
526 return new _FileOutputStream(openedFile);
527 } 561 }
528 562
529 void readAsBytes() { 563 void readAsBytes() {
530 _asyncUsed = true; 564 _asyncUsed = true;
531 var chunks = new _BufferList(); 565 var chunks = new _BufferList();
532 openInputStream(); 566 var stream = openInputStreamSync();
533 inputStreamHandler = (inputStream) { 567 stream.closeHandler = () {
534 inputStream.closeHandler = () { 568 if (_readAsBytesHandler != null) {
535 if (_readAsBytesHandler != null) { 569 _readAsBytesHandler(chunks.readBytes(chunks.length));
536 _readAsBytesHandler(chunks.readBytes(chunks.length)); 570 }
537 } 571 };
538 }; 572 stream.dataHandler = () {
539 inputStream.dataHandler = () { 573 var chunk = stream.read();
540 var chunk = inputStream.read(); 574 chunks.add(chunk);
541 chunks.add(chunk); 575 };
542 }; 576 stream.errorHandler = () {
543 inputStream.errorHandler = () { 577 if (_errorHandler != null) {
544 if (_errorHandler != null) { 578 _errorHandler("Failed to read file as bytes: $_name");
545 _errorHandler("Failed to read file as bytes: $_name"); 579 }
546 }
547 };
548 }; 580 };
549 } 581 }
550 582
551 List<int> readAsBytesSync() { 583 List<int> readAsBytesSync() {
552 if (_asyncUsed) { 584 if (_asyncUsed) {
553 throw new FileIOException( 585 throw new FileIOException(
554 "Mixed use of synchronous and asynchronous API"); 586 "Mixed use of synchronous and asynchronous API");
555 } 587 }
556 var opened = openSync(); 588 var opened = openSync();
557 var length = opened.lengthSync(); 589 var length = opened.lengthSync();
558 var result = new ByteArray(length); 590 var result = new ByteArray(length);
559 var read = opened.readListSync(result, 0, length); 591 var read = opened.readListSync(result, 0, length);
560 if (read != length) { 592 if (read != length) {
561 throw new FileIOException("Failed reading file as bytes: $_name"); 593 throw new FileIOException("Failed reading file as bytes: $_name");
562 } 594 }
595 opened.close();
563 return result; 596 return result;
564 } 597 }
565 598
566 _StringDecoder _getDecoder(encoding) { 599 _StringDecoder _getDecoder(encoding) {
567 if (encoding == "UTF-8") { 600 if (encoding == "UTF-8") {
568 return new _UTF8Decoder(); 601 return new _UTF8Decoder();
569 } else if (encoding == "ISO-8859-1") { 602 } else if (encoding == "ISO-8859-1") {
570 return new _Latin1Decoder(); 603 return new _Latin1Decoder();
571 } else if (encoding == "ASCII") { 604 } else if (encoding == "ASCII") {
572 return new _AsciiDecoder(); 605 return new _AsciiDecoder();
(...skipping 526 matching lines...) Expand 10 before | Expand all | Expand 10 after
1099 void set readByteHandler(void handler(int byte)) { 1132 void set readByteHandler(void handler(int byte)) {
1100 _readByteHandler = handler; 1133 _readByteHandler = handler;
1101 } 1134 }
1102 1135
1103 void set readListHandler(void handler(int read)) { 1136 void set readListHandler(void handler(int read)) {
1104 _readListHandler = handler; 1137 _readListHandler = handler;
1105 } 1138 }
1106 1139
1107 void set noPendingWriteHandler(void handler()) { 1140 void set noPendingWriteHandler(void handler()) {
1108 _noPendingWriteHandler = handler; 1141 _noPendingWriteHandler = handler;
1142 if (_pendingWrites == 0) {
1143 _noPendingWriteTimer = new Timer((t) {
1144 if (_noPendingWriteHandler != null) _noPendingWriteHandler();
1145 }, 0);
1146 }
1109 } 1147 }
1110 1148
1111 void set positionHandler(void handler(int pos)) { 1149 void set positionHandler(void handler(int pos)) {
1112 _positionHandler = handler; 1150 _positionHandler = handler;
1113 } 1151 }
1114 1152
1115 void set setPositionHandler(void handler()) { 1153 void set setPositionHandler(void handler()) {
1116 _setPositionHandler = handler; 1154 _setPositionHandler = handler;
1117 } 1155 }
1118 1156
1119 void set truncateHandler(void handler()) { 1157 void set truncateHandler(void handler()) {
1120 _truncateHandler = handler; 1158 _truncateHandler = handler;
1121 } 1159 }
1122 1160
1123 void set lengthHandler(void handler(int length)) { 1161 void set lengthHandler(void handler(int length)) {
1124 _lengthHandler = handler; 1162 _lengthHandler = handler;
1125 } 1163 }
1126 1164
1127 void set flushHandler(void handler()) { 1165 void set flushHandler(void handler()) {
1128 _flushHandler = handler; 1166 _flushHandler = handler;
1129 } 1167 }
1130 1168
1131 void _ensureFileService() { 1169 void _ensureFileService() {
1132 if (_fileService == null) { 1170 if (_fileService == null) {
1133 _fileService = _FileUtils.newServicePort(); 1171 _fileService = _FileUtils.newServicePort();
1134 } 1172 }
1135 } 1173 }
1136 1174
1137 void _writeEnqueued() => _pendingWrites++; 1175 void _writeEnqueued() {
1176 _pendingWrites++;
1177 if (_noPendingWriteTimer != null) {
1178 _noPendingWriteTimer.cancel();
1179 _noPendingWriteTimer = null;
1180 }
1181 }
1138 1182
1139 void _writeCompleted() { 1183 void _writeCompleted() {
1140 _pendingWrites--; 1184 _pendingWrites--;
1141 if (_pendingWrites == 0 && _noPendingWriteHandler != null) { 1185 if (_pendingWrites == 0 && _noPendingWriteHandler != null) {
1142 _noPendingWriteHandler(); 1186 _noPendingWriteHandler();
1143 } 1187 }
1144 } 1188 }
1145 1189
1146 1190
1147 String _name; 1191 String _name;
1148 int _id; 1192 int _id;
1149 bool _asyncUsed; 1193 bool _asyncUsed;
1150 int _pendingWrites = 0; 1194 int _pendingWrites = 0;
1151 1195
1152 SendPort _fileService; 1196 SendPort _fileService;
1153 1197
1198 Timer _noPendingWriteTimer;
1199
1154 Function _closeHandler; 1200 Function _closeHandler;
1155 Function _readByteHandler; 1201 Function _readByteHandler;
1156 Function _readListHandler; 1202 Function _readListHandler;
1157 Function _noPendingWriteHandler; 1203 Function _noPendingWriteHandler;
1158 Function _positionHandler; 1204 Function _positionHandler;
1159 Function _setPositionHandler; 1205 Function _setPositionHandler;
1160 Function _truncateHandler; 1206 Function _truncateHandler;
1161 Function _lengthHandler; 1207 Function _lengthHandler;
1162 Function _flushHandler; 1208 Function _flushHandler;
1163 Function _errorHandler; 1209 Function _errorHandler;
1164 } 1210 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698