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

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

Issue 9415043: Port async file operations to be using native ports instead or an isolate (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Implemented all file operations using native ports 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
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(File file) { 6 _FileInputStream(File file) {
7 _file = file.openSync(); 7 _file = file.openSync();
8 _length = _file.lengthSync(); 8 _length = _file.lengthSync();
9 _streamMarkedClosed = true; 9 _streamMarkedClosed = true;
10 _checkScheduleCallbacks(); 10 _checkScheduleCallbacks();
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
97 return true; 97 return true;
98 } else { 98 } else {
99 throw "FileOutputStream: write error"; 99 throw "FileOutputStream: write error";
100 } 100 }
101 } 101 }
102 102
103 RandomAccessFile _file; 103 RandomAccessFile _file;
104 } 104 }
105 105
106 106
107 class _FileOperation {
108 abstract void execute(ReceivePort port);
109
110 void set replyPort(SendPort port) {
111 _replyPort = port;
112 }
113
114 bool isWrite() => false;
115
116 SendPort _replyPort;
117 }
118
119
120 class _ExistsOperation extends _FileOperation {
121 _ExistsOperation(String this._name);
122
123 void execute(ReceivePort port) {
124 _replyPort.send(_FileUtils.exists(_name), port.toSendPort());
125 }
126
127 String _name;
128 }
129
130
131 class _OpenOperation extends _FileOperation {
132 _OpenOperation(String this._name, int this._mode);
133
134 void execute(ReceivePort port) {
135 _replyPort.send(_FileUtils.checkedOpen(_name, _mode),
136 port.toSendPort());
137 }
138
139 String _name;
140 int _mode;
141 }
142
143
144 class _CloseOperation extends _FileOperation {
145 _CloseOperation(int this._id);
146
147 void execute(ReceivePort port) {
148 _replyPort.send(_FileUtils.close(_id), port.toSendPort());
149 }
150
151 int _id;
152 }
153
154
155 class _ReadByteOperation extends _FileOperation {
156 _ReadByteOperation(int this._id);
157
158 void execute(ReceivePort port) {
159 _replyPort.send(_FileUtils.readByte(_id), port.toSendPort());
160 }
161
162 int _id;
163 }
164
165
166 class _ReadListResult {
167 _ReadListResult(this.read, this.buffer);
168 int read;
169 List buffer;
170 }
171
172
173 class _ReadListOperation extends _FileOperation {
174 _ReadListOperation(int this._id,
175 int this._length,
176 int this._offset,
177 int this._bytes);
178
179 void execute(ReceivePort port) {
180 if (_bytes == 0) {
181 _replyPort.send(0, port.toSendPort());
182 return;
183 }
184 int index =
185 _FileUtils.checkReadWriteListArguments(_length, _offset, _bytes);
186 if (index != 0) {
187 _replyPort.send("index out of range in readList: $index",
188 port.toSendPort());
189 return;
190 }
191 ByteArray buffer = new ByteArray(_bytes);
192 var result =
193 new _ReadListResult(_FileUtils.readList(_id, buffer, 0, _bytes),
194 buffer);
195 _replyPort.send(result, port.toSendPort());
196 }
197
198 int _id;
199 int _length;
200 int _offset;
201 int _bytes;
202 }
203
204
205 class _WriteByteOperation extends _FileOperation {
206 _WriteByteOperation(int this._id, int this._value);
207
208 void execute(ReceivePort port) {
209 _replyPort.send(_FileUtils.writeByte(_id, _value), port.toSendPort());
210 }
211
212 bool isWrite() => true;
213
214 int _id;
215 int _value;
216 }
217
218
219 class _WriteListOperation extends _FileOperation {
220 _WriteListOperation(int this._id,
221 List this._buffer,
222 int this._offset,
223 int this._bytes);
224
225 void execute(ReceivePort port) {
226 if (_bytes == 0) {
227 _replyPort.send(0, port.toSendPort());
228 return;
229 }
230 int index =
231 _FileUtils.checkReadWriteListArguments(_buffer.length, _offset, _bytes);
232 if (index != 0) {
233 _replyPort.send("index out of range in writeList: $index",
234 port.toSendPort());
235 return;
236 }
237 var result = _FileUtils.writeList(_id, _buffer, _offset, _bytes);
238 _replyPort.send(result, port.toSendPort());
239 }
240
241 bool isWrite() => true;
242
243 int _id;
244 List _buffer;
245 int _offset;
246 int _bytes;
247 }
248
249
250 class _WriteStringOperation extends _FileOperation {
251 _WriteStringOperation(int this._id, String this._string);
252
253 void execute(ReceivePort port) {
254 _replyPort.send(_FileUtils.checkedWriteString(_id, _string),
255 port.toSendPort());
256 }
257
258 bool isWrite() => true;
259
260 int _id;
261 String _string;
262 }
263
264
265 class _PositionOperation extends _FileOperation {
266 _PositionOperation(int this._id);
267
268 void execute(ReceivePort port) {
269 _replyPort.send(_FileUtils.position(_id), port.toSendPort());
270 }
271
272 int _id;
273 }
274
275
276 class _SetPositionOperation extends _FileOperation {
277 _SetPositionOperation(int this._id, int this._position);
278
279 void execute(ReceivePort port) {
280 _replyPort.send(_FileUtils.setPosition(_id, _position), port.toSendPort());
281 }
282
283 int _id;
284 int _position;
285 }
286
287
288 class _TruncateOperation extends _FileOperation {
289 _TruncateOperation(int this._id, int this._length);
290
291 void execute(ReceivePort port) {
292 _replyPort.send(_FileUtils.truncate(_id, _length), port.toSendPort());
293 }
294
295 int _id;
296 int _length;
297 }
298
299
300 class _LengthOperation extends _FileOperation {
301 _LengthOperation(int this._id);
302
303 void execute(ReceivePort port) {
304 _replyPort.send(_FileUtils.length(_id), port.toSendPort());
305 }
306
307 int _id;
308 }
309
310
311 class _FlushOperation extends _FileOperation {
312 _FlushOperation(int this._id);
313
314 void execute(ReceivePort port) {
315 _replyPort.send(_FileUtils.flush(_id), port.toSendPort());
316 }
317
318 int _id;
319 }
320
321
322 class _FullPathOperation extends _FileOperation {
323 _FullPathOperation(String this._name);
324
325 void execute(ReceivePort port) {
326 _replyPort.send(_FileUtils.checkedFullPath(_name), port.toSendPort());
327 }
328
329 String _name;
330 }
331
332
333 class _CreateOperation extends _FileOperation {
334 _CreateOperation(String this._name);
335
336 void execute(ReceivePort port) {
337 _replyPort.send(_FileUtils.checkedCreate(_name), port.toSendPort());
338 }
339
340 String _name;
341 }
342
343
344 class _DeleteOperation extends _FileOperation {
345 _DeleteOperation(String this._name);
346
347 void execute(ReceivePort port) {
348 _replyPort.send(_FileUtils.checkedDelete(_name), port.toSendPort());
349 }
350
351 String _name;
352 }
353
354
355 class _ExitOperation extends _FileOperation {
356 void execute(ReceivePort port) {
357 port.close();
358 }
359 }
360
361
362 class _FileOperationIsolate extends Isolate {
363 _FileOperationIsolate() : super.heavy();
364
365 void handleOperation(_FileOperation message, SendPort ignored) {
366 message.execute(port);
367 port.receive(handleOperation);
368 }
369
370 void main() {
371 port.receive(handleOperation);
372 }
373 }
374
375
376 class _FileOperationScheduler {
377 _FileOperationScheduler() : _queue = new Queue();
378
379 void schedule(SendPort port) {
380 assert(_isolate != null);
381 if (_queue.isEmpty()) {
382 port.send(new _ExitOperation());
383 _isolate = null;
384 } else {
385 port.send(_queue.removeFirst());
386 }
387 }
388
389 void scheduleWrap(void callback(result, ignored)) {
390 return (result, replyTo) {
391 callback(result, replyTo);
392 schedule(replyTo);
393 };
394 }
395
396 void enqueue(_FileOperation operation, void callback(result, ignored)) {
397 ReceivePort replyPort = new ReceivePort.singleShot();
398 replyPort.receive(scheduleWrap(callback));
399 operation.replyPort = replyPort.toSendPort();
400 _queue.addLast(operation);
401 if (_isolate == null) {
402 _isolate = new _FileOperationIsolate();
403 _isolate.spawn().then((port) {
404 schedule(port);
405 });
406 }
407 }
408
409 bool noPendingWrite() {
410 int queuedWrites = 0;
411 _queue.forEach((operation) {
412 if (operation.isWrite()) {
413 queuedWrites++;
414 }
415 });
416 return queuedWrites == 0;
417 }
418
419 Queue<_FileOperation> _queue;
420 _FileOperationIsolate _isolate;
421 }
422
423
424 // Helper class containing static file helper methods. 107 // Helper class containing static file helper methods.
425 class _FileUtils { 108 class _FileUtils {
109 static final kExistsRequest = 0;
110 static final kCreateRequest = 1;
111 static final kDeleteRequest = 2;
112 static final kOpenRequest = 3;
113 static final kFullPathRequest = 4;
114 static final kCloseRequest = 5;
115 static final kPositionRequest = 6;
116 static final kSetPositionRequest = 7;
117 static final kTruncateRequest = 8;
118 static final kLengthRequest = 9;
119 static final kFlushRequest = 10;
120 static final kReadByteRequest = 11;
121 static final kWriteByteRequest = 12;
122 static final kReadListRequest = 13;
123 static final kWriteListRequest = 14;
124 static final kWriteStringRequest = 15;
125
426 static bool exists(String name) native "File_Exists"; 126 static bool exists(String name) native "File_Exists";
427 static int open(String name, int mode) native "File_Open"; 127 static int open(String name, int mode) native "File_Open";
428 static bool create(String name) native "File_Create"; 128 static bool create(String name) native "File_Create";
429 static bool delete(String name) native "File_Delete"; 129 static bool delete(String name) native "File_Delete";
430 static String fullPath(String name) native "File_FullPath"; 130 static String fullPath(String name) native "File_FullPath";
431 static int close(int id) native "File_Close"; 131 static int close(int id) native "File_Close";
432 static int readByte(int id) native "File_ReadByte"; 132 static int readByte(int id) native "File_ReadByte";
433 static int readList(int id, List<int> buffer, int offset, int bytes) 133 static int readList(int id, List<int> buffer, int offset, int bytes)
434 native "File_ReadList"; 134 native "File_ReadList";
435 static int writeByte(int id, int value) native "File_WriteByte"; 135 static int writeByte(int id, int value) native "File_WriteByte";
(...skipping 23 matching lines...) Expand all
459 } 159 }
460 static int writeListNative(int id, List<int> buffer, int offset, int bytes) 160 static int writeListNative(int id, List<int> buffer, int offset, int bytes)
461 native "File_WriteList"; 161 native "File_WriteList";
462 static int writeString(int id, String string) native "File_WriteString"; 162 static int writeString(int id, String string) native "File_WriteString";
463 static int position(int id) native "File_Position"; 163 static int position(int id) native "File_Position";
464 static bool setPosition(int id, int position) native "File_SetPosition"; 164 static bool setPosition(int id, int position) native "File_SetPosition";
465 static bool truncate(int id, int length) native "File_Truncate"; 165 static bool truncate(int id, int length) native "File_Truncate";
466 static int length(int id) native "File_Length"; 166 static int length(int id) native "File_Length";
467 static int flush(int id) native "File_Flush"; 167 static int flush(int id) native "File_Flush";
468 static int openStdio(int fd) native "File_OpenStdio"; 168 static int openStdio(int fd) native "File_OpenStdio";
169 static SendPort newServicePort() native "File_NewServicePort";
469 170
470 static int checkedOpen(String name, int mode) { 171 static int checkedOpen(String name, int mode) {
471 if (name is !String || mode is !int) return 0; 172 if (name is !String || mode is !int) return 0;
472 return open(name, mode); 173 return open(name, mode);
473 } 174 }
474 175
475 static bool checkedCreate(String name) { 176 static bool checkedCreate(String name) {
476 if (name is !String) return false; 177 if (name is !String) return false;
477 return create(name); 178 return create(name);
478 } 179 }
(...skipping 18 matching lines...) Expand all
497 static int checkedWriteString(int id, String string) { 198 static int checkedWriteString(int id, String string) {
498 if (string is !String) return -1; 199 if (string is !String) return -1;
499 return writeString(id, string); 200 return writeString(id, string);
500 } 201 }
501 } 202 }
502 203
503 204
504 // Class for encapsulating the native implementation of files. 205 // Class for encapsulating the native implementation of files.
505 class _File implements File { 206 class _File implements File {
506 // Constructor for file. 207 // Constructor for file.
507 _File(String this._name) 208 _File(String this._name) : _asyncUsed = false;
508 : _scheduler = new _FileOperationScheduler(),
509 _asyncUsed = false;
510 209
511 void exists() { 210 void exists() {
211 if (_fileService == null) {
Mads Ager (google) 2012/02/20 13:50:31 How about having an ensureFileService here as well
Søren Gjesse 2012/02/21 14:22:39 Done.
212 _fileService = _FileUtils.newServicePort();
213 }
512 _asyncUsed = true; 214 _asyncUsed = true;
513 if (_name is !String) { 215 if (_name is !String) {
514 if (_errorHandler != null) { 216 if (_errorHandler != null) {
515 _errorHandler('File name is not a string: $_name'); 217 _errorHandler('File name is not a string: $_name');
516 } 218 }
517 return; 219 return;
518 } 220 }
519 var operation = new _ExistsOperation(_name); 221 List request = new List(2);
Mads Ager (google) 2012/02/20 13:50:31 Why not use list literals here? var request = [ _
Søren Gjesse 2012/02/21 14:22:39 Yes, but we cannot serialize list literals :-( I w
520 _scheduler.enqueue(operation, (result, ignored) { 222 request[0] = _FileUtils.kExistsRequest;
521 var handler = 223 request[1] = _name;
522 (_existsHandler != null) ? _existsHandler : (result) => null; 224 _fileService.call(request).receive((exists, replyTo) {
523 handler(result); 225 if (_existsHandler != null) _existsHandler(exists);
Mads Ager (google) 2012/02/20 13:50:31 Indentation is off. Here and in the rest of the fi
Søren Gjesse 2012/02/21 14:22:39 Done (Emacs Dart mode thinks this is the way).
524 }); 226 });
525 } 227 }
526 228
527 bool existsSync() { 229 bool existsSync() {
528 if (_asyncUsed) { 230 if (_asyncUsed) {
529 throw new FileIOException( 231 throw new FileIOException(
530 "Mixed use of synchronous and asynchronous API"); 232 "Mixed use of synchronous and asynchronous API");
531 } 233 }
532 if (_name is !String) { 234 if (_name is !String) {
533 throw new FileIOException('File name is not a string: $_name'); 235 throw new FileIOException('File name is not a string: $_name');
534 } 236 }
535 return _FileUtils.exists(_name); 237 return _FileUtils.exists(_name);
536 } 238 }
537 239
538 void create() { 240 void create() {
241 if (_fileService == null) {
242 _fileService = _FileUtils.newServicePort();
243 }
539 _asyncUsed = true; 244 _asyncUsed = true;
540 var handleCreateResult = (created, ignored) { 245 List request = new List(2);
541 var handler = (_createHandler != null) ? _createHandler : () => null; 246 request[0] = _FileUtils.kCreateRequest;
542 if (created) { 247 request[1] = _name;
543 handler(); 248 _fileService.call(request).receive((created, replyTo) {
544 } else if (_errorHandler != null) { 249 if (created) {
545 _errorHandler("Cannot create file: $_name"); 250 if (_createHandler != null) _createHandler();
546 } 251 } else if (_errorHandler != null) {
547 }; 252 _errorHandler("Cannot create file: $_name");
548 var operation = new _CreateOperation(_name); 253 }
549 _scheduler.enqueue(operation, handleCreateResult); 254 });
550 } 255 }
551 256
552 void createSync() { 257 void createSync() {
553 if (_asyncUsed) { 258 if (_asyncUsed) {
554 throw new FileIOException( 259 throw new FileIOException(
555 "Mixed use of synchronous and asynchronous API"); 260 "Mixed use of synchronous and asynchronous API");
556 } 261 }
557 bool created = _FileUtils.checkedCreate(_name); 262 bool created = _FileUtils.checkedCreate(_name);
558 if (!created) { 263 if (!created) {
559 throw new FileIOException("Cannot create file: $_name"); 264 throw new FileIOException("Cannot create file: $_name");
560 } 265 }
561 } 266 }
562 267
563 void delete() { 268 void delete() {
269 if (_fileService == null) {
270 _fileService = _FileUtils.newServicePort();
271 }
564 _asyncUsed = true; 272 _asyncUsed = true;
565 var handleDeleteResult = (created, ignored) { 273 List request = new List(2);
566 var handler = (_deleteHandler != null) ? _deleteHandler : () => null; 274 request[0] = _FileUtils.kDeleteRequest;
567 if (created) { 275 request[1] = _name;
568 handler(); 276 _fileService.call(request).receive((deleted, replyTo) {
569 } else if (_errorHandler != null) { 277 if (deleted) {
570 _errorHandler("Cannot delete file: $_name"); 278 if (_deleteHandler != null) _deleteHandler();
571 } 279 } else if (_errorHandler != null) {
572 }; 280 _errorHandler("Cannot delete file: $_name");
573 var operation = new _DeleteOperation(_name); 281 }
574 _scheduler.enqueue(operation, handleDeleteResult); 282 });
575 } 283 }
576 284
577 void deleteSync() { 285 void deleteSync() {
578 if (_asyncUsed) { 286 if (_asyncUsed) {
579 throw new FileIOException( 287 throw new FileIOException(
580 "Mixed use of synchronous and asynchronous API"); 288 "Mixed use of synchronous and asynchronous API");
581 } 289 }
582 bool deleted = _FileUtils.checkedDelete(_name); 290 bool deleted = _FileUtils.checkedDelete(_name);
583 if (!deleted) { 291 if (!deleted) {
584 throw new FileIOException("Cannot delete file: $_name"); 292 throw new FileIOException("Cannot delete file: $_name");
585 } 293 }
586 } 294 }
587 295
588 void open([FileMode mode = FileMode.READ]) { 296 void open([FileMode mode = FileMode.READ]) {
297 if (_fileService == null) {
298 _fileService = _FileUtils.newServicePort();
299 }
589 _asyncUsed = true; 300 _asyncUsed = true;
590 if (mode != FileMode.READ && 301 if (mode != FileMode.READ &&
591 mode != FileMode.WRITE && 302 mode != FileMode.WRITE &&
592 mode != FileMode.APPEND) { 303 mode != FileMode.APPEND) {
593 if (_errorHandler != null) { 304 if (_errorHandler != null) {
594 _errorHandler("Unknown file mode. Use FileMode.READ, FileMode.WRITE " + 305 _errorHandler("Unknown file mode. Use FileMode.READ, FileMode.WRITE " +
595 "or FileMode.APPEND."); 306 "or FileMode.APPEND.");
596 return; 307 return;
597 } 308 }
598 } 309 }
599 var handleOpenResult = (id, ignored) { 310 List request = new List(3);
600 // If no open handler is present, close the file immediately to 311 request[0] = _FileUtils.kOpenRequest;
601 // avoid leaking an open file descriptor. 312 request[1] = _name;
602 var handler = _openHandler; 313 request[2] = mode._mode; // Direct int value for serialization.
603 if (handler === null) { 314 _fileService.call(request).receive((id, replyTo) {
604 handler = (file) => file.close(); 315 var handler = _openHandler;
605 } 316 if (handler === null) {
606 if (id != 0) { 317 // If no open handler is present, close the file immediately to
607 var randomAccessFile = new _RandomAccessFile(id, _name); 318 // avoid leaking an open file descriptor.
608 handler(randomAccessFile); 319 handler = (file) => file.close();
609 } else if (_errorHandler != null) { 320 }
610 _errorHandler("Cannot open file: $_name"); 321 if (id != 0) {
611 } 322 var randomAccessFile = new _RandomAccessFile(id, _name);
612 }; 323 handler(randomAccessFile);
613 var operation = new _OpenOperation(_name, mode._mode); 324 } else if (_errorHandler != null) {
614 _scheduler.enqueue(operation, handleOpenResult); 325 _errorHandler("Cannot open file: $_name");
326 }
327 });
615 } 328 }
616 329
617 RandomAccessFile openSync([FileMode mode = FileMode.READ]) { 330 RandomAccessFile openSync([FileMode mode = FileMode.READ]) {
618 if (_asyncUsed) { 331 if (_asyncUsed) {
619 throw new FileIOException( 332 throw new FileIOException(
620 "Mixed use of synchronous and asynchronous API"); 333 "Mixed use of synchronous and asynchronous API");
621 } 334 }
622 if (mode != FileMode.READ && 335 if (mode != FileMode.READ &&
623 mode != FileMode.WRITE && 336 mode != FileMode.WRITE &&
624 mode != FileMode.APPEND) { 337 mode != FileMode.APPEND) {
625 throw new FileIOException("Unknown file mode. Use FileMode.READ, " + 338 throw new FileIOException("Unknown file mode. Use FileMode.READ, " +
626 "FileMode.WRITE or FileMode.APPEND."); 339 "FileMode.WRITE or FileMode.APPEND.");
627 } 340 }
628 var id = _FileUtils.checkedOpen(_name, mode._mode); 341 var id = _FileUtils.checkedOpen(_name, mode._mode);
629 if (id == 0) { 342 if (id == 0) {
630 throw new FileIOException("Cannot open file: $_name"); 343 throw new FileIOException("Cannot open file: $_name");
631 } 344 }
632 return new _RandomAccessFile(id, _name); 345 return new _RandomAccessFile(id, _name);
633 } 346 }
634 347
635 static RandomAccessFile _openStdioSync(int fd) { 348 static RandomAccessFile _openStdioSync(int fd) {
636 var id = _FileUtils.openStdio(fd); 349 var id = _FileUtils.openStdio(fd);
637 if (id == 0) { 350 if (id == 0) {
638 throw new FileIOException("Cannot open stdio file for: $fd"); 351 throw new FileIOException("Cannot open stdio file for: $fd");
639 } 352 }
640 return new _RandomAccessFile(id, ""); 353 return new _RandomAccessFile(id, "");
641 } 354 }
642 355
643 void fullPath() { 356 void fullPath() {
357 if (_fileService == null) {
358 _fileService = _FileUtils.newServicePort();
359 }
644 _asyncUsed = true; 360 _asyncUsed = true;
645 var handleFullPathResult = (result, ignored) { 361 List request = new List(2);
646 var handler = _fullPathHandler; 362 request[0] = _FileUtils.kFullPathRequest;
647 if (handler == null) handler = (path) => null; 363 request[1] = _name;
648 if (result != null) { 364 _fileService.call(request).receive((result, replyTo) {
649 handler(result); 365 if (result != null) {
650 } else if (_errorHandler != null) { 366 if (_fullPathHandler != null) _fullPathHandler(result);
651 _errorHandler("fullPath failed"); 367 } else if (_errorHandler != null) {
652 } 368 _errorHandler("fullPath failed");
653 }; 369 }
654 var operation = new _FullPathOperation(_name); 370 });
655 _scheduler.enqueue(operation, handleFullPathResult);
656 } 371 }
657 372
658 String fullPathSync() { 373 String fullPathSync() {
659 if (_asyncUsed) { 374 if (_asyncUsed) {
660 throw new FileIOException( 375 throw new FileIOException(
661 "Mixed use of synchronous and asynchronous API"); 376 "Mixed use of synchronous and asynchronous API");
662 } 377 }
663 String result = _FileUtils.checkedFullPath(_name); 378 String result = _FileUtils.checkedFullPath(_name);
664 if (result == null) { 379 if (result == null) {
665 throw new FileIOException("fullPath failed"); 380 throw new FileIOException("fullPath failed");
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
700 _fullPathHandler = handler; 415 _fullPathHandler = handler;
701 } 416 }
702 417
703 void set errorHandler(void handler(String error)) { 418 void set errorHandler(void handler(String error)) {
704 _errorHandler = handler; 419 _errorHandler = handler;
705 } 420 }
706 421
707 String _name; 422 String _name;
708 bool _asyncUsed; 423 bool _asyncUsed;
709 424
710 _FileOperationScheduler _scheduler; 425 SendPort _fileService;
711 426
712 var _existsHandler; 427 var _existsHandler;
713 var _createHandler; 428 var _createHandler;
714 var _deleteHandler; 429 var _deleteHandler;
715 var _openHandler; 430 var _openHandler;
716 var _fullPathHandler; 431 var _fullPathHandler;
717 var _errorHandler; 432 var _errorHandler;
718 } 433 }
719 434
720 435
721 class _RandomAccessFile implements RandomAccessFile { 436 class _RandomAccessFile implements RandomAccessFile {
722 _RandomAccessFile(int this._id, String this._name) 437 _RandomAccessFile(int this._id, String this._name) : _asyncUsed = false;
723 : _scheduler = new _FileOperationScheduler(),
724 _asyncUsed = false;
725 438
726 void close() { 439 void close() {
440 _ensureFileService();
727 _asyncUsed = true; 441 _asyncUsed = true;
728 var handleCloseResult = (result, ignored) { 442 List request = new List(2);
729 var handler = (_closeHandler != null) ? _closeHandler : () => null; 443 request[0] = _FileUtils.kCloseRequest;
730 if (result != -1) { 444 request[1] = _id;
731 _id = result; 445 _fileService.call(request).receive((result, replyTo) {
732 handler(); 446 if (result != -1) {
733 } else if (_errorHandler != null) { 447 _id = result;
734 _errorHandler("Cannot close file: $_name"); 448 if (_closeHandler != null) _closeHandler();
735 } 449 } else if (_errorHandler != null) {
736 }; 450 _errorHandler("Cannot close file: $_name");
737 var operation = new _CloseOperation(_id); 451 }
738 _scheduler.enqueue(operation, handleCloseResult); 452 });
739 } 453 }
740 454
741 void closeSync() { 455 void closeSync() {
742 if (_asyncUsed) { 456 if (_asyncUsed) {
743 throw new FileIOException( 457 throw new FileIOException(
744 "Mixed use of synchronous and asynchronous API"); 458 "Mixed use of synchronous and asynchronous API");
745 } 459 }
746 var id = _FileUtils.close(_id); 460 var id = _FileUtils.close(_id);
747 if (id == -1) { 461 if (id == -1) {
748 throw new FileIOException("Cannot close file: $_name"); 462 throw new FileIOException("Cannot close file: $_name");
749 } 463 }
750 _id = id; 464 _id = id;
751 } 465 }
752 466
753 void readByte() { 467 void readByte() {
468 _ensureFileService();
754 _asyncUsed = true; 469 _asyncUsed = true;
755 var handleReadByteResult = (result, ignored) { 470 List request = new List(2);
756 var handler = 471 request[0] = _FileUtils.kReadByteRequest;
757 (_readByteHandler != null) ? _readByteHandler : (byte) => null; 472 request[1] = _id;
758 if (result != -1) { 473 _fileService.call(request).receive((result, replyTo) {
759 handler(result); 474 if (result != -1) {
760 } else if (_errorHandler != null) { 475 if (_readByteHandler != null) _readByteHandler(result);
761 _errorHandler("readByte failed"); 476 } else if (_errorHandler != null) {
762 } 477 _errorHandler("readByte failed");
763 }; 478 }
764 var operation = new _ReadByteOperation(_id); 479 });
765 _scheduler.enqueue(operation, handleReadByteResult);
766 } 480 }
767 481
768 int readByteSync() { 482 int readByteSync() {
769 if (_asyncUsed) { 483 if (_asyncUsed) {
770 throw new FileIOException( 484 throw new FileIOException(
771 "Mixed use of synchronous and asynchronous API"); 485 "Mixed use of synchronous and asynchronous API");
772 } 486 }
773 int result = _FileUtils.readByte(_id); 487 int result = _FileUtils.readByte(_id);
774 if (result == -1) { 488 if (result == -1) {
775 throw new FileIOException("readByte failed"); 489 throw new FileIOException("readByte failed");
776 } 490 }
777 return result; 491 return result;
778 } 492 }
779 493
780 void readList(List<int> buffer, int offset, int bytes) { 494 void readList(List<int> buffer, int offset, int bytes) {
495 _ensureFileService();
781 _asyncUsed = true; 496 _asyncUsed = true;
782 if (buffer is !List || offset is !int || bytes is !int) { 497 if (buffer is !List || offset is !int || bytes is !int) {
783 if (_errorHandler != null) { 498 if (_errorHandler != null) {
784 _errorHandler("Invalid arguments to readList"); 499 _errorHandler("Invalid arguments to readList");
785 } 500 }
786 return; 501 return;
787 }; 502 };
788 var handleReadListResult = (result, ignored) { 503 List request = new List(3);
789 var handler = 504 request[0] = _FileUtils.kReadListRequest;
790 (_readListHandler != null) ? _readListHandler : (result) => null; 505 request[1] = _id;
791 if (result is _ReadListResult && result.read != -1) { 506 request[2] = bytes;
792 var read = result.read; 507 _fileService.call(request).receive((result, replyTo) {
793 buffer.setRange(offset, read, result.buffer); 508 if (result is List && result.length == 2 && result[0] != -1) {
794 handler(read); 509 var read = result[0];
795 return; 510 var data = result[1];
796 } 511 buffer.setRange(offset, read, data);
797 if (_errorHandler != null) { 512 if (_readListHandler != null) _readListHandler(read);
798 _errorHandler(result is String ? result : "readList failed"); 513 return;
799 } 514 } else if (_errorHandler != null) {
800 }; 515 _errorHandler(result is String ? result : "readList failed");
801 var operation = new _ReadListOperation(_id, buffer.length, offset, bytes); 516 }
802 _scheduler.enqueue(operation, handleReadListResult); 517 });
803 } 518 }
804 519
805 int readListSync(List<int> buffer, int offset, int bytes) { 520 int readListSync(List<int> buffer, int offset, int bytes) {
806 if (_asyncUsed) { 521 if (_asyncUsed) {
807 throw new FileIOException( 522 throw new FileIOException(
808 "Mixed use of synchronous and asynchronous API"); 523 "Mixed use of synchronous and asynchronous API");
809 } 524 }
810 if (buffer is !List || offset is !int || bytes is !int) { 525 if (buffer is !List || offset is !int || bytes is !int) {
811 throw new FileIOException("Invalid arguments to readList"); 526 throw new FileIOException("Invalid arguments to readList");
812 } 527 }
(...skipping 10 matching lines...) Expand all
823 return result; 538 return result;
824 } 539 }
825 540
826 void _checkPendingWrites() { 541 void _checkPendingWrites() {
827 if (_scheduler.noPendingWrite() && _noPendingWriteHandler != null) { 542 if (_scheduler.noPendingWrite() && _noPendingWriteHandler != null) {
828 _noPendingWriteHandler(); 543 _noPendingWriteHandler();
829 } 544 }
830 } 545 }
831 546
832 void writeByte(int value) { 547 void writeByte(int value) {
548 _ensureFileService();
833 _asyncUsed = true; 549 _asyncUsed = true;
834 if (value is !int) { 550 if (value is !int) {
835 if (_errorHandler != null) { 551 if (_errorHandler != null) {
836 _errorHandler("Invalid argument to writeByte"); 552 _errorHandler("Invalid argument to writeByte");
837 } 553 }
838 return; 554 return;
839 } 555 }
840 var handleReadByteResult = (result, ignored) { 556 List request = new List(3);
841 if (result == -1 &&_errorHandler != null) { 557 request[0] = _FileUtils.kWriteByteRequest;
842 _errorHandler("writeByte failed"); 558 request[1] = _id;
843 return; 559 request[2] = value;
844 } 560 _fileService.call(request).receive((result, replyTo) {
845 _checkPendingWrites(); 561 if (result != -1) {
846 }; 562 // TODO(sgjesse): Handle no pending writes correctly.
Mads Ager (google) 2012/02/20 13:50:31 This one looks important. This should be fixed bef
Søren Gjesse 2012/02/22 16:27:07 Done.
847 var operation = new _WriteByteOperation(_id, value); 563 if (_noPendingWriteHandler != null) _noPendingWriteHandler();
848 _scheduler.enqueue(operation, handleReadByteResult); 564 } else {
565 _errorHandler("writeByte failed");
566 }
567 });
849 } 568 }
850 569
851 int writeByteSync(int value) { 570 int writeByteSync(int value) {
852 if (_asyncUsed) { 571 if (_asyncUsed) {
853 throw new FileIOException( 572 throw new FileIOException(
854 "Mixed use of synchronous and asynchronous API"); 573 "Mixed use of synchronous and asynchronous API");
855 } 574 }
856 if (value is !int) { 575 if (value is !int) {
857 throw new FileIOException("Invalid argument to writeByte"); 576 throw new FileIOException("Invalid argument to writeByte");
858 } 577 }
859 int result = _FileUtils.writeByte(_id, value); 578 int result = _FileUtils.writeByte(_id, value);
860 if (result == -1) { 579 if (result == -1) {
861 throw new FileIOException("writeByte failed"); 580 throw new FileIOException("writeByte failed");
862 } 581 }
863 return result; 582 return result;
864 } 583 }
865 584
866 void writeList(List<int> buffer, int offset, int bytes) { 585 void writeList(List<int> buffer, int offset, int bytes) {
586 _ensureFileService();
867 _asyncUsed = true; 587 _asyncUsed = true;
868 if (buffer is !List || offset is !int || bytes is !int) { 588 if (buffer is !List || offset is !int || bytes is !int) {
869 if (_errorHandler != null) { 589 if (_errorHandler != null) {
870 _errorHandler("Invalid arguments to writeList"); 590 _errorHandler("Invalid arguments to writeList");
871 } 591 }
872 return; 592 return;
873 } 593 }
874 var handleWriteListResult = (result, ignored) { 594 List request = new List(5);
875 if (result is !String && result != -1) { 595 request[0] = _FileUtils.kWriteListRequest;
876 if (result < bytes) { 596 request[1] = _id;
877 writeList(buffer, offset + result, bytes - result); 597 request[2] = buffer;
598 request[3] = offset;
599 request[4] = bytes;
600 _fileService.call(request).receive((result, replyTo) {
601 if (result is !String && result != -1) {
602 // TODO(sgjesse): Handle no pending writes correctly.
603 if (_noPendingWriteHandler != null) _noPendingWriteHandler();
878 } else { 604 } else {
879 _checkPendingWrites(); 605 _errorHandler(result is String ? result : "writeList failed");
880 } 606 }
881 return; 607 });
882 }
883 if (_errorHandler != null) {
884 _errorHandler(result is String ? result : "writeList failed");
885 }
886 };
887 var operation = new _WriteListOperation(_id, buffer, offset, bytes);
888 _scheduler.enqueue(operation, handleWriteListResult);
889 } 608 }
890 609
891 int writeListSync(List<int> buffer, int offset, int bytes) { 610 int writeListSync(List<int> buffer, int offset, int bytes) {
892 if (_asyncUsed) { 611 if (_asyncUsed) {
893 throw new FileIOException( 612 throw new FileIOException(
894 "Mixed use of synchronous and asynchronous API"); 613 "Mixed use of synchronous and asynchronous API");
895 } 614 }
896 if (buffer is !List || offset is !int || bytes is !int) { 615 if (buffer is !List || offset is !int || bytes is !int) {
897 throw new FileIOException("Invalid arguments to writeList"); 616 throw new FileIOException("Invalid arguments to writeList");
898 } 617 }
899 if (bytes == 0) return 0; 618 if (bytes == 0) return 0;
900 int index = 619 int index =
901 _FileUtils.checkReadWriteListArguments(buffer.length, offset, bytes); 620 _FileUtils.checkReadWriteListArguments(buffer.length, offset, bytes);
902 if (index != 0) { 621 if (index != 0) {
903 throw new IndexOutOfRangeException(index); 622 throw new IndexOutOfRangeException(index);
904 } 623 }
905 int result = _FileUtils.writeList(_id, buffer, offset, bytes); 624 int result = _FileUtils.writeList(_id, buffer, offset, bytes);
906 if (result == -1) { 625 if (result == -1) {
907 throw new FileIOException("writeList failed"); 626 throw new FileIOException("writeList failed");
908 } 627 }
909 return result; 628 return result;
910 } 629 }
911 630
912 void writeString(String string) { 631 void writeString(String string) {
632 _ensureFileService();
913 _asyncUsed = true; 633 _asyncUsed = true;
914 var handleWriteStringResult = (result, ignored) { 634 List request = new List(3);
915 if (result == -1 &&_errorHandler != null) { 635 request[0] = _FileUtils.kWriteStringRequest;
916 _errorHandler("writeString failed"); 636 request[1] = _id;
917 return; 637 request[2] = string;
918 } 638 _fileService.call(request).receive((result, replyTo) {
919 if (result < string.length) { 639 if (result is !String && result != -1) {
920 writeString(string.substring(result)); 640 // TODO(sgjesse): Handle no pending writes correctly.
921 } else { 641 if (_noPendingWriteHandler != null) _noPendingWriteHandler();
922 _checkPendingWrites(); 642 } else {
923 } 643 _errorHandler(result is String ? result : "writeString failed");
924 }; 644 }
925 var operation = new _WriteStringOperation(_id, string); 645 });
926 _scheduler.enqueue(operation, handleWriteStringResult);
927 } 646 }
928 647
929 int writeStringSync(String string) { 648 int writeStringSync(String string) {
930 if (_asyncUsed) { 649 if (_asyncUsed) {
931 throw new FileIOException( 650 throw new FileIOException(
932 "Mixed use of synchronous and asynchronous API"); 651 "Mixed use of synchronous and asynchronous API");
933 } 652 }
934 int result = _FileUtils.checkedWriteString(_id, string); 653 int result = _FileUtils.checkedWriteString(_id, string);
935 if (result == -1) { 654 if (result == -1) {
936 throw new FileIOException("writeString failed"); 655 throw new FileIOException("writeString failed");
937 } 656 }
938 return result; 657 return result;
939 } 658 }
940 659
941 void position() { 660 void position() {
661 _ensureFileService();
942 _asyncUsed = true; 662 _asyncUsed = true;
943 var handlePositionResult = (result, ignored) { 663 List request = new List(2);
944 var handler = 664 request[0] = _FileUtils.kPositionRequest;
945 (_positionHandler != null) ? _positionHandler : (pos) => null; 665 request[1] = _id;
946 if (result == -1 && _errorHandler != null) { 666 _fileService.call(request).receive((result, replyTo) {
947 _errorHandler("position failed"); 667 if (result != -1) {
948 return; 668 if (_positionHandler != null) _positionHandler(result);
949 } 669 } else if (_errorHandler != null) {
950 handler(result); 670 _errorHandler("position failed");
951 }; 671 }
952 var operation = new _PositionOperation(_id); 672 });
953 _scheduler.enqueue(operation, handlePositionResult);
954 } 673 }
955 674
956 int positionSync() { 675 int positionSync() {
957 if (_asyncUsed) { 676 if (_asyncUsed) {
958 throw new FileIOException( 677 throw new FileIOException(
959 "Mixed use of synchronous and asynchronous API"); 678 "Mixed use of synchronous and asynchronous API");
960 } 679 }
961 int result = _FileUtils.position(_id); 680 int result = _FileUtils.position(_id);
962 if (result == -1) { 681 if (result == -1) {
963 throw new FileIOException("position failed"); 682 throw new FileIOException("position failed");
964 } 683 }
965 return result; 684 return result;
966 } 685 }
967 686
968 void setPosition(int position) { 687 void setPosition(int position) {
688 _ensureFileService();
969 _asyncUsed = true; 689 _asyncUsed = true;
970 var handleSetPositionResult = (result, ignored) { 690 List request = new List(3);
971 var handler = 691 request[0] = _FileUtils.kSetPositionRequest;
972 (_setPositionHandler != null) ? _setPositionHandler : () => null; 692 request[1] = _id;
973 if (result == false && _errorHandler != null) { 693 request[2] = position;
974 _errorHandler("setPosition failed"); 694 _fileService.call(request).receive((result, replyTo) {
975 return; 695 if (result) {
976 } 696 if (_setPositionHandler != null) _setPositionHandler();
977 handler(); 697 } else if (_errorHandler != null) {
978 }; 698 _errorHandler("setPosition failed");
979 var operation = new _SetPositionOperation(_id, position); 699 }
980 _scheduler.enqueue(operation, handleSetPositionResult); 700 });
981 } 701 }
982 702
983 void setPositionSync(int position) { 703 void setPositionSync(int position) {
704 _ensureFileService();
984 if (_asyncUsed) { 705 if (_asyncUsed) {
985 throw new FileIOException( 706 throw new FileIOException(
986 "Mixed use of synchronous and asynchronous API"); 707 "Mixed use of synchronous and asynchronous API");
987 } 708 }
988 bool result = _FileUtils.setPosition(_id, position); 709 bool result = _FileUtils.setPosition(_id, position);
989 if (result == false) { 710 if (result == false) {
990 throw new FileIOException("setPosition failed"); 711 throw new FileIOException("setPosition failed");
991 } 712 }
992 } 713 }
993 714
994 void truncate(int length) { 715 void truncate(int length) {
716 _ensureFileService();
995 _asyncUsed = true; 717 _asyncUsed = true;
996 var handleTruncateResult = (result, ignored) { 718 List request = new List(3);
997 var handler = (_truncateHandler != null) ? _truncateHandler : () => null; 719 request[0] = _FileUtils.kTruncateRequest;
998 if (result == false && _errorHandler != null) { 720 request[1] = _id;
999 _errorHandler("truncate failed"); 721 request[2] = length;
1000 return; 722 _fileService.call(request).receive((result, replyTo) {
1001 } 723 if (result) {
1002 handler(); 724 if (_truncateHandler != null) _truncateHandler();
1003 }; 725 } else if (_errorHandler != null) {
1004 var operation = new _TruncateOperation(_id, length); 726 _errorHandler("truncate failed");
1005 _scheduler.enqueue(operation, handleTruncateResult); 727 }
728 });
1006 } 729 }
1007 730
1008 void truncateSync(int length) { 731 void truncateSync(int length) {
1009 if (_asyncUsed) { 732 if (_asyncUsed) {
1010 throw new FileIOException( 733 throw new FileIOException(
1011 "Mixed use of synchronous and asynchronous API"); 734 "Mixed use of synchronous and asynchronous API");
1012 } 735 }
1013 bool result = _FileUtils.truncate(_id, length); 736 bool result = _FileUtils.truncate(_id, length);
1014 if (result == false) { 737 if (result == false) {
1015 throw new FileIOException("truncate failed"); 738 throw new FileIOException("truncate failed");
1016 } 739 }
1017 } 740 }
1018 741
1019 void length() { 742 void length() {
743 _ensureFileService();
1020 _asyncUsed = true; 744 _asyncUsed = true;
1021 var handleLengthResult = (result, ignored) { 745 List request = new List(2);
1022 var handler = (_lengthHandler != null) ? _lengthHandler : (pos) => null; 746 request[0] = _FileUtils.kLengthRequest;
1023 if (result == -1 && _errorHandler != null) { 747 request[1] = _id;
1024 _errorHandler("length failed"); 748 _fileService.call(request).receive((result, replyTo) {
1025 return; 749 if (result != -1) {
1026 } 750 if (_lengthHandler != null) _lengthHandler(result);
1027 handler(result); 751 } else if (_errorHandler != null) {
1028 }; 752 _errorHandler("length failed");
1029 var operation = new _LengthOperation(_id); 753 }
1030 _scheduler.enqueue(operation, handleLengthResult); 754 });
1031 } 755 }
1032 756
1033 int lengthSync() { 757 int lengthSync() {
1034 if (_asyncUsed) { 758 if (_asyncUsed) {
1035 throw new FileIOException( 759 throw new FileIOException(
1036 "Mixed use of synchronous and asynchronous API"); 760 "Mixed use of synchronous and asynchronous API");
1037 } 761 }
1038 int result = _FileUtils.length(_id); 762 int result = _FileUtils.length(_id);
1039 if (result == -1) { 763 if (result == -1) {
1040 throw new FileIOException("length failed"); 764 throw new FileIOException("length failed");
1041 } 765 }
1042 return result; 766 return result;
1043 } 767 }
1044 768
1045 void flush() { 769 void flush() {
770 _ensureFileService();
1046 _asyncUsed = true; 771 _asyncUsed = true;
1047 var handleFlushResult = (result, ignored) { 772 List request = new List(2);
1048 var handler = (_flushHandler != null) ? _flushHandler : (pos) => null; 773 request[0] = _FileUtils.kFlushRequest;
1049 if (result == -1 && _errorHandler != null) { 774 request[1] = _id;
1050 _errorHandler("flush failed"); 775 _fileService.call(request).receive((result, replyTo) {
1051 return; 776 if (result != -1) {
1052 } 777 if (_flushHandler != null) _flushHandler();
1053 handler(); 778 } else if (_errorHandler != null) {
1054 }; 779 _errorHandler("flush failed");
1055 var operation = new _FlushOperation(_id); 780 }
1056 _scheduler.enqueue(operation, handleFlushResult); 781 });
1057 } 782 }
1058 783
1059 void flushSync() { 784 void flushSync() {
1060 if (_asyncUsed) { 785 if (_asyncUsed) {
1061 throw new FileIOException( 786 throw new FileIOException(
1062 "Mixed use of synchronous and asynchronous API"); 787 "Mixed use of synchronous and asynchronous API");
1063 } 788 }
1064 int result = _FileUtils.flush(_id); 789 int result = _FileUtils.flush(_id);
1065 if (result == -1) { 790 if (result == -1) {
1066 throw new FileIOException("flush failed"); 791 throw new FileIOException("flush failed");
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
1102 } 827 }
1103 828
1104 void set lengthHandler(void handler(int length)) { 829 void set lengthHandler(void handler(int length)) {
1105 _lengthHandler = handler; 830 _lengthHandler = handler;
1106 } 831 }
1107 832
1108 void set flushHandler(void handler()) { 833 void set flushHandler(void handler()) {
1109 _flushHandler = handler; 834 _flushHandler = handler;
1110 } 835 }
1111 836
837 void _ensureFileService() {
838 if (_fileService == null) {
839 _fileService = _FileUtils.newServicePort();
840 }
841 }
842
1112 String _name; 843 String _name;
1113 int _id; 844 int _id;
1114 bool _asyncUsed; 845 bool _asyncUsed;
1115 846
1116 _FileOperationScheduler _scheduler; 847 SendPort _fileService;
1117 848
1118 var _closeHandler; 849 var _closeHandler;
1119 var _readByteHandler; 850 var _readByteHandler;
1120 var _readListHandler; 851 var _readListHandler;
1121 var _noPendingWriteHandler; 852 var _noPendingWriteHandler;
1122 var _positionHandler; 853 var _positionHandler;
1123 var _setPositionHandler; 854 var _setPositionHandler;
1124 var _truncateHandler; 855 var _truncateHandler;
1125 var _lengthHandler; 856 var _lengthHandler;
1126 var _flushHandler; 857 var _flushHandler;
1127 var _errorHandler; 858 var _errorHandler;
1128 } 859 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698