Lines 13-24
Link Here
|
13 |
|
13 |
|
14 |
package org.openide.util; |
14 |
package org.openide.util; |
15 |
|
15 |
|
|
|
16 |
import java.awt.EventQueue; |
17 |
import java.io.IOException; |
16 |
import java.lang.ref.*; |
18 |
import java.lang.ref.*; |
17 |
import java.util.*; |
19 |
import java.util.*; |
18 |
import org.openide.ErrorManager; |
20 |
import org.openide.ErrorManager; |
19 |
import junit.framework.*; |
21 |
import junit.framework.*; |
20 |
import org.netbeans.junit.*; |
22 |
import org.netbeans.junit.*; |
21 |
|
23 |
|
|
|
24 |
/** |
25 |
* Test behavior of the read-write mutex. |
26 |
* @author Jaroslav Tulach, Ales Novak, Petr Hrebejk, Jesse Glick |
27 |
*/ |
22 |
public class MutexTest extends NbTestCase { |
28 |
public class MutexTest extends NbTestCase { |
23 |
private Mutex.Privileged p; |
29 |
private Mutex.Privileged p; |
24 |
private Mutex m; |
30 |
private Mutex m; |
Lines 133-139
Link Here
|
133 |
|
139 |
|
134 |
/** Behaviour of postReadRequest is defined by this test. |
140 |
/** Behaviour of postReadRequest is defined by this test. |
135 |
*/ |
141 |
*/ |
136 |
public void testPostReadRequest () { |
142 |
// Cannot go S -> X |
|
|
143 |
public void DONOTtestPostReadRequest () { |
137 |
|
144 |
|
138 |
State s = new State (); |
145 |
State s = new State (); |
139 |
|
146 |
|
Lines 162-168
Link Here
|
162 |
} |
169 |
} |
163 |
|
170 |
|
164 |
/** Test enter from S mode to X mode */ |
171 |
/** Test enter from S mode to X mode */ |
165 |
public void testXtoS() { |
172 |
// You cannot go from S -> X |
|
|
173 |
public void DONOTtestXtoS() { |
166 |
State s = new State (); |
174 |
State s = new State (); |
167 |
|
175 |
|
168 |
p.enterReadAccess (); |
176 |
p.enterReadAccess (); |
Lines 193-212
Link Here
|
193 |
|
201 |
|
194 |
m.postReadRequest(s); |
202 |
m.postReadRequest(s); |
195 |
|
203 |
|
196 |
if (s.state != 0) { |
204 |
if (s.state != 1) { |
197 |
fail ("Read request started when we are in write access"); |
205 |
fail ("Read request not run when we are in read access inside write access"); |
198 |
} |
206 |
} |
199 |
|
207 |
|
200 |
p.exitReadAccess (); |
208 |
p.exitReadAccess (); |
201 |
|
209 |
|
202 |
if (s.state != 1) { |
210 |
if (s.state != 2) { |
203 |
fail ("Write request not run when leaving read access: " + s.state); |
211 |
fail ("Write request not run when leaving read access: " + s.state); |
204 |
} |
212 |
} |
205 |
|
213 |
|
|
|
214 |
m.postReadRequest(s); |
215 |
|
216 |
if (s.state != 2) { |
217 |
fail ("Read request started when we are in write access"); |
218 |
} |
219 |
|
206 |
// exiting |
220 |
// exiting |
207 |
p.exitWriteAccess (); |
221 |
p.exitWriteAccess (); |
208 |
|
222 |
|
209 |
if (s.state != 2) { |
223 |
if (s.state != 3) { |
210 |
fail ("Read request not run when leaving write access: " + s.state); |
224 |
fail ("Read request not run when leaving write access: " + s.state); |
211 |
} |
225 |
} |
212 |
|
226 |
|
Lines 540-543
Link Here
|
540 |
} |
554 |
} |
541 |
|
555 |
|
542 |
} // end of State |
556 |
} // end of State |
|
|
557 |
|
558 |
// --- TESTS ADDED BY JGLICK --- |
559 |
|
560 |
public void testEventAccess() throws Exception { |
561 |
assertTrue("Not starting in AWT", !EventQueue.isDispatchThread()); |
562 |
// test canRead, canWrite, correct thread used by synch methods |
563 |
assertTrue(!Mutex.EVENT.canRead()); |
564 |
assertTrue(!Mutex.EVENT.canWrite()); |
565 |
assertEquals(Boolean.TRUE, Mutex.EVENT.readAccess(new Mutex.Action() { |
566 |
public Object run() { |
567 |
return new Boolean(EventQueue.isDispatchThread() && |
568 |
Mutex.EVENT.canRead() && |
569 |
Mutex.EVENT.canWrite()); |
570 |
} |
571 |
})); |
572 |
assertEquals(Boolean.TRUE, Mutex.EVENT.readAccess(new Mutex.ExceptionAction() { |
573 |
public Object run() throws Exception { |
574 |
return new Boolean(EventQueue.isDispatchThread() && |
575 |
Mutex.EVENT.canRead() && |
576 |
Mutex.EVENT.canWrite()); |
577 |
} |
578 |
})); |
579 |
assertEquals(Boolean.TRUE, Mutex.EVENT.writeAccess(new Mutex.Action() { |
580 |
public Object run() { |
581 |
return new Boolean(EventQueue.isDispatchThread() && |
582 |
Mutex.EVENT.canRead() && |
583 |
Mutex.EVENT.canWrite()); |
584 |
} |
585 |
})); |
586 |
assertEquals(Boolean.TRUE, Mutex.EVENT.writeAccess(new Mutex.ExceptionAction() { |
587 |
public Object run() throws Exception { |
588 |
return new Boolean(EventQueue.isDispatchThread() && |
589 |
Mutex.EVENT.canRead() && |
590 |
Mutex.EVENT.canWrite()); |
591 |
} |
592 |
})); |
593 |
// test that r/wA(Runnable) runs in AWT eventually |
594 |
final boolean[] b = new boolean[1]; |
595 |
// first, that r/wA will run (even asynch) |
596 |
Mutex.EVENT.readAccess(new Runnable() { |
597 |
public void run() { |
598 |
synchronized (b) { |
599 |
b[0] = EventQueue.isDispatchThread(); |
600 |
b.notify(); |
601 |
} |
602 |
} |
603 |
}); |
604 |
synchronized (b) { |
605 |
if (!b[0]) b.wait(9999); |
606 |
} |
607 |
assertTrue(b[0]); |
608 |
Mutex.EVENT.writeAccess(new Runnable() { |
609 |
public void run() { |
610 |
synchronized (b) { |
611 |
b[0] = !EventQueue.isDispatchThread(); |
612 |
b.notify(); |
613 |
} |
614 |
} |
615 |
}); |
616 |
synchronized (b) { |
617 |
if (b[0]) b.wait(9999); |
618 |
} |
619 |
assertTrue(!b[0]); |
620 |
// now that r/wA runs synch in event thread |
621 |
EventQueue.invokeAndWait(new Runnable() { |
622 |
public void run() { |
623 |
Mutex.EVENT.readAccess(new Runnable() { |
624 |
public void run() { |
625 |
b[0] = EventQueue.isDispatchThread(); |
626 |
} |
627 |
}); |
628 |
} |
629 |
}); |
630 |
assertTrue(b[0]); |
631 |
EventQueue.invokeAndWait(new Runnable() { |
632 |
public void run() { |
633 |
Mutex.EVENT.writeAccess(new Runnable() { |
634 |
public void run() { |
635 |
b[0] = !EventQueue.isDispatchThread(); |
636 |
} |
637 |
}); |
638 |
} |
639 |
}); |
640 |
// and that pR/WR runs synch outside AWT |
641 |
assertTrue(!b[0]); |
642 |
Mutex.EVENT.postReadRequest(new Runnable() { |
643 |
public void run() { |
644 |
b[0] = EventQueue.isDispatchThread(); |
645 |
} |
646 |
}); |
647 |
assertTrue(b[0]); |
648 |
Mutex.EVENT.postWriteRequest(new Runnable() { |
649 |
public void run() { |
650 |
b[0] = !EventQueue.isDispatchThread(); |
651 |
} |
652 |
}); |
653 |
assertTrue(!b[0]); |
654 |
} |
655 |
|
656 |
public void testEventExceptions() throws Exception { |
657 |
assertTrue("Not starting in AWT", !EventQueue.isDispatchThread()); |
658 |
// test that checked excs from M.EA throw correct ME |
659 |
try { |
660 |
Mutex.EVENT.readAccess(new Mutex.ExceptionAction() { |
661 |
public Object run() throws Exception { |
662 |
throw new IOException(); |
663 |
} |
664 |
}); |
665 |
fail(); |
666 |
} catch (MutexException e) { |
667 |
assertEquals(IOException.class, e.getException().getClass()); |
668 |
} |
669 |
// but that unchecked excs are passed thru |
670 |
try { |
671 |
Mutex.EVENT.readAccess(new Mutex.ExceptionAction() { |
672 |
public Object run() throws Exception { |
673 |
throw new IllegalArgumentException(); |
674 |
} |
675 |
}); |
676 |
fail(); |
677 |
} catch (IllegalArgumentException e) { |
678 |
// OK |
679 |
} catch (Exception e) { |
680 |
fail(e.toString()); |
681 |
} |
682 |
// similarly for unchecked excs from M.A |
683 |
try { |
684 |
Mutex.EVENT.readAccess(new Mutex.Action() { |
685 |
public Object run() { |
686 |
throw new IllegalArgumentException(); |
687 |
} |
688 |
}); |
689 |
fail(); |
690 |
} catch (IllegalArgumentException e) { |
691 |
// OK |
692 |
} catch (RuntimeException e) { |
693 |
fail(e.toString()); |
694 |
} |
695 |
// and blocking runnables |
696 |
try { |
697 |
Mutex.EVENT.postReadRequest(new Runnable() { |
698 |
public void run() { |
699 |
throw new IllegalArgumentException(); |
700 |
} |
701 |
}); |
702 |
fail(); |
703 |
} catch (IllegalArgumentException e) { |
704 |
// OK. |
705 |
} |
706 |
try { |
707 |
Mutex.EVENT.postWriteRequest(new Runnable() { |
708 |
public void run() { |
709 |
throw new IllegalArgumentException(); |
710 |
} |
711 |
}); |
712 |
fail(); |
713 |
} catch (IllegalArgumentException e) { |
714 |
// OK. |
715 |
} |
716 |
} |
717 |
|
718 |
public void testLockOrdering() throws Exception { |
719 |
Mutex.Privileged p1 = new Mutex.Privileged(); |
720 |
Mutex m1 = new Mutex("one", p1, 1); |
721 |
Mutex.Privileged p2 = new Mutex.Privileged(); |
722 |
Mutex m2 = new Mutex("two", p2, 2); |
723 |
Mutex.Privileged p2a = new Mutex.Privileged(); |
724 |
Mutex m2a = new Mutex("two-a", p2a, 2); |
725 |
Mutex.Privileged px = new Mutex.Privileged(); |
726 |
Mutex mx = new Mutex(px); |
727 |
Mutex.Privileged pxa = new Mutex.Privileged(); |
728 |
Mutex mxa = new Mutex(pxa); |
729 |
// test that higher -> lower is OK, and can entered unordered too |
730 |
m2.enterReadAccess(); |
731 |
try { |
732 |
m1.enterReadAccess(); |
733 |
try { |
734 |
mx.enterReadAccess(); |
735 |
mx.exitReadAccess(); |
736 |
} finally { |
737 |
m1.exitReadAccess(); |
738 |
} |
739 |
} finally { |
740 |
m2.exitReadAccess(); |
741 |
} |
742 |
// check that lower -> higher is blocked |
743 |
m1.enterReadAccess(); |
744 |
try { |
745 |
boolean ok = true; |
746 |
try { |
747 |
m2.enterReadAccess(); |
748 |
ok = false; |
749 |
m2.exitReadAccess(); |
750 |
fail(); |
751 |
} catch (IllegalStateException e) { |
752 |
assertTrue(ok); |
753 |
} |
754 |
mx.enterReadAccess(); |
755 |
mx.exitReadAccess(); |
756 |
} finally { |
757 |
m1.exitReadAccess(); |
758 |
} |
759 |
// check that from unordered, can enter anything |
760 |
mx.enterReadAccess(); |
761 |
try { |
762 |
m1.enterReadAccess(); |
763 |
m1.exitReadAccess(); |
764 |
m2.enterReadAccess(); |
765 |
m2.exitReadAccess(); |
766 |
} finally { |
767 |
mx.exitReadAccess(); |
768 |
} |
769 |
// even higher -> lower -> higher is blocked |
770 |
m2.enterReadAccess(); |
771 |
try { |
772 |
m1.enterReadAccess(); |
773 |
try { |
774 |
boolean ok = true; |
775 |
try { |
776 |
m2.enterReadAccess(); |
777 |
ok = false; |
778 |
m2.exitReadAccess(); |
779 |
fail(); |
780 |
} catch (IllegalStateException e) { |
781 |
assertTrue(ok); |
782 |
} |
783 |
} finally { |
784 |
m1.exitReadAccess(); |
785 |
} |
786 |
} finally { |
787 |
m2.exitReadAccess(); |
788 |
} |
789 |
// high -> equiv. is blocked too |
790 |
m2.enterReadAccess(); |
791 |
try { |
792 |
boolean ok = true; |
793 |
try { |
794 |
m2a.enterReadAccess(); |
795 |
ok = false; |
796 |
m2a.exitReadAccess(); |
797 |
fail(); |
798 |
} catch (IllegalStateException e) { |
799 |
assertTrue(ok); |
800 |
} |
801 |
} finally { |
802 |
m2.exitReadAccess(); |
803 |
} |
804 |
// but can reenter yourself |
805 |
m2.enterReadAccess(); |
806 |
try { |
807 |
m2.enterReadAccess(); |
808 |
m2.exitReadAccess(); |
809 |
} finally { |
810 |
m2.exitReadAccess(); |
811 |
} |
812 |
// undef level mutexes do not block transitions |
813 |
mx.enterReadAccess(); |
814 |
try { |
815 |
mxa.enterReadAccess(); |
816 |
mxa.exitReadAccess(); |
817 |
} finally { |
818 |
mx.exitReadAccess(); |
819 |
} |
820 |
// higher -> lower is OK in W/R, R/W, and W/W combos too |
821 |
m2.enterWriteAccess(); |
822 |
try { |
823 |
m1.enterReadAccess(); |
824 |
m1.exitReadAccess(); |
825 |
} finally { |
826 |
m2.exitWriteAccess(); |
827 |
} |
828 |
m2.enterReadAccess(); |
829 |
try { |
830 |
m1.enterWriteAccess(); |
831 |
m1.exitWriteAccess(); |
832 |
} finally { |
833 |
m2.exitReadAccess(); |
834 |
} |
835 |
m2.enterWriteAccess(); |
836 |
try { |
837 |
m1.enterWriteAccess(); |
838 |
m1.exitWriteAccess(); |
839 |
} finally { |
840 |
m2.exitWriteAccess(); |
841 |
} |
842 |
} |
843 |
|
844 |
public void testEventOrdering() throws Exception { |
845 |
Mutex.Privileged p0 = new Mutex.Privileged(); |
846 |
final Mutex m0 = new Mutex("zero", p0, 0); |
847 |
Mutex.Privileged px = new Mutex.Privileged(); |
848 |
final Mutex mx = new Mutex(px); |
849 |
// can go EVENT -> ordered |
850 |
Mutex.EVENT.postReadRequest(new Runnable() { |
851 |
public void run() { |
852 |
m0.enterReadAccess(); |
853 |
m0.exitReadAccess(); |
854 |
} |
855 |
}); |
856 |
// but not ordered -> EVENT |
857 |
m0.enterReadAccess(); |
858 |
try { |
859 |
try { |
860 |
Mutex.EVENT.postReadRequest(new Runnable() { |
861 |
public void run() { |
862 |
fail(); |
863 |
} |
864 |
}); |
865 |
} catch (IllegalStateException e) { |
866 |
// OK. |
867 |
} |
868 |
} finally { |
869 |
m0.exitReadAccess(); |
870 |
} |
871 |
// however EVENT -> unordered is OK |
872 |
Mutex.EVENT.postReadRequest(new Runnable() { |
873 |
public void run() { |
874 |
mx.enterReadAccess(); |
875 |
mx.exitReadAccess(); |
876 |
} |
877 |
}); |
878 |
// as is unordered -> EVENT |
879 |
mx.enterReadAccess(); |
880 |
try { |
881 |
final boolean[] b = new boolean[1]; |
882 |
Mutex.EVENT.postReadRequest(new Runnable() { |
883 |
public void run() { |
884 |
b[0] = true; |
885 |
} |
886 |
}); |
887 |
assertTrue(b[0]); |
888 |
} finally { |
889 |
mx.exitReadAccess(); |
890 |
} |
891 |
} |
892 |
|
893 |
public void testMisorderedMutexes() throws Exception { |
894 |
Mutex.Privileged p1 = new Mutex.Privileged(); |
895 |
Mutex m1 = new Mutex("one", p1, 1); |
896 |
Mutex.Privileged p2 = new Mutex.Privileged(); |
897 |
Mutex m2 = new Mutex("two", p2, 2); |
898 |
// Cannot exit wrong read access when ordered |
899 |
m2.enterReadAccess(); |
900 |
try { |
901 |
m1.enterReadAccess(); |
902 |
try { |
903 |
m2.exitReadAccess(); |
904 |
fail(); |
905 |
} catch (IllegalStateException e) { |
906 |
// OK. |
907 |
} finally { |
908 |
m1.exitReadAccess(); |
909 |
} |
910 |
} finally { |
911 |
try { |
912 |
m2.exitReadAccess(); |
913 |
} catch (IllegalStateException e) { |
914 |
fail(); |
915 |
} |
916 |
} |
917 |
// but for compatibility, unordered mutexes can be intermixed |
918 |
Mutex.Privileged px1 = new Mutex.Privileged(); |
919 |
Mutex mx1 = new Mutex(px1); |
920 |
Mutex.Privileged px2 = new Mutex.Privileged(); |
921 |
Mutex mx2 = new Mutex(px2); |
922 |
boolean exited2 = false; |
923 |
mx2.enterReadAccess(); |
924 |
try { |
925 |
mx1.enterReadAccess(); |
926 |
mx2.exitReadAccess(); |
927 |
exited2 = true; |
928 |
} finally { |
929 |
mx1.exitReadAccess(); |
930 |
if (!exited2) { |
931 |
// in case test fails, still clean up |
932 |
mx2.exitReadAccess(); |
933 |
} |
934 |
} |
935 |
} |
936 |
|
937 |
public void testNestedEntries() throws Exception { |
938 |
Mutex.Privileged p = new Mutex.Privileged(); |
939 |
Mutex m = new Mutex(p); |
940 |
// can go write -> read |
941 |
m.enterWriteAccess(); |
942 |
try { |
943 |
m.enterReadAccess(); |
944 |
m.exitReadAccess(); |
945 |
} finally { |
946 |
m.exitWriteAccess(); |
947 |
} |
948 |
// and write -> write -> read |
949 |
m.enterWriteAccess(); |
950 |
try { |
951 |
m.enterWriteAccess(); |
952 |
try { |
953 |
m.enterReadAccess(); |
954 |
m.exitReadAccess(); |
955 |
} finally { |
956 |
m.exitWriteAccess(); |
957 |
} |
958 |
} finally { |
959 |
m.exitWriteAccess(); |
960 |
} |
961 |
// and write -> read -> read |
962 |
m.enterWriteAccess(); |
963 |
try { |
964 |
m.enterReadAccess(); |
965 |
try { |
966 |
m.enterReadAccess(); |
967 |
m.exitReadAccess(); |
968 |
} finally { |
969 |
m.exitReadAccess(); |
970 |
} |
971 |
} finally { |
972 |
m.exitWriteAccess(); |
973 |
} |
974 |
// and even write -> write -> read -> read |
975 |
m.enterWriteAccess(); |
976 |
try { |
977 |
m.enterWriteAccess(); |
978 |
try { |
979 |
m.enterReadAccess(); |
980 |
try { |
981 |
m.enterReadAccess(); |
982 |
m.exitReadAccess(); |
983 |
} finally { |
984 |
m.exitReadAccess(); |
985 |
} |
986 |
} finally { |
987 |
m.exitWriteAccess(); |
988 |
} |
989 |
} finally { |
990 |
m.exitWriteAccess(); |
991 |
} |
992 |
// but read -> write is forbidden |
993 |
m.enterReadAccess(); |
994 |
try { |
995 |
boolean ok = true; |
996 |
try { |
997 |
m.enterWriteAccess(); |
998 |
ok = false; |
999 |
m.exitWriteAccess(); |
1000 |
} catch (IllegalStateException e) { |
1001 |
assertTrue(ok); |
1002 |
} |
1003 |
} finally { |
1004 |
m.exitReadAccess(); |
1005 |
} |
1006 |
// so is write -> read -> write! |
1007 |
m.enterWriteAccess(); |
1008 |
try { |
1009 |
m.enterReadAccess(); |
1010 |
try { |
1011 |
boolean ok = true; |
1012 |
try { |
1013 |
m.enterWriteAccess(); |
1014 |
ok = false; |
1015 |
m.exitWriteAccess(); |
1016 |
} catch (IllegalStateException e) { |
1017 |
assertTrue(ok); |
1018 |
} |
1019 |
} finally { |
1020 |
m.exitReadAccess(); |
1021 |
} |
1022 |
} finally { |
1023 |
m.exitWriteAccess(); |
1024 |
} |
1025 |
} |
1026 |
|
543 |
} |
1027 |
} |