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

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: Forgot to remove #import from op.dart 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/file.cc ('k') | runtime/vm/dart_api_message.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 class _FileInputStream extends _BaseDataInputStream implements InputStream { 5 class _FileInputStream extends _BaseDataInputStream implements InputStream {
6 _FileInputStream(RandomAccessFile this._file, int this._length) { 6 _FileInputStream(RandomAccessFile this._file, int this._length) {
7 _streamMarkedClosed = true; 7 _streamMarkedClosed = true;
8 _checkScheduleCallbacks(); 8 _checkScheduleCallbacks();
9 } 9 }
10 10
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after
149 // the stream is fully closed. 149 // the stream is fully closed.
150 bool _closeCallbackCalled = false; 150 bool _closeCallbackCalled = false;
151 151
152 Timer _scheduledNoPendingWriteCallback; 152 Timer _scheduledNoPendingWriteCallback;
153 Timer _scheduledCloseCallback; 153 Timer _scheduledCloseCallback;
154 Function _noPendingWriteHandler; 154 Function _noPendingWriteHandler;
155 Function _closeHandler; 155 Function _closeHandler;
156 } 156 }
157 157
158 158
159 class _FileOperation {
160 abstract void execute(ReceivePort port);
161
162 void set replyPort(SendPort port) {
163 _replyPort = port;
164 }
165
166 bool isWrite() => false;
167
168 SendPort _replyPort;
169 }
170
171
172 class _ExistsOperation extends _FileOperation {
173 _ExistsOperation(String this._name);
174
175 void execute(ReceivePort port) {
176 _replyPort.send(_FileUtils.exists(_name), port.toSendPort());
177 }
178
179 String _name;
180 }
181
182
183 class _OpenOperation extends _FileOperation {
184 _OpenOperation(String this._name, int this._mode);
185
186 void execute(ReceivePort port) {
187 _replyPort.send(_FileUtils.checkedOpen(_name, _mode),
188 port.toSendPort());
189 }
190
191 String _name;
192 int _mode;
193 }
194
195
196 class _CloseOperation extends _FileOperation {
197 _CloseOperation(int this._id);
198
199 void execute(ReceivePort port) {
200 _replyPort.send(_FileUtils.close(_id), port.toSendPort());
201 }
202
203 int _id;
204 }
205
206
207 class _ReadByteOperation extends _FileOperation {
208 _ReadByteOperation(int this._id);
209
210 void execute(ReceivePort port) {
211 _replyPort.send(_FileUtils.readByte(_id), port.toSendPort());
212 }
213
214 int _id;
215 }
216
217
218 class _ReadListResult {
219 _ReadListResult(this.read, this.buffer);
220 int read;
221 List buffer;
222 }
223
224
225 class _ReadListOperation extends _FileOperation {
226 _ReadListOperation(int this._id,
227 int this._length,
228 int this._offset,
229 int this._bytes);
230
231 void execute(ReceivePort port) {
232 if (_bytes == 0) {
233 _replyPort.send(0, port.toSendPort());
234 return;
235 }
236 int index =
237 _FileUtils.checkReadWriteListArguments(_length, _offset, _bytes);
238 if (index != 0) {
239 _replyPort.send("index out of range in readList: $index",
240 port.toSendPort());
241 return;
242 }
243 ByteArray buffer = new ByteArray(_bytes);
244 var result =
245 new _ReadListResult(_FileUtils.readList(_id, buffer, 0, _bytes),
246 buffer);
247 _replyPort.send(result, port.toSendPort());
248 }
249
250 int _id;
251 int _length;
252 int _offset;
253 int _bytes;
254 }
255
256
257 class _WriteByteOperation extends _FileOperation {
258 _WriteByteOperation(int this._id, int this._value);
259
260 void execute(ReceivePort port) {
261 _replyPort.send(_FileUtils.writeByte(_id, _value), port.toSendPort());
262 }
263
264 bool isWrite() => true;
265
266 int _id;
267 int _value;
268 }
269
270
271 class _WriteListOperation extends _FileOperation {
272 _WriteListOperation(int this._id,
273 List this._buffer,
274 int this._offset,
275 int this._bytes);
276
277 void execute(ReceivePort port) {
278 if (_bytes == 0) {
279 _replyPort.send(0, port.toSendPort());
280 return;
281 }
282 int index =
283 _FileUtils.checkReadWriteListArguments(_buffer.length, _offset, _bytes);
284 if (index != 0) {
285 _replyPort.send("index out of range in writeList: $index",
286 port.toSendPort());
287 return;
288 }
289 var result = _FileUtils.writeList(_id, _buffer, _offset, _bytes);
290 _replyPort.send(result, port.toSendPort());
291 }
292
293 bool isWrite() => true;
294
295 int _id;
296 List _buffer;
297 int _offset;
298 int _bytes;
299 }
300
301
302 class _WriteStringOperation extends _FileOperation {
303 _WriteStringOperation(int this._id, String this._string);
304
305 void execute(ReceivePort port) {
306 _replyPort.send(_FileUtils.checkedWriteString(_id, _string),
307 port.toSendPort());
308 }
309
310 bool isWrite() => true;
311
312 int _id;
313 String _string;
314 }
315
316
317 class _PositionOperation extends _FileOperation {
318 _PositionOperation(int this._id);
319
320 void execute(ReceivePort port) {
321 _replyPort.send(_FileUtils.position(_id), port.toSendPort());
322 }
323
324 int _id;
325 }
326
327
328 class _SetPositionOperation extends _FileOperation {
329 _SetPositionOperation(int this._id, int this._position);
330
331 void execute(ReceivePort port) {
332 _replyPort.send(_FileUtils.setPosition(_id, _position), port.toSendPort());
333 }
334
335 int _id;
336 int _position;
337 }
338
339
340 class _TruncateOperation extends _FileOperation {
341 _TruncateOperation(int this._id, int this._length);
342
343 void execute(ReceivePort port) {
344 _replyPort.send(_FileUtils.truncate(_id, _length), port.toSendPort());
345 }
346
347 int _id;
348 int _length;
349 }
350
351
352 class _LengthOperation extends _FileOperation {
353 _LengthOperation(int this._id);
354
355 void execute(ReceivePort port) {
356 _replyPort.send(_FileUtils.length(_id), port.toSendPort());
357 }
358
359 int _id;
360 }
361
362
363 class _FlushOperation extends _FileOperation {
364 _FlushOperation(int this._id);
365
366 void execute(ReceivePort port) {
367 _replyPort.send(_FileUtils.flush(_id), port.toSendPort());
368 }
369
370 int _id;
371 }
372
373
374 class _FullPathOperation extends _FileOperation {
375 _FullPathOperation(String this._name);
376
377 void execute(ReceivePort port) {
378 _replyPort.send(_FileUtils.checkedFullPath(_name), port.toSendPort());
379 }
380
381 String _name;
382 }
383
384
385 class _CreateOperation extends _FileOperation {
386 _CreateOperation(String this._name);
387
388 void execute(ReceivePort port) {
389 _replyPort.send(_FileUtils.checkedCreate(_name), port.toSendPort());
390 }
391
392 String _name;
393 }
394
395
396 class _DeleteOperation extends _FileOperation {
397 _DeleteOperation(String this._name);
398
399 void execute(ReceivePort port) {
400 _replyPort.send(_FileUtils.checkedDelete(_name), port.toSendPort());
401 }
402
403 String _name;
404 }
405
406
407 class _DirectoryOperation extends _FileOperation {
408 _DirectoryOperation(String this._name);
409
410 void execute(ReceivePort port) {
411 if (_name is String) {
412 if (_FileUtils.exists(_name)) {
413 _replyPort.send(_FileUtils.directory(_name), port.toSendPort());
414 return;
415 }
416 }
417 // Either _name is not a string or the file does not exist.
418 _replyPort.send(null, port.toSendPort());
419 }
420
421 String _name;
422 }
423
424
425 class _ExitOperation extends _FileOperation {
426 void execute(ReceivePort port) {
427 port.close();
428 }
429 }
430
431
432 class _FileOperationIsolate extends Isolate {
433 _FileOperationIsolate() : super.heavy();
434
435 void handleOperation(_FileOperation message, SendPort ignored) {
436 message.execute(port);
437 port.receive(handleOperation);
438 }
439
440 void main() {
441 port.receive(handleOperation);
442 }
443 }
444
445
446 class _FileOperationScheduler {
447 _FileOperationScheduler() : _queue = new Queue();
448
449 void schedule(SendPort port) {
450 assert(_isolate != null);
451 if (_queue.isEmpty()) {
452 port.send(new _ExitOperation());
453 _isolate = null;
454 } else {
455 port.send(_queue.removeFirst());
456 }
457 }
458
459 void scheduleWrap(void callback(result, ignored)) {
460 return (result, replyTo) {
461 callback(result, replyTo);
462 schedule(replyTo);
463 };
464 }
465
466 void enqueue(_FileOperation operation, void callback(result, ignored)) {
467 ReceivePort replyPort = new ReceivePort.singleShot();
468 replyPort.receive(scheduleWrap(callback));
469 operation.replyPort = replyPort.toSendPort();
470 _queue.addLast(operation);
471 if (_isolate == null) {
472 _isolate = new _FileOperationIsolate();
473 _isolate.spawn().then((port) {
474 schedule(port);
475 });
476 }
477 }
478
479 bool noPendingWrite() {
480 int queuedWrites = 0;
481 _queue.forEach((operation) {
482 if (operation.isWrite()) {
483 queuedWrites++;
484 }
485 });
486 return queuedWrites == 0;
487 }
488
489 Queue<_FileOperation> _queue;
490 _FileOperationIsolate _isolate;
491 }
492
493
494 // Helper class containing static file helper methods. 159 // Helper class containing static file helper methods.
495 class _FileUtils { 160 class _FileUtils {
496 static bool exists(String name) native "File_Exists"; 161 static final kExistsRequest = 0;
497 static int open(String name, int mode) native "File_Open"; 162 static final kCreateRequest = 1;
498 static bool create(String name) native "File_Create"; 163 static final kDeleteRequest = 2;
499 static bool delete(String name) native "File_Delete"; 164 static final kOpenRequest = 3;
500 static String directory(String name) native "File_Directory"; 165 static final kFullPathRequest = 4;
501 static String fullPath(String name) native "File_FullPath"; 166 static final kDirectoryRequest = 5;
502 static int close(int id) native "File_Close"; 167 static final kCloseRequest = 6;
503 static int readByte(int id) native "File_ReadByte"; 168 static final kPositionRequest = 7;
504 static int readList(int id, List<int> buffer, int offset, int bytes) 169 static final kSetPositionRequest = 8;
505 native "File_ReadList"; 170 static final kTruncateRequest = 9;
506 static int writeByte(int id, int value) native "File_WriteByte"; 171 static final kLengthRequest = 10;
507 static int writeList(int id, List<int> buffer, int offset, int bytes) { 172 static final kFlushRequest = 11;
173 static final kReadByteRequest = 12;
174 static final kWriteByteRequest = 13;
175 static final kReadListRequest = 14;
176 static final kWriteListRequest = 15;
177 static final kWriteStringRequest = 16;
178
179 static List ensureFastAndSerializableBuffer(
180 List buffer, int offset, int bytes) {
508 // When using the Dart C API to access raw data, using a ByteArray is 181 // When using the Dart C API to access raw data, using a ByteArray is
509 // currently much faster. This function will make a copy of the 182 // currently much faster. This function will make a copy of the
510 // supplied List to a ByteArray if it isn't already. 183 // supplied List to a ByteArray if it isn't already.
511 List outBuffer; 184 List outBuffer;
512 int outOffset = offset; 185 int outOffset = offset;
513 if (buffer is ByteArray || buffer is ObjectArray) { 186 if (buffer is ByteArray || buffer is ObjectArray) {
514 outBuffer = buffer; 187 outBuffer = buffer;
515 } else { 188 } else {
516 outBuffer = new ByteArray(bytes); 189 outBuffer = new ByteArray(bytes);
517 outOffset = 0; 190 outOffset = 0;
518 int j = offset; 191 int j = offset;
519 for (int i = 0; i < bytes; i++) { 192 for (int i = 0; i < bytes; i++) {
520 int value = buffer[j]; 193 int value = buffer[j];
521 if (value is! int) { 194 if (value is! int) {
522 throw new FileIOException( 195 throw new FileIOException(
523 "List element is not an integer at index $j"); 196 "List element is not an integer at index $j");
524 } 197 }
525 outBuffer[i] = value; 198 outBuffer[i] = value;
526 j++; 199 j++;
527 } 200 }
528 } 201 }
202 return [outBuffer, outOffset];
203 }
204
205 static bool exists(String name) native "File_Exists";
206 static int open(String name, int mode) native "File_Open";
207 static bool create(String name) native "File_Create";
208 static bool delete(String name) native "File_Delete";
209 static String fullPath(String name) native "File_FullPath";
210 static String directory(String name) native "File_Directory";
211 static int close(int id) native "File_Close";
212 static int readByte(int id) native "File_ReadByte";
213 static int readList(int id, List<int> buffer, int offset, int bytes)
214 native "File_ReadList";
215 static int writeByte(int id, int value) native "File_WriteByte";
216 static int writeList(int id, List<int> buffer, int offset, int bytes) {
217 List result =
218 _FileUtils.ensureFastAndSerializableBuffer(buffer, offset, bytes);
219 List outBuffer = result[0];
220 int outOffset = result[1];
529 return writeListNative(id, outBuffer, outOffset, bytes); 221 return writeListNative(id, outBuffer, outOffset, bytes);
530 } 222 }
531 static int writeListNative(int id, List<int> buffer, int offset, int bytes) 223 static int writeListNative(int id, List<int> buffer, int offset, int bytes)
532 native "File_WriteList"; 224 native "File_WriteList";
533 static int writeString(int id, String string) native "File_WriteString"; 225 static int writeString(int id, String string) native "File_WriteString";
534 static int position(int id) native "File_Position"; 226 static int position(int id) native "File_Position";
535 static bool setPosition(int id, int position) native "File_SetPosition"; 227 static bool setPosition(int id, int position) native "File_SetPosition";
536 static bool truncate(int id, int length) native "File_Truncate"; 228 static bool truncate(int id, int length) native "File_Truncate";
537 static int length(int id) native "File_Length"; 229 static int length(int id) native "File_Length";
538 static int flush(int id) native "File_Flush"; 230 static int flush(int id) native "File_Flush";
539 static int openStdio(int fd) native "File_OpenStdio"; 231 static int openStdio(int fd) native "File_OpenStdio";
232 static SendPort newServicePort() native "File_NewServicePort";
540 233
541 static int checkedOpen(String name, int mode) { 234 static int checkedOpen(String name, int mode) {
542 if (name is !String || mode is !int) return 0; 235 if (name is !String || mode is !int) return 0;
543 return open(name, mode); 236 return open(name, mode);
544 } 237 }
545 238
546 static bool checkedCreate(String name) { 239 static bool checkedCreate(String name) {
547 if (name is !String) return false; 240 if (name is !String) return false;
548 return create(name); 241 return create(name);
549 } 242 }
(...skipping 18 matching lines...) Expand all
568 static int checkedWriteString(int id, String string) { 261 static int checkedWriteString(int id, String string) {
569 if (string is !String) return -1; 262 if (string is !String) return -1;
570 return writeString(id, string); 263 return writeString(id, string);
571 } 264 }
572 } 265 }
573 266
574 267
575 // Class for encapsulating the native implementation of files. 268 // Class for encapsulating the native implementation of files.
576 class _File implements File { 269 class _File implements File {
577 // Constructor for file. 270 // Constructor for file.
578 _File(String this._name) 271 _File(String this._name) : _asyncUsed = false;
579 : _scheduler = new _FileOperationScheduler(),
580 _asyncUsed = false;
581 272
582 void exists() { 273 void exists() {
274 _ensureFileService();
583 _asyncUsed = true; 275 _asyncUsed = true;
584 if (_name is !String) { 276 if (_name is !String) {
585 if (_errorHandler != null) { 277 if (_errorHandler != null) {
586 _errorHandler('File name is not a string: $_name'); 278 _errorHandler('File name is not a string: $_name');
587 } 279 }
588 return; 280 return;
589 } 281 }
590 var operation = new _ExistsOperation(_name); 282 List request = new List(2);
591 _scheduler.enqueue(operation, (result, ignored) { 283 request[0] = _FileUtils.kExistsRequest;
592 var handler = 284 request[1] = _name;
593 (_existsHandler != null) ? _existsHandler : (result) => null; 285 _fileService.call(request).receive((exists, replyTo) {
594 handler(result); 286 if (_existsHandler != null) _existsHandler(exists);
595 }); 287 });
596 } 288 }
597 289
598 bool existsSync() { 290 bool existsSync() {
599 if (_asyncUsed) { 291 if (_asyncUsed) {
600 throw new FileIOException( 292 throw new FileIOException(
601 "Mixed use of synchronous and asynchronous API"); 293 "Mixed use of synchronous and asynchronous API");
602 } 294 }
603 if (_name is !String) { 295 if (_name is !String) {
604 throw new FileIOException('File name is not a string: $_name'); 296 throw new FileIOException('File name is not a string: $_name');
605 } 297 }
606 return _FileUtils.exists(_name); 298 return _FileUtils.exists(_name);
607 } 299 }
608 300
609 void create() { 301 void create() {
302 _ensureFileService();
610 _asyncUsed = true; 303 _asyncUsed = true;
611 var handleCreateResult = (created, ignored) { 304 List request = new List(2);
612 var handler = (_createHandler != null) ? _createHandler : () => null; 305 request[0] = _FileUtils.kCreateRequest;
306 request[1] = _name;
307 _fileService.call(request).receive((created, replyTo) {
613 if (created) { 308 if (created) {
614 handler(); 309 if (_createHandler != null) _createHandler();
615 } else if (_errorHandler != null) { 310 } else if (_errorHandler != null) {
616 _errorHandler("Cannot create file: $_name"); 311 _errorHandler("Cannot create file: $_name");
617 } 312 }
618 }; 313 });
619 var operation = new _CreateOperation(_name);
620 _scheduler.enqueue(operation, handleCreateResult);
621 } 314 }
622 315
623 void createSync() { 316 void createSync() {
624 if (_asyncUsed) { 317 if (_asyncUsed) {
625 throw new FileIOException( 318 throw new FileIOException(
626 "Mixed use of synchronous and asynchronous API"); 319 "Mixed use of synchronous and asynchronous API");
627 } 320 }
628 bool created = _FileUtils.checkedCreate(_name); 321 bool created = _FileUtils.checkedCreate(_name);
629 if (!created) { 322 if (!created) {
630 throw new FileIOException("Cannot create file: $_name"); 323 throw new FileIOException("Cannot create file: $_name");
631 } 324 }
632 } 325 }
633 326
634 void delete() { 327 void delete() {
328 _ensureFileService();
635 _asyncUsed = true; 329 _asyncUsed = true;
636 var handleDeleteResult = (created, ignored) { 330 List request = new List(2);
637 var handler = (_deleteHandler != null) ? _deleteHandler : () => null; 331 request[0] = _FileUtils.kDeleteRequest;
638 if (created) { 332 request[1] = _name;
639 handler(); 333 _fileService.call(request).receive((deleted, replyTo) {
334 if (deleted) {
335 if (_deleteHandler != null) _deleteHandler();
640 } else if (_errorHandler != null) { 336 } else if (_errorHandler != null) {
641 _errorHandler("Cannot delete file: $_name"); 337 _errorHandler("Cannot delete file: $_name");
642 } 338 }
643 }; 339 });
644 var operation = new _DeleteOperation(_name);
645 _scheduler.enqueue(operation, handleDeleteResult);
646 } 340 }
647 341
648 void deleteSync() { 342 void deleteSync() {
649 if (_asyncUsed) { 343 if (_asyncUsed) {
650 throw new FileIOException( 344 throw new FileIOException(
651 "Mixed use of synchronous and asynchronous API"); 345 "Mixed use of synchronous and asynchronous API");
652 } 346 }
653 bool deleted = _FileUtils.checkedDelete(_name); 347 bool deleted = _FileUtils.checkedDelete(_name);
654 if (!deleted) { 348 if (!deleted) {
655 throw new FileIOException("Cannot delete file: $_name"); 349 throw new FileIOException("Cannot delete file: $_name");
656 } 350 }
657 } 351 }
658 352
659 void directory() { 353 void directory() {
354 _ensureFileService();
660 _asyncUsed = true; 355 _asyncUsed = true;
661 var handleDirectoryResult = (path, ignored) { 356 List request = new List(2);
662 var handler = 357 request[0] = _FileUtils.kDirectoryRequest;
663 (_directoryHandler != null) ? _directoryHandler : (s) => null; 358 request[1] = _name;
359 _fileService.call(request).receive((path, replyTo) {
664 if (path != null) { 360 if (path != null) {
665 handler(new Directory(path)); 361 if (_directoryHandler != null) _directoryHandler(new Directory(path));
666 } else if (_errorHandler != null) { 362 } else if (_errorHandler != null) {
667 _errorHandler("Cannot get containing directory for: ${_name}"); 363 _errorHandler("Cannot get directory for: ${_name}");
668 } 364 }
669 }; 365 });
670 var operation = new _DirectoryOperation(_name);
671 _scheduler.enqueue(operation, handleDirectoryResult);
672 } 366 }
673 367
674 void directorySync() { 368 void directorySync() {
675 if (_asyncUsed) { 369 if (_asyncUsed) {
676 throw new FileIOException( 370 throw new FileIOException(
677 "Mixed use of synchronous and asynchronous API"); 371 "Mixed use of synchronous and asynchronous API");
678 } 372 }
679 if (!existsSync()) { 373 if (!existsSync()) {
680 throw new FileIOException("Cannot get directory for: $_name"); 374 throw new FileIOException("Cannot get directory for: $_name");
681 } 375 }
682 return new Directory(_FileUtils.directory(_name)); 376 return new Directory(_FileUtils.directory(_name));
683 } 377 }
684 378
685 void open([FileMode mode = FileMode.READ]) { 379 void open([FileMode mode = FileMode.READ]) {
380 _ensureFileService();
686 _asyncUsed = true; 381 _asyncUsed = true;
687 if (mode != FileMode.READ && 382 if (mode != FileMode.READ &&
688 mode != FileMode.WRITE && 383 mode != FileMode.WRITE &&
689 mode != FileMode.APPEND) { 384 mode != FileMode.APPEND) {
690 if (_errorHandler != null) { 385 if (_errorHandler != null) {
691 _errorHandler("Unknown file mode. Use FileMode.READ, FileMode.WRITE " + 386 _errorHandler("Unknown file mode. Use FileMode.READ, FileMode.WRITE " +
692 "or FileMode.APPEND."); 387 "or FileMode.APPEND.");
693 return; 388 return;
694 } 389 }
695 } 390 }
696 var handleOpenResult = (id, ignored) { 391 List request = new List(3);
697 // If no open handler is present, close the file immediately to 392 request[0] = _FileUtils.kOpenRequest;
698 // avoid leaking an open file descriptor. 393 request[1] = _name;
394 request[2] = mode._mode; // Direct int value for serialization.
395 _fileService.call(request).receive((id, replyTo) {
699 var handler = _openHandler; 396 var handler = _openHandler;
700 if (handler === null) { 397 if (handler === null) {
398 // If no open handler is present, close the file immediately to
399 // avoid leaking an open file descriptor.
701 handler = (file) => file.close(); 400 handler = (file) => file.close();
702 } 401 }
703 if (id != 0) { 402 if (id != 0) {
704 var randomAccessFile = new _RandomAccessFile(id, _name); 403 var randomAccessFile = new _RandomAccessFile(id, _name);
705 handler(randomAccessFile); 404 handler(randomAccessFile);
706 } else if (_errorHandler != null) { 405 } else if (_errorHandler != null) {
707 _errorHandler("Cannot open file: $_name"); 406 _errorHandler("Cannot open file: $_name");
708 } 407 }
709 }; 408 });
710 var operation = new _OpenOperation(_name, mode._mode);
711 _scheduler.enqueue(operation, handleOpenResult);
712 } 409 }
713 410
714 RandomAccessFile openSync([FileMode mode = FileMode.READ]) { 411 RandomAccessFile openSync([FileMode mode = FileMode.READ]) {
715 if (_asyncUsed) { 412 if (_asyncUsed) {
716 throw new FileIOException( 413 throw new FileIOException(
717 "Mixed use of synchronous and asynchronous API"); 414 "Mixed use of synchronous and asynchronous API");
718 } 415 }
719 if (mode != FileMode.READ && 416 if (mode != FileMode.READ &&
720 mode != FileMode.WRITE && 417 mode != FileMode.WRITE &&
721 mode != FileMode.APPEND) { 418 mode != FileMode.APPEND) {
722 throw new FileIOException("Unknown file mode. Use FileMode.READ, " + 419 throw new FileIOException("Unknown file mode. Use FileMode.READ, " +
723 "FileMode.WRITE or FileMode.APPEND."); 420 "FileMode.WRITE or FileMode.APPEND.");
724 } 421 }
725 var id = _FileUtils.checkedOpen(_name, mode._mode); 422 var id = _FileUtils.checkedOpen(_name, mode._mode);
726 if (id == 0) { 423 if (id == 0) {
727 throw new FileIOException("Cannot open file: $_name"); 424 throw new FileIOException("Cannot open file: $_name");
728 } 425 }
729 return new _RandomAccessFile(id, _name); 426 return new _RandomAccessFile(id, _name);
730 } 427 }
731 428
732 static RandomAccessFile _openStdioSync(int fd) { 429 static RandomAccessFile _openStdioSync(int fd) {
733 var id = _FileUtils.openStdio(fd); 430 var id = _FileUtils.openStdio(fd);
734 if (id == 0) { 431 if (id == 0) {
735 throw new FileIOException("Cannot open stdio file for: $fd"); 432 throw new FileIOException("Cannot open stdio file for: $fd");
736 } 433 }
737 return new _RandomAccessFile(id, ""); 434 return new _RandomAccessFile(id, "");
738 } 435 }
739 436
740 void fullPath() { 437 void fullPath() {
438 _ensureFileService();
741 _asyncUsed = true; 439 _asyncUsed = true;
742 var handleFullPathResult = (result, ignored) { 440 List request = new List(2);
743 var handler = _fullPathHandler; 441 request[0] = _FileUtils.kFullPathRequest;
744 if (handler == null) handler = (path) => null; 442 request[1] = _name;
443 _fileService.call(request).receive((result, replyTo) {
745 if (result != null) { 444 if (result != null) {
746 handler(result); 445 if (_fullPathHandler != null) _fullPathHandler(result);
747 } else if (_errorHandler != null) { 446 } else if (_errorHandler != null) {
748 _errorHandler("fullPath failed"); 447 _errorHandler("fullPath failed");
749 } 448 }
750 }; 449 });
751 var operation = new _FullPathOperation(_name);
752 _scheduler.enqueue(operation, handleFullPathResult);
753 } 450 }
754 451
755 String fullPathSync() { 452 String fullPathSync() {
756 if (_asyncUsed) { 453 if (_asyncUsed) {
757 throw new FileIOException( 454 throw new FileIOException(
758 "Mixed use of synchronous and asynchronous API"); 455 "Mixed use of synchronous and asynchronous API");
759 } 456 }
760 String result = _FileUtils.checkedFullPath(_name); 457 String result = _FileUtils.checkedFullPath(_name);
761 if (result == null) { 458 if (result == null) {
762 throw new FileIOException("fullPath failed"); 459 throw new FileIOException("fullPath failed");
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
858 } 555 }
859 556
860 void set fullPathHandler(void handler(String)) { 557 void set fullPathHandler(void handler(String)) {
861 _fullPathHandler = handler; 558 _fullPathHandler = handler;
862 } 559 }
863 560
864 void set errorHandler(void handler(String error)) { 561 void set errorHandler(void handler(String error)) {
865 _errorHandler = handler; 562 _errorHandler = handler;
866 } 563 }
867 564
565 void _ensureFileService() {
566 if (_fileService == null) {
567 _fileService = _FileUtils.newServicePort();
568 }
569 }
570
868 String _name; 571 String _name;
869 bool _asyncUsed; 572 bool _asyncUsed;
870 573
871 _FileOperationScheduler _scheduler; 574 SendPort _fileService;
872 575
873 Function _existsHandler; 576 Function _existsHandler;
874 Function _createHandler; 577 Function _createHandler;
875 Function _deleteHandler; 578 Function _deleteHandler;
876 Function _directoryHandler; 579 Function _directoryHandler;
877 Function _openHandler; 580 Function _openHandler;
878 Function _inputStreamHandler; 581 Function _inputStreamHandler;
879 Function _outputStreamHandler; 582 Function _outputStreamHandler;
880 Function _fullPathHandler; 583 Function _fullPathHandler;
881 Function _errorHandler; 584 Function _errorHandler;
882 } 585 }
883 586
884 587
885 class _RandomAccessFile implements RandomAccessFile { 588 class _RandomAccessFile implements RandomAccessFile {
886 _RandomAccessFile(int this._id, String this._name) 589 _RandomAccessFile(int this._id, String this._name) : _asyncUsed = false;
887 : _scheduler = new _FileOperationScheduler(),
888 _asyncUsed = false;
889 590
890 void close() { 591 void close() {
592 if (_id == 0) return;
593 _ensureFileService();
891 _asyncUsed = true; 594 _asyncUsed = true;
892 var handleCloseResult = (result, ignored) { 595 List request = new List(2);
893 var handler = (_closeHandler != null) ? _closeHandler : () => null; 596 request[0] = _FileUtils.kCloseRequest;
597 request[1] = _id;
598 // Set the id_ to 0 (NULL) to ensure the no more async requests
599 // can be issues for this file.
600 _id = 0;
601 _fileService.call(request).receive((result, replyTo) {
894 if (result != -1) { 602 if (result != -1) {
895 _id = result; 603 _id = result;
896 handler(); 604 if (_closeHandler != null) _closeHandler();
897 } else if (_errorHandler != null) { 605 } else if (_errorHandler != null) {
898 _errorHandler("Cannot close file: $_name"); 606 _errorHandler("Cannot close file: $_name");
899 } 607 }
900 }; 608 });
901 var operation = new _CloseOperation(_id);
902 _scheduler.enqueue(operation, handleCloseResult);
903 } 609 }
904 610
905 void closeSync() { 611 void closeSync() {
906 if (_asyncUsed) { 612 if (_asyncUsed) {
907 throw new FileIOException( 613 throw new FileIOException(
908 "Mixed use of synchronous and asynchronous API"); 614 "Mixed use of synchronous and asynchronous API");
909 } 615 }
910 var id = _FileUtils.close(_id); 616 var id = _FileUtils.close(_id);
911 if (id == -1) { 617 if (id == -1) {
912 throw new FileIOException("Cannot close file: $_name"); 618 throw new FileIOException("Cannot close file: $_name");
913 } 619 }
914 _id = id; 620 _id = id;
915 } 621 }
916 622
917 void readByte() { 623 void readByte() {
624 _ensureFileService();
918 _asyncUsed = true; 625 _asyncUsed = true;
919 var handleReadByteResult = (result, ignored) { 626 List request = new List(2);
920 var handler = 627 request[0] = _FileUtils.kReadByteRequest;
921 (_readByteHandler != null) ? _readByteHandler : (byte) => null; 628 request[1] = _id;
629 _fileService.call(request).receive((result, replyTo) {
922 if (result != -1) { 630 if (result != -1) {
923 handler(result); 631 if (_readByteHandler != null) _readByteHandler(result);
924 } else if (_errorHandler != null) { 632 } else if (_errorHandler != null) {
925 _errorHandler("readByte failed"); 633 _errorHandler("readByte failed");
926 } 634 }
927 }; 635 });
928 var operation = new _ReadByteOperation(_id);
929 _scheduler.enqueue(operation, handleReadByteResult);
930 } 636 }
931 637
932 int readByteSync() { 638 int readByteSync() {
933 if (_asyncUsed) { 639 if (_asyncUsed) {
934 throw new FileIOException( 640 throw new FileIOException(
935 "Mixed use of synchronous and asynchronous API"); 641 "Mixed use of synchronous and asynchronous API");
936 } 642 }
937 int result = _FileUtils.readByte(_id); 643 int result = _FileUtils.readByte(_id);
938 if (result == -1) { 644 if (result == -1) {
939 throw new FileIOException("readByte failed"); 645 throw new FileIOException("readByte failed");
940 } 646 }
941 return result; 647 return result;
942 } 648 }
943 649
944 void readList(List<int> buffer, int offset, int bytes) { 650 void readList(List<int> buffer, int offset, int bytes) {
651 _ensureFileService();
945 _asyncUsed = true; 652 _asyncUsed = true;
946 if (buffer is !List || offset is !int || bytes is !int) { 653 if (buffer is !List || offset is !int || bytes is !int) {
947 if (_errorHandler != null) { 654 if (_errorHandler != null) {
948 _errorHandler("Invalid arguments to readList"); 655 _errorHandler("Invalid arguments to readList");
949 } 656 }
950 return; 657 return;
951 }; 658 };
952 var handleReadListResult = (result, ignored) { 659 List request = new List(3);
953 var handler = 660 request[0] = _FileUtils.kReadListRequest;
954 (_readListHandler != null) ? _readListHandler : (result) => null; 661 request[1] = _id;
955 if (result is _ReadListResult && result.read != -1) { 662 request[2] = bytes;
956 var read = result.read; 663 _fileService.call(request).receive((result, replyTo) {
957 buffer.setRange(offset, read, result.buffer); 664 if (result is List && result.length == 2 && result[0] != -1) {
958 handler(read); 665 var read = result[0];
666 var data = result[1];
667 buffer.setRange(offset, read, data);
668 if (_readListHandler != null) _readListHandler(read);
959 return; 669 return;
960 } 670 } else if (_errorHandler != null) {
961 if (_errorHandler != null) {
962 _errorHandler(result is String ? result : "readList failed"); 671 _errorHandler(result is String ? result : "readList failed");
963 } 672 }
964 }; 673 });
965 var operation = new _ReadListOperation(_id, buffer.length, offset, bytes);
966 _scheduler.enqueue(operation, handleReadListResult);
967 } 674 }
968 675
969 int readListSync(List<int> buffer, int offset, int bytes) { 676 int readListSync(List<int> buffer, int offset, int bytes) {
970 if (_asyncUsed) { 677 if (_asyncUsed) {
971 throw new FileIOException( 678 throw new FileIOException(
972 "Mixed use of synchronous and asynchronous API"); 679 "Mixed use of synchronous and asynchronous API");
973 } 680 }
974 if (buffer is !List || offset is !int || bytes is !int) { 681 if (buffer is !List || offset is !int || bytes is !int) {
975 throw new FileIOException("Invalid arguments to readList"); 682 throw new FileIOException("Invalid arguments to readList");
976 } 683 }
977 if (bytes == 0) return 0; 684 if (bytes == 0) return 0;
978 int index = 685 int index =
979 _FileUtils.checkReadWriteListArguments(buffer.length, offset, bytes); 686 _FileUtils.checkReadWriteListArguments(buffer.length, offset, bytes);
980 if (index != 0) { 687 if (index != 0) {
981 throw new IndexOutOfRangeException(index); 688 throw new IndexOutOfRangeException(index);
982 } 689 }
983 int result = _FileUtils.readList(_id, buffer, offset, bytes); 690 int result = _FileUtils.readList(_id, buffer, offset, bytes);
984 if (result == -1) { 691 if (result == -1) {
985 throw new FileIOException("readList failed"); 692 throw new FileIOException("readList failed");
986 } 693 }
987 return result; 694 return result;
988 } 695 }
989 696
990 void _checkPendingWrites() {
991 if (_scheduler.noPendingWrite() && _noPendingWriteHandler != null) {
992 _noPendingWriteHandler();
993 }
994 }
995
996 void writeByte(int value) { 697 void writeByte(int value) {
698 _ensureFileService();
997 _asyncUsed = true; 699 _asyncUsed = true;
998 if (value is !int) { 700 if (value is !int) {
999 if (_errorHandler != null) { 701 if (_errorHandler != null) {
1000 _errorHandler("Invalid argument to writeByte"); 702 _errorHandler("Invalid argument to writeByte");
1001 } 703 }
1002 return; 704 return;
1003 } 705 }
1004 var handleReadByteResult = (result, ignored) { 706 List request = new List(3);
1005 if (result == -1 &&_errorHandler != null) { 707 request[0] = _FileUtils.kWriteByteRequest;
708 request[1] = _id;
709 request[2] = value;
710 _writeEnqueued();
711 _fileService.call(request).receive((result, replyTo) {
712 _writeCompleted();
713 if (result == -1 && _errorHandler !== null) {
1006 _errorHandler("writeByte failed"); 714 _errorHandler("writeByte failed");
1007 return;
1008 } 715 }
1009 _checkPendingWrites(); 716 });
1010 };
1011 var operation = new _WriteByteOperation(_id, value);
1012 _scheduler.enqueue(operation, handleReadByteResult);
1013 } 717 }
1014 718
1015 int writeByteSync(int value) { 719 int writeByteSync(int value) {
1016 if (_asyncUsed) { 720 if (_asyncUsed) {
1017 throw new FileIOException( 721 throw new FileIOException(
1018 "Mixed use of synchronous and asynchronous API"); 722 "Mixed use of synchronous and asynchronous API");
1019 } 723 }
1020 if (value is !int) { 724 if (value is !int) {
1021 throw new FileIOException("Invalid argument to writeByte"); 725 throw new FileIOException("Invalid argument to writeByte");
1022 } 726 }
1023 int result = _FileUtils.writeByte(_id, value); 727 int result = _FileUtils.writeByte(_id, value);
1024 if (result == -1) { 728 if (result == -1) {
1025 throw new FileIOException("writeByte failed"); 729 throw new FileIOException("writeByte failed");
1026 } 730 }
1027 return result; 731 return result;
1028 } 732 }
1029 733
1030 void writeList(List<int> buffer, int offset, int bytes) { 734 void writeList(List<int> buffer, int offset, int bytes) {
735 _ensureFileService();
1031 _asyncUsed = true; 736 _asyncUsed = true;
1032 if (buffer is !List || offset is !int || bytes is !int) { 737 if (buffer is !List || offset is !int || bytes is !int) {
1033 if (_errorHandler != null) { 738 if (_errorHandler != null) {
1034 _errorHandler("Invalid arguments to writeList"); 739 _errorHandler("Invalid arguments to writeList");
1035 } 740 }
1036 return; 741 return;
1037 } 742 }
1038 var handleWriteListResult = (result, ignored) { 743
1039 if (result is !String && result != -1) { 744 List result =
1040 if (result < bytes) { 745 _FileUtils.ensureFastAndSerializableBuffer(buffer, offset, bytes);
1041 writeList(buffer, offset + result, bytes - result); 746 List outBuffer = result[0];
1042 } else { 747 int outOffset = result[1];
1043 _checkPendingWrites(); 748
1044 } 749 List request = new List(5);
1045 return; 750 request[0] = _FileUtils.kWriteListRequest;
751 request[1] = _id;
752 request[2] = outBuffer;
753 request[3] = outOffset;
754 request[4] = bytes;
755 _writeEnqueued();
756 _fileService.call(request).receive((result, replyTo) {
757 _writeCompleted();
758 if (result == -1 && _errorHandler !== null) {
759 _errorHandler("writeList failed");
1046 } 760 }
1047 if (_errorHandler != null) { 761 });
1048 _errorHandler(result is String ? result : "writeList failed");
1049 }
1050 };
1051 var operation = new _WriteListOperation(_id, buffer, offset, bytes);
1052 _scheduler.enqueue(operation, handleWriteListResult);
1053 } 762 }
1054 763
1055 int writeListSync(List<int> buffer, int offset, int bytes) { 764 int writeListSync(List<int> buffer, int offset, int bytes) {
1056 if (_asyncUsed) { 765 if (_asyncUsed) {
1057 throw new FileIOException( 766 throw new FileIOException(
1058 "Mixed use of synchronous and asynchronous API"); 767 "Mixed use of synchronous and asynchronous API");
1059 } 768 }
1060 if (buffer is !List || offset is !int || bytes is !int) { 769 if (buffer is !List || offset is !int || bytes is !int) {
1061 throw new FileIOException("Invalid arguments to writeList"); 770 throw new FileIOException("Invalid arguments to writeList");
1062 } 771 }
1063 if (bytes == 0) return 0; 772 if (bytes == 0) return 0;
1064 int index = 773 int index =
1065 _FileUtils.checkReadWriteListArguments(buffer.length, offset, bytes); 774 _FileUtils.checkReadWriteListArguments(buffer.length, offset, bytes);
1066 if (index != 0) { 775 if (index != 0) {
1067 throw new IndexOutOfRangeException(index); 776 throw new IndexOutOfRangeException(index);
1068 } 777 }
1069 int result = _FileUtils.writeList(_id, buffer, offset, bytes); 778 int result = _FileUtils.writeList(_id, buffer, offset, bytes);
1070 if (result == -1) { 779 if (result == -1) {
1071 throw new FileIOException("writeList failed"); 780 throw new FileIOException("writeList failed");
1072 } 781 }
1073 return result; 782 return result;
1074 } 783 }
1075 784
1076 void writeString(String string) { 785 void writeString(String string) {
786 _ensureFileService();
1077 _asyncUsed = true; 787 _asyncUsed = true;
1078 var handleWriteStringResult = (result, ignored) { 788 List request = new List(3);
1079 if (result == -1 &&_errorHandler != null) { 789 request[0] = _FileUtils.kWriteStringRequest;
790 request[1] = _id;
791 request[2] = string;
792 _writeEnqueued();
793 _fileService.call(request).receive((result, replyTo) {
794 _writeCompleted();
795 if (result == -1 && _errorHandler !== null) {
1080 _errorHandler("writeString failed"); 796 _errorHandler("writeString failed");
1081 return;
1082 } 797 }
1083 if (result < string.length) { 798 });
1084 writeString(string.substring(result));
1085 } else {
1086 _checkPendingWrites();
1087 }
1088 };
1089 var operation = new _WriteStringOperation(_id, string);
1090 _scheduler.enqueue(operation, handleWriteStringResult);
1091 } 799 }
1092 800
1093 int writeStringSync(String string) { 801 int writeStringSync(String string) {
1094 if (_asyncUsed) { 802 if (_asyncUsed) {
1095 throw new FileIOException( 803 throw new FileIOException(
1096 "Mixed use of synchronous and asynchronous API"); 804 "Mixed use of synchronous and asynchronous API");
1097 } 805 }
1098 int result = _FileUtils.checkedWriteString(_id, string); 806 int result = _FileUtils.checkedWriteString(_id, string);
1099 if (result == -1) { 807 if (result == -1) {
1100 throw new FileIOException("writeString failed"); 808 throw new FileIOException("writeString failed");
1101 } 809 }
1102 return result; 810 return result;
1103 } 811 }
1104 812
1105 void position() { 813 void position() {
814 _ensureFileService();
1106 _asyncUsed = true; 815 _asyncUsed = true;
1107 var handlePositionResult = (result, ignored) { 816 List request = new List(2);
1108 var handler = 817 request[0] = _FileUtils.kPositionRequest;
1109 (_positionHandler != null) ? _positionHandler : (pos) => null; 818 request[1] = _id;
1110 if (result == -1 && _errorHandler != null) { 819 _fileService.call(request).receive((result, replyTo) {
820 if (result != -1) {
821 if (_positionHandler != null) _positionHandler(result);
822 } else if (_errorHandler != null) {
1111 _errorHandler("position failed"); 823 _errorHandler("position failed");
1112 return;
1113 } 824 }
1114 handler(result); 825 });
1115 };
1116 var operation = new _PositionOperation(_id);
1117 _scheduler.enqueue(operation, handlePositionResult);
1118 } 826 }
1119 827
1120 int positionSync() { 828 int positionSync() {
1121 if (_asyncUsed) { 829 if (_asyncUsed) {
1122 throw new FileIOException( 830 throw new FileIOException(
1123 "Mixed use of synchronous and asynchronous API"); 831 "Mixed use of synchronous and asynchronous API");
1124 } 832 }
1125 int result = _FileUtils.position(_id); 833 int result = _FileUtils.position(_id);
1126 if (result == -1) { 834 if (result == -1) {
1127 throw new FileIOException("position failed"); 835 throw new FileIOException("position failed");
1128 } 836 }
1129 return result; 837 return result;
1130 } 838 }
1131 839
1132 void setPosition(int position) { 840 void setPosition(int position) {
841 _ensureFileService();
1133 _asyncUsed = true; 842 _asyncUsed = true;
1134 var handleSetPositionResult = (result, ignored) { 843 List request = new List(3);
1135 var handler = 844 request[0] = _FileUtils.kSetPositionRequest;
1136 (_setPositionHandler != null) ? _setPositionHandler : () => null; 845 request[1] = _id;
1137 if (result == false && _errorHandler != null) { 846 request[2] = position;
847 _fileService.call(request).receive((result, replyTo) {
848 if (result) {
849 if (_setPositionHandler != null) _setPositionHandler();
850 } else if (_errorHandler != null) {
1138 _errorHandler("setPosition failed"); 851 _errorHandler("setPosition failed");
1139 return;
1140 } 852 }
1141 handler(); 853 });
1142 };
1143 var operation = new _SetPositionOperation(_id, position);
1144 _scheduler.enqueue(operation, handleSetPositionResult);
1145 } 854 }
1146 855
1147 void setPositionSync(int position) { 856 void setPositionSync(int position) {
857 _ensureFileService();
1148 if (_asyncUsed) { 858 if (_asyncUsed) {
1149 throw new FileIOException( 859 throw new FileIOException(
1150 "Mixed use of synchronous and asynchronous API"); 860 "Mixed use of synchronous and asynchronous API");
1151 } 861 }
1152 bool result = _FileUtils.setPosition(_id, position); 862 bool result = _FileUtils.setPosition(_id, position);
1153 if (result == false) { 863 if (result == false) {
1154 throw new FileIOException("setPosition failed"); 864 throw new FileIOException("setPosition failed");
1155 } 865 }
1156 } 866 }
1157 867
1158 void truncate(int length) { 868 void truncate(int length) {
869 _ensureFileService();
1159 _asyncUsed = true; 870 _asyncUsed = true;
1160 var handleTruncateResult = (result, ignored) { 871 List request = new List(3);
1161 var handler = (_truncateHandler != null) ? _truncateHandler : () => null; 872 request[0] = _FileUtils.kTruncateRequest;
1162 if (result == false && _errorHandler != null) { 873 request[1] = _id;
874 request[2] = length;
875 _fileService.call(request).receive((result, replyTo) {
876 if (result) {
877 if (_truncateHandler != null) _truncateHandler();
878 } else if (_errorHandler != null) {
1163 _errorHandler("truncate failed"); 879 _errorHandler("truncate failed");
1164 return;
1165 } 880 }
1166 handler(); 881 });
1167 };
1168 var operation = new _TruncateOperation(_id, length);
1169 _scheduler.enqueue(operation, handleTruncateResult);
1170 } 882 }
1171 883
1172 void truncateSync(int length) { 884 void truncateSync(int length) {
1173 if (_asyncUsed) { 885 if (_asyncUsed) {
1174 throw new FileIOException( 886 throw new FileIOException(
1175 "Mixed use of synchronous and asynchronous API"); 887 "Mixed use of synchronous and asynchronous API");
1176 } 888 }
1177 bool result = _FileUtils.truncate(_id, length); 889 bool result = _FileUtils.truncate(_id, length);
1178 if (result == false) { 890 if (result == false) {
1179 throw new FileIOException("truncate failed"); 891 throw new FileIOException("truncate failed");
1180 } 892 }
1181 } 893 }
1182 894
1183 void length() { 895 void length() {
896 _ensureFileService();
1184 _asyncUsed = true; 897 _asyncUsed = true;
1185 var handleLengthResult = (result, ignored) { 898 List request = new List(2);
1186 var handler = (_lengthHandler != null) ? _lengthHandler : (pos) => null; 899 request[0] = _FileUtils.kLengthRequest;
1187 if (result == -1 && _errorHandler != null) { 900 request[1] = _id;
901 _fileService.call(request).receive((result, replyTo) {
902 if (result != -1) {
903 if (_lengthHandler != null) _lengthHandler(result);
904 } else if (_errorHandler != null) {
1188 _errorHandler("length failed"); 905 _errorHandler("length failed");
1189 return;
1190 } 906 }
1191 handler(result); 907 });
1192 };
1193 var operation = new _LengthOperation(_id);
1194 _scheduler.enqueue(operation, handleLengthResult);
1195 } 908 }
1196 909
1197 int lengthSync() { 910 int lengthSync() {
1198 if (_asyncUsed) { 911 if (_asyncUsed) {
1199 throw new FileIOException( 912 throw new FileIOException(
1200 "Mixed use of synchronous and asynchronous API"); 913 "Mixed use of synchronous and asynchronous API");
1201 } 914 }
1202 int result = _FileUtils.length(_id); 915 int result = _FileUtils.length(_id);
1203 if (result == -1) { 916 if (result == -1) {
1204 throw new FileIOException("length failed"); 917 throw new FileIOException("length failed");
1205 } 918 }
1206 return result; 919 return result;
1207 } 920 }
1208 921
1209 void flush() { 922 void flush() {
923 _ensureFileService();
1210 _asyncUsed = true; 924 _asyncUsed = true;
1211 var handleFlushResult = (result, ignored) { 925 List request = new List(2);
1212 var handler = (_flushHandler != null) ? _flushHandler : (pos) => null; 926 request[0] = _FileUtils.kFlushRequest;
1213 if (result == -1 && _errorHandler != null) { 927 request[1] = _id;
928 _fileService.call(request).receive((result, replyTo) {
929 if (result != -1) {
930 if (_flushHandler != null) _flushHandler();
931 } else if (_errorHandler != null) {
1214 _errorHandler("flush failed"); 932 _errorHandler("flush failed");
1215 return;
1216 } 933 }
1217 handler(); 934 });
1218 };
1219 var operation = new _FlushOperation(_id);
1220 _scheduler.enqueue(operation, handleFlushResult);
1221 } 935 }
1222 936
1223 void flushSync() { 937 void flushSync() {
1224 if (_asyncUsed) { 938 if (_asyncUsed) {
1225 throw new FileIOException( 939 throw new FileIOException(
1226 "Mixed use of synchronous and asynchronous API"); 940 "Mixed use of synchronous and asynchronous API");
1227 } 941 }
1228 int result = _FileUtils.flush(_id); 942 int result = _FileUtils.flush(_id);
1229 if (result == -1) { 943 if (result == -1) {
1230 throw new FileIOException("flush failed"); 944 throw new FileIOException("flush failed");
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
1266 } 980 }
1267 981
1268 void set lengthHandler(void handler(int length)) { 982 void set lengthHandler(void handler(int length)) {
1269 _lengthHandler = handler; 983 _lengthHandler = handler;
1270 } 984 }
1271 985
1272 void set flushHandler(void handler()) { 986 void set flushHandler(void handler()) {
1273 _flushHandler = handler; 987 _flushHandler = handler;
1274 } 988 }
1275 989
990 void _ensureFileService() {
991 if (_fileService == null) {
992 _fileService = _FileUtils.newServicePort();
993 }
994 }
995
996 void _writeEnqueued() => _pendingWrites++;
997
998 void _writeCompleted() {
999 _pendingWrites--;
1000 if (_pendingWrites == 0 && _noPendingWriteHandler != null) {
1001 _noPendingWriteHandler();
1002 }
1003 }
1004
1005
1276 String _name; 1006 String _name;
1277 int _id; 1007 int _id;
1278 bool _asyncUsed; 1008 bool _asyncUsed;
1009 int _pendingWrites = 0;
1279 1010
1280 _FileOperationScheduler _scheduler; 1011 SendPort _fileService;
1281 1012
1282 Function _closeHandler; 1013 Function _closeHandler;
1283 Function _readByteHandler; 1014 Function _readByteHandler;
1284 Function _readListHandler; 1015 Function _readListHandler;
1285 Function _noPendingWriteHandler; 1016 Function _noPendingWriteHandler;
1286 Function _positionHandler; 1017 Function _positionHandler;
1287 Function _setPositionHandler; 1018 Function _setPositionHandler;
1288 Function _truncateHandler; 1019 Function _truncateHandler;
1289 Function _lengthHandler; 1020 Function _lengthHandler;
1290 Function _flushHandler; 1021 Function _flushHandler;
1291 Function _errorHandler; 1022 Function _errorHandler;
1292 } 1023 }
OLDNEW
« no previous file with comments | « runtime/bin/file.cc ('k') | runtime/vm/dart_api_message.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698