This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 32439
Collapse All | Expand All

(-)openide/test/unit/src/org/openide/util/MutexTest.java (-6 / +490 lines)
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
}

Return to bug 32439