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

Side by Side Diff: sdk/lib/io/file_impl.dart

Issue 24721003: Only allow one async operation on RandomAccessFile at a time. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Also disallow sync calls while an async operation is scheduled. Created 7 years, 2 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 | « no previous file | tests/standalone/io/file_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, 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 part of dart.io; 5 part of dart.io;
6 6
7 // Read the file in blocks of size 64k. 7 // Read the file in blocks of size 64k.
8 const int _BLOCK_SIZE = 64 * 1024; 8 const int _BLOCK_SIZE = 64 * 1024;
9 9
10 10
(...skipping 513 matching lines...) Expand 10 before | Expand all | Expand 10 after
524 if (result is OSError) { 524 if (result is OSError) {
525 throw new FileException(msg, path, result); 525 throw new FileException(msg, path, result);
526 } 526 }
527 } 527 }
528 } 528 }
529 529
530 530
531 class _RandomAccessFile implements RandomAccessFile { 531 class _RandomAccessFile implements RandomAccessFile {
532 final String path; 532 final String path;
533 int _id; 533 int _id;
534 bool _asyncDispatched = false;
534 SendPort _fileService; 535 SendPort _fileService;
535 536
536 _RandomAccessFile(int this._id, String this.path); 537 _RandomAccessFile(int this._id, String this.path);
537 538
538 Future<RandomAccessFile> close() { 539 Future<RandomAccessFile> close() {
539 if (closed) return _closedException(); 540 return _dispatch(_FILE_CLOSE, [_id], markClosed: true).then((result) {
540 // Set the id_ to 0 (NULL) to ensure the no more async requests
541 // can be issued for this file.
542 int id = _id;
543 _id = 0;
544 return _IOService.dispatch(_FILE_CLOSE, [id]).then((result) {
545 if (result != -1) { 541 if (result != -1) {
546 _id = result; 542 _id = result;
547 return this; 543 return this;
548 } else { 544 } else {
549 throw new FileException("Cannot close file", path); 545 throw new FileException("Cannot close file", path);
550 } 546 }
551 }); 547 });
552 } 548 }
553 549
554 external static int _close(int id); 550 external static int _close(int id);
555 551
556 void closeSync() { 552 void closeSync() {
557 _checkNotClosed(); 553 _checkAvailable();
558 var id = _close(_id); 554 var id = _close(_id);
559 if (id == -1) { 555 if (id == -1) {
560 throw new FileException("Cannot close file", path); 556 throw new FileException("Cannot close file", path);
561 } 557 }
562 _id = id; 558 _id = id;
563 } 559 }
564 560
565 Future<int> readByte() { 561 Future<int> readByte() {
566 if (closed) return _closedException(); 562 return _dispatch(_FILE_READ_BYTE, [_id]).then((response) {
567 return _IOService.dispatch(_FILE_READ_BYTE, [_id]).then((response) {
568 if (_isErrorResponse(response)) { 563 if (_isErrorResponse(response)) {
569 throw _exceptionFromResponse(response, "readByte failed", path); 564 throw _exceptionFromResponse(response, "readByte failed", path);
570 } 565 }
571 return response; 566 return response;
572 }); 567 });
573 } 568 }
574 569
575 external static _readByte(int id); 570 external static _readByte(int id);
576 571
577 int readByteSync() { 572 int readByteSync() {
578 _checkNotClosed(); 573 _checkAvailable();
579 var result = _readByte(_id); 574 var result = _readByte(_id);
580 if (result is OSError) { 575 if (result is OSError) {
581 throw new FileException("readByte failed", path, result); 576 throw new FileException("readByte failed", path, result);
582 } 577 }
583 return result; 578 return result;
584 } 579 }
585 580
586 Future<List<int>> read(int bytes) { 581 Future<List<int>> read(int bytes) {
587 if (bytes is !int) { 582 if (bytes is !int) {
588 throw new ArgumentError(bytes); 583 throw new ArgumentError(bytes);
589 } 584 }
590 if (closed) return _closedException(); 585 return _dispatch(_FILE_READ, [_id, bytes]).then((response) {
591 return _IOService.dispatch(_FILE_READ, [_id, bytes]).then((response) {
592 if (_isErrorResponse(response)) { 586 if (_isErrorResponse(response)) {
593 throw _exceptionFromResponse(response, "read failed", path); 587 throw _exceptionFromResponse(response, "read failed", path);
594 } 588 }
595 return response[1]; 589 return response[1];
596 }); 590 });
597 } 591 }
598 592
599 external static _read(int id, int bytes); 593 external static _read(int id, int bytes);
600 594
601 List<int> readSync(int bytes) { 595 List<int> readSync(int bytes) {
602 _checkNotClosed(); 596 _checkAvailable();
603 if (bytes is !int) { 597 if (bytes is !int) {
604 throw new ArgumentError(bytes); 598 throw new ArgumentError(bytes);
605 } 599 }
606 var result = _read(_id, bytes); 600 var result = _read(_id, bytes);
607 if (result is OSError) { 601 if (result is OSError) {
608 throw new FileException("readSync failed", path, result); 602 throw new FileException("readSync failed", path, result);
609 } 603 }
610 return result; 604 return result;
611 } 605 }
612 606
613 Future<int> readInto(List<int> buffer, [int start, int end]) { 607 Future<int> readInto(List<int> buffer, [int start, int end]) {
614 if (buffer is !List || 608 if (buffer is !List ||
615 (start != null && start is !int) || 609 (start != null && start is !int) ||
616 (end != null && end is !int)) { 610 (end != null && end is !int)) {
617 throw new ArgumentError(); 611 throw new ArgumentError();
618 } 612 }
619 if (closed) return _closedException();
620 if (start == null) start = 0; 613 if (start == null) start = 0;
621 if (end == null) end = buffer.length; 614 if (end == null) end = buffer.length;
622 int length = end - start; 615 int length = end - start;
623 return _IOService.dispatch(_FILE_READ_INTO, [_id, length]).then((response) { 616 return _dispatch(_FILE_READ_INTO, [_id, length]).then((response) {
624 if (_isErrorResponse(response)) { 617 if (_isErrorResponse(response)) {
625 throw _exceptionFromResponse(response, "readInto failed", path); 618 throw _exceptionFromResponse(response, "readInto failed", path);
626 } 619 }
627 var read = response[1]; 620 var read = response[1];
628 var data = response[2]; 621 var data = response[2];
629 buffer.setRange(start, start + read, data); 622 buffer.setRange(start, start + read, data);
630 return read; 623 return read;
631 }); 624 });
632 } 625 }
633 626
634 static void _checkReadWriteListArguments(int length, int start, int end) { 627 static void _checkReadWriteListArguments(int length, int start, int end) {
635 if (start < 0) throw new RangeError.value(start); 628 if (start < 0) throw new RangeError.value(start);
636 if (end < start) throw new RangeError.value(end); 629 if (end < start) throw new RangeError.value(end);
637 if (end > length) { 630 if (end > length) {
638 throw new RangeError.value(end); 631 throw new RangeError.value(end);
639 } 632 }
640 } 633 }
641 634
642 external static _readInto(int id, List<int> buffer, int start, int end); 635 external static _readInto(int id, List<int> buffer, int start, int end);
643 636
644 int readIntoSync(List<int> buffer, [int start, int end]) { 637 int readIntoSync(List<int> buffer, [int start, int end]) {
645 _checkNotClosed(); 638 _checkAvailable();
646 if (buffer is !List || 639 if (buffer is !List ||
647 (start != null && start is !int) || 640 (start != null && start is !int) ||
648 (end != null && end is !int)) { 641 (end != null && end is !int)) {
649 throw new ArgumentError(); 642 throw new ArgumentError();
650 } 643 }
651 if (start == null) start = 0; 644 if (start == null) start = 0;
652 if (end == null) end = buffer.length; 645 if (end == null) end = buffer.length;
653 if (end == start) return 0; 646 if (end == start) return 0;
654 _checkReadWriteListArguments(buffer.length, start, end); 647 _checkReadWriteListArguments(buffer.length, start, end);
655 var result = _readInto(_id, buffer, start, end); 648 var result = _readInto(_id, buffer, start, end);
656 if (result is OSError) { 649 if (result is OSError) {
657 throw new FileException("readInto failed", path, result); 650 throw new FileException("readInto failed", path, result);
658 } 651 }
659 return result; 652 return result;
660 } 653 }
661 654
662 Future<RandomAccessFile> writeByte(int value) { 655 Future<RandomAccessFile> writeByte(int value) {
663 if (value is !int) { 656 if (value is !int) {
664 throw new ArgumentError(value); 657 throw new ArgumentError(value);
665 } 658 }
666 if (closed) return _closedException(); 659 return _dispatch(_FILE_WRITE_BYTE, [_id, value]).then((response) {
667 return _IOService.dispatch(_FILE_WRITE_BYTE, [_id, value]).then((response) {
668 if (_isErrorResponse(response)) { 660 if (_isErrorResponse(response)) {
669 throw _exceptionFromResponse(response, "writeByte failed", path); 661 throw _exceptionFromResponse(response, "writeByte failed", path);
670 } 662 }
671 return this; 663 return this;
672 }); 664 });
673 } 665 }
674 666
675 external static _writeByte(int id, int value); 667 external static _writeByte(int id, int value);
676 668
677 int writeByteSync(int value) { 669 int writeByteSync(int value) {
678 _checkNotClosed(); 670 _checkAvailable();
679 if (value is !int) { 671 if (value is !int) {
680 throw new ArgumentError(value); 672 throw new ArgumentError(value);
681 } 673 }
682 var result = _writeByte(_id, value); 674 var result = _writeByte(_id, value);
683 if (result is OSError) { 675 if (result is OSError) {
684 throw new FileException("writeByte failed", path, result); 676 throw new FileException("writeByte failed", path, result);
685 } 677 }
686 return result; 678 return result;
687 } 679 }
688 680
689 Future<RandomAccessFile> writeFrom(List<int> buffer, [int start, int end]) { 681 Future<RandomAccessFile> writeFrom(List<int> buffer, [int start, int end]) {
690 if ((buffer is !List && buffer is !ByteData) || 682 if ((buffer is !List && buffer is !ByteData) ||
691 (start != null && start is !int) || 683 (start != null && start is !int) ||
692 (end != null && end is !int)) { 684 (end != null && end is !int)) {
693 throw new ArgumentError("Invalid arguments to writeFrom"); 685 throw new ArgumentError("Invalid arguments to writeFrom");
694 } 686 }
695 687
696 if (closed) return _closedException();
697
698 _BufferAndStart result; 688 _BufferAndStart result;
699 try { 689 try {
700 result = _ensureFastAndSerializableByteData(buffer, start, end); 690 result = _ensureFastAndSerializableByteData(buffer, start, end);
701 } catch (e) { 691 } catch (e) {
702 return new Future.error(e); 692 return new Future.error(e);
703 } 693 }
704 694
705 List request = new List(4); 695 List request = new List(4);
706 request[0] = _id; 696 request[0] = _id;
707 request[1] = result.buffer; 697 request[1] = result.buffer;
708 request[2] = result.start; 698 request[2] = result.start;
709 request[3] = end - (start - result.start); 699 request[3] = end - (start - result.start);
710 return _IOService.dispatch(_FILE_WRITE_FROM, request).then((response) { 700 return _dispatch(_FILE_WRITE_FROM, request).then((response) {
711 if (_isErrorResponse(response)) { 701 if (_isErrorResponse(response)) {
712 throw _exceptionFromResponse(response, "writeFrom failed", path); 702 throw _exceptionFromResponse(response, "writeFrom failed", path);
713 } 703 }
714 return this; 704 return this;
715 }); 705 });
716 } 706 }
717 707
718 external static _writeFrom(int id, List<int> buffer, int start, int end); 708 external static _writeFrom(int id, List<int> buffer, int start, int end);
719 709
720 void writeFromSync(List<int> buffer, [int start, int end]) { 710 void writeFromSync(List<int> buffer, [int start, int end]) {
721 _checkNotClosed(); 711 _checkAvailable();
722 if (buffer is !List || 712 if (buffer is !List ||
723 (start != null && start is !int) || 713 (start != null && start is !int) ||
724 (end != null && end is !int)) { 714 (end != null && end is !int)) {
725 throw new ArgumentError("Invalid arguments to writeFromSync"); 715 throw new ArgumentError("Invalid arguments to writeFromSync");
726 } 716 }
727 if (start == null) start = 0; 717 if (start == null) start = 0;
728 if (end == null) end = buffer.length; 718 if (end == null) end = buffer.length;
729 if (end == start) return; 719 if (end == start) return;
730 _checkReadWriteListArguments(buffer.length, start, end); 720 _checkReadWriteListArguments(buffer.length, start, end);
731 _BufferAndStart bufferAndStart = 721 _BufferAndStart bufferAndStart =
(...skipping 18 matching lines...) Expand all
750 740
751 void writeStringSync(String string, {Encoding encoding: UTF8}) { 741 void writeStringSync(String string, {Encoding encoding: UTF8}) {
752 if (encoding is! Encoding) { 742 if (encoding is! Encoding) {
753 throw new ArgumentError(encoding); 743 throw new ArgumentError(encoding);
754 } 744 }
755 var data = encoding.encode(string); 745 var data = encoding.encode(string);
756 writeFromSync(data, 0, data.length); 746 writeFromSync(data, 0, data.length);
757 } 747 }
758 748
759 Future<int> position() { 749 Future<int> position() {
760 if (closed) return _closedException(); 750 return _dispatch(_FILE_POSITION, [_id]).then((response) {
761 return _IOService.dispatch(_FILE_POSITION, [_id]).then((response) {
762 if (_isErrorResponse(response)) { 751 if (_isErrorResponse(response)) {
763 throw _exceptionFromResponse(response, "position failed", path); 752 throw _exceptionFromResponse(response, "position failed", path);
764 } 753 }
765 return response; 754 return response;
766 }); 755 });
767 } 756 }
768 757
769 external static _position(int id); 758 external static _position(int id);
770 759
771 int positionSync() { 760 int positionSync() {
772 _checkNotClosed(); 761 _checkAvailable();
773 var result = _position(_id); 762 var result = _position(_id);
774 if (result is OSError) { 763 if (result is OSError) {
775 throw new FileException("position failed", path, result); 764 throw new FileException("position failed", path, result);
776 } 765 }
777 return result; 766 return result;
778 } 767 }
779 768
780 Future<RandomAccessFile> setPosition(int position) { 769 Future<RandomAccessFile> setPosition(int position) {
781 if (closed) return _closedException(); 770 return _dispatch(_FILE_SET_POSITION, [_id, position])
782 return _IOService.dispatch(_FILE_SET_POSITION, [_id, position])
783 .then((response) { 771 .then((response) {
784 if (_isErrorResponse(response)) { 772 if (_isErrorResponse(response)) {
785 throw _exceptionFromResponse(response, "setPosition failed", path); 773 throw _exceptionFromResponse(response, "setPosition failed", path);
786 } 774 }
787 return this; 775 return this;
788 }); 776 });
789 } 777 }
790 778
791 external static _setPosition(int id, int position); 779 external static _setPosition(int id, int position);
792 780
793 void setPositionSync(int position) { 781 void setPositionSync(int position) {
794 _checkNotClosed(); 782 _checkAvailable();
795 var result = _setPosition(_id, position); 783 var result = _setPosition(_id, position);
796 if (result is OSError) { 784 if (result is OSError) {
797 throw new FileException("setPosition failed", path, result); 785 throw new FileException("setPosition failed", path, result);
798 } 786 }
799 } 787 }
800 788
801 Future<RandomAccessFile> truncate(int length) { 789 Future<RandomAccessFile> truncate(int length) {
802 if (closed) return _closedException(); 790 return _dispatch(_FILE_TRUNCATE, [_id, length]).then((response) {
803 return _IOService.dispatch(_FILE_TRUNCATE, [_id, length]).then((response) {
804 if (_isErrorResponse(response)) { 791 if (_isErrorResponse(response)) {
805 throw _exceptionFromResponse(response, "truncate failed", path); 792 throw _exceptionFromResponse(response, "truncate failed", path);
806 } 793 }
807 return this; 794 return this;
808 }); 795 });
809 } 796 }
810 797
811 external static _truncate(int id, int length); 798 external static _truncate(int id, int length);
812 799
813 void truncateSync(int length) { 800 void truncateSync(int length) {
814 _checkNotClosed(); 801 _checkAvailable();
815 var result = _truncate(_id, length); 802 var result = _truncate(_id, length);
816 if (result is OSError) { 803 if (result is OSError) {
817 throw new FileException("truncate failed", path, result); 804 throw new FileException("truncate failed", path, result);
818 } 805 }
819 } 806 }
820 807
821 Future<int> length() { 808 Future<int> length() {
822 if (closed) return _closedException(); 809 return _dispatch(_FILE_LENGTH, [_id]).then((response) {
823 return _IOService.dispatch(_FILE_LENGTH, [_id]).then((response) {
824 if (_isErrorResponse(response)) { 810 if (_isErrorResponse(response)) {
825 throw _exceptionFromResponse(response, "length failed", path); 811 throw _exceptionFromResponse(response, "length failed", path);
826 } 812 }
827 return response; 813 return response;
828 }); 814 });
829 } 815 }
830 816
831 external static _length(int id); 817 external static _length(int id);
832 818
833 int lengthSync() { 819 int lengthSync() {
834 _checkNotClosed(); 820 _checkAvailable();
835 var result = _length(_id); 821 var result = _length(_id);
836 if (result is OSError) { 822 if (result is OSError) {
837 throw new FileException("length failed", path, result); 823 throw new FileException("length failed", path, result);
838 } 824 }
839 return result; 825 return result;
840 } 826 }
841 827
842 Future<RandomAccessFile> flush() { 828 Future<RandomAccessFile> flush() {
843 if (closed) return _closedException(); 829 return _dispatch(_FILE_FLUSH, [_id]).then((response) {
844 return _IOService.dispatch(_FILE_FLUSH, [_id]).then((response) {
845 if (_isErrorResponse(response)) { 830 if (_isErrorResponse(response)) {
846 throw _exceptionFromResponse(response, 831 throw _exceptionFromResponse(response,
847 "flush failed", 832 "flush failed",
848 path); 833 path);
849 } 834 }
850 return this; 835 return this;
851 }); 836 });
852 } 837 }
853 838
854 external static _flush(int id); 839 external static _flush(int id);
855 840
856 void flushSync() { 841 void flushSync() {
857 _checkNotClosed(); 842 _checkAvailable();
858 var result = _flush(_id); 843 var result = _flush(_id);
859 if (result is OSError) { 844 if (result is OSError) {
860 throw new FileException("flush failed", path, result); 845 throw new FileException("flush failed", path, result);
861 } 846 }
862 } 847 }
863 848
864 bool get closed => _id == 0; 849 bool get closed => _id == 0;
865 850
866 void _checkNotClosed() { 851 Future _dispatch(int request, List data, { bool markClosed: false }) {
852 if (closed) {
853 return new Future.error(new FileException("File closed", path));
854 }
855 if (_asyncDispatched) {
856 var msg = "An async operation is currently pending";
857 return new Future.error(new FileException(msg, path));
858 }
859 if (markClosed) {
860 // Set the id_ to 0 (NULL) to ensure the no more async requests
861 // can be issued for this file.
862 _id = 0;
863 }
864 _asyncDispatched = true;
865 return _IOService.dispatch(request, data)
866 .whenComplete(() {
867 _asyncDispatched = false;
868 });
869 }
870
871 void _checkAvailable() {
872 if (_asyncDispatched) {
873 throw new FileException("An async operation is currently pending", path);
874 }
867 if (closed) { 875 if (closed) {
868 throw new FileException("File closed", path); 876 throw new FileException("File closed", path);
869 } 877 }
870 } 878 }
871
872 Future _closedException() {
873 return new Future.error(new FileException("File closed", path));
874 }
875 } 879 }
OLDNEW
« no previous file with comments | « no previous file | tests/standalone/io/file_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698