1 19 20 package org.openide.util; 21 22 import java.io.IOException ; 23 import java.lang.ref.*; 24 import java.lang.reflect.InvocationTargetException ; 25 import java.util.*; 26 import java.util.concurrent.atomic.AtomicBoolean ; 27 import java.util.logging.Level ; 28 import java.util.logging.Logger ; 29 import junit.framework.*; 30 import org.netbeans.junit.*; 31 32 public class MutexTest extends NbTestCase { 33 Mutex.Privileged p; 34 Mutex m; 35 36 37 38 public MutexTest(java.lang.String testName) { 39 super(testName); 40 } 41 42 public static void main(java.lang.String [] args) { 43 junit.textui.TestRunner.run(suite()); 44 } 45 46 public static Test suite() { 47 NbTestSuite suite = new NbTestSuite(MutexTest.class); 48 49 return suite; 50 } 51 52 54 protected void setUp () { 55 p = new Mutex.Privileged (); 56 m = new Mutex (p); 57 Mutex.beStrict = true; 58 } 59 60 public void testReadWriteRead() throws Exception { 61 62 final Object lock = new Object (); 63 final Mutex.Privileged mPriv = new Mutex.Privileged(); 64 final Mutex m = new Mutex( mPriv ); 65 66 synchronized ( lock ) { 67 mPriv.enterReadAccess(); 68 69 new Thread () { 70 public void run () { 71 synchronized( lock ) { 72 lock.notifyAll(); 73 } 74 mPriv.enterWriteAccess(); 75 synchronized ( lock ) { 76 lock.notifyAll(); 77 mPriv.exitWriteAccess(); 78 } 79 } 80 }.start(); 81 82 lock.wait(); 83 84 } 85 Thread.sleep (100); 86 87 mPriv.enterReadAccess(); 88 89 mPriv.exitReadAccess(); 90 91 synchronized ( lock ) { 92 mPriv.exitReadAccess(); 93 lock.wait(); 94 } 95 } 96 97 99 public void testPostImmediatelly () { 100 State s = new State (); 101 102 m.postReadRequest(s); 103 104 if (s.state != 1) { 105 fail ("Read request not started immediatelly"); 106 } 107 108 m.postWriteRequest (s); 109 110 if (s.state != 2) { 111 fail ("Write request not started immediately"); 112 } 113 } 114 115 117 public void testPostWriteRequest () { 118 119 State s = new State (); 120 121 p.enterWriteAccess (); 123 p.enterReadAccess (); 124 125 m.postWriteRequest(s); 126 127 if (s.state != 0) { 128 fail ("Write request started when we are in read access"); 129 } 130 131 p.exitReadAccess (); 132 133 if (s.state != 1) { 134 fail ("Write request not run when leaving read access: " + s.state); 135 } 136 137 p.exitWriteAccess (); 139 140 if (s.state != 1) { 141 fail ("Run more times?: " + s.state); 142 } 143 } 144 145 147 public void testPostReadRequest () { 148 149 State s = new State (); 150 151 p.enterWriteAccess (); 153 154 m.postReadRequest(s); 155 156 if (s.state != 0) { 157 fail ("Read request started when we are in write access"); 158 } 159 160 p.exitWriteAccess (); 161 162 if (s.state != 1) { 163 fail ("Read request not run when leaving write access: " + s.state); 164 } 165 166 167 if (s.state != 1) { 168 fail ("Run more times?: " + s.state); 169 } 170 } 171 172 186 187 190 public void testPostWriteReadRequests() { 191 State s = new State (); 192 193 p.enterWriteAccess (); 195 p.enterReadAccess (); 196 197 m.postWriteRequest(s); 198 199 if (s.state != 0) { 200 fail ("Write request started when we are in read access"); 201 } 202 203 m.postReadRequest(s); 204 205 if (s.state != 0) { 206 fail ("Read request started when we are in write access"); 207 } 208 209 p.exitReadAccess (); 210 211 if (s.state != 1) { 212 fail ("Write request not run when leaving read access: " + s.state); 213 } 214 215 p.exitWriteAccess (); 217 218 if (s.state != 2) { 219 fail ("Read request not run when leaving write access: " + s.state); 220 } 221 222 consistencyCheck(); 223 } 224 225 226 public void testSimplePostWriteRequest() { 227 State s = new State (); 228 229 m.postWriteRequest(s); 230 231 if (s.state != 1) { 232 fail ("Write request not run: " + s.state); 233 } 234 235 consistencyCheck(); 236 } 237 238 239 public void testSimplePostReadRequest() { 240 State s = new State (); 241 242 m.postReadRequest(s); 243 244 if (s.state != 1) { 245 fail ("Read request not run: " + s.state); 246 } 247 248 consistencyCheck(); 249 } 250 251 private static void asyncEnter(final Mutex.Privileged p, final boolean X, final long timeout) throws InterruptedException { 254 asyncEnter(p, X, timeout, null); 255 } 256 257 private static void asyncEnter(final Mutex.Privileged p, final boolean X, final long timeout, final Runnable run) throws InterruptedException { 260 final Object lock = new Object (); 261 262 synchronized (lock) { 263 new Thread (new Runnable () { 264 public void run() { 265 if (X) { 266 p.enterWriteAccess(); 267 } else { 268 p.enterReadAccess(); 269 } 270 271 synchronized (lock) { 272 lock.notify(); 273 } 274 275 if (run != null) { 276 run.run(); 277 } 278 279 try { 280 Thread.sleep(timeout); 281 } catch (InterruptedException e) { 282 e.printStackTrace(); 283 } 284 285 if (X) { 286 p.exitWriteAccess(); 287 } else { 288 p.exitReadAccess(); 289 } 290 291 } 292 }).start(); 293 294 lock.wait(); 295 } 296 } 297 298 301 public void testXContendedX() throws InterruptedException { 302 asyncEnter(p, true, 2000); 303 304 p.enterWriteAccess(); 306 p.exitWriteAccess(); 307 308 consistencyCheck(); 309 } 310 311 314 public void testXContendedS() throws InterruptedException { 315 asyncEnter(p, true, 2000); 316 317 p.enterReadAccess(); 319 p.exitReadAccess(); 320 321 consistencyCheck(); 322 } 323 324 327 public void testSContendedX() throws InterruptedException { 328 asyncEnter(p, false, 2000); 329 330 p.enterWriteAccess(); 332 p.exitWriteAccess(); 333 334 consistencyCheck(); 335 } 336 337 340 public void testSContendedS() throws InterruptedException { 341 asyncEnter(p, false, 2000); 342 343 p.enterReadAccess(); 345 p.exitReadAccess(); 346 347 consistencyCheck(); 348 } 349 350 353 public void testXContendedPx() throws InterruptedException { 354 asyncEnter(p, true, 2000); 355 356 State s = new State (); 357 358 m.postWriteRequest(s); 359 360 if (s.state != 1) { 361 fail ("Write request not run: " + s.state); 362 } 363 364 consistencyCheck(); 365 } 366 367 370 public void testXContendedPs() throws InterruptedException { 371 asyncEnter(p, true, 2000); 372 373 State s = new State (); 374 375 m.postReadRequest(s); 376 377 if (s.state != 1) { 378 fail ("Read request not run: " + s.state); 379 } 380 381 consistencyCheck(); 382 } 383 384 387 public void testSContendedPx() throws InterruptedException { 388 asyncEnter(p, false, 2000); 389 390 State s = new State (); 391 392 m.postWriteRequest(s); 393 394 if (s.state != 1) { 395 fail ("Write request not run: " + s.state); 396 } 397 398 consistencyCheck(); 399 } 400 401 404 public void testSContendedPs() throws InterruptedException { 405 asyncEnter(p, false, 2000); 406 407 State s = new State (); 408 409 m.postReadRequest(s); 410 411 if (s.state != 1) { 412 fail ("Write request not run: " + s.state); 413 } 414 415 consistencyCheck(); 416 } 417 418 421 public void testSContendedSPsPx() throws InterruptedException { 422 asyncEnter(p, false, 2000); 423 424 State s = new State (); 425 426 p.enterReadAccess(); 427 m.postReadRequest(s); 428 429 if (s.state != 1) { 430 fail ("Read request not run: " + s.state); 431 } 432 433 m.postWriteRequest(s); 434 435 if (s.state != 1) { 436 fail ("Write request run: " + s.state); 437 } 438 439 p.exitReadAccess(); 440 441 if (s.state != 2) { 442 fail ("Write request not run: " + s.state); 443 } 444 445 consistencyCheck(); 446 } 447 448 451 public void testSPxContendedX() throws Exception { 452 final State s = new State (); 453 454 asyncEnter(p, false, 2000, new Runnable () { 455 public void run() { 456 try { 457 Thread.sleep(1000); 458 } catch (Exception e) { 459 e.printStackTrace(); 460 } 461 m.postWriteRequest(s); 462 if (s.state == 1) { 463 fail ("Write request run: " + s.state); 464 } 465 } 466 }); 467 468 p.enterWriteAccess(); 469 if (s.state != 1) { 470 fail ("Write request not run: " + s.state); 471 } 472 p.exitWriteAccess(); 473 474 consistencyCheck(); 475 } 476 477 482 public void testXSPxContendedX() throws Exception { 483 final State s = new State (); 484 485 asyncEnter(p, true, 2000, new Runnable () { 486 public void run() { 487 p.enterReadAccess(); 488 try { 489 Thread.sleep(1000); 490 } catch (Exception e) { 491 e.printStackTrace(); 492 } 493 m.postWriteRequest(s); 494 p.exitReadAccess(); 495 496 if (s.state != 1) { 497 fail ("Write request not run: " + s.state); 498 } 499 } 500 }); 501 502 p.enterWriteAccess(); 503 p.exitWriteAccess(); 504 505 consistencyCheck(); 506 } 507 508 526 public void testStarvation68106() throws Exception { 527 final Mutex.Privileged PR = new Mutex.Privileged(); 528 final Mutex M = new Mutex(PR); 529 final Object L = new Object (); 530 final boolean[] done = new boolean[3]; 531 532 final Ticker tickX1 = new Ticker(); 533 final Ticker tickX2 = new Ticker(); 534 final Ticker tickX3 = new Ticker(); 535 536 Thread A = new Thread ("A") { public void run() { 537 PR.enterReadAccess(); 538 539 tickX1.tick(); 540 tickX2.waitOn(); 541 542 synchronized(L) { 543 done[0] = true; 544 } 545 546 PR.exitReadAccess(); 547 }}; 548 549 Thread B = new Thread ("B") { public void run() { 550 synchronized(L) { 551 552 tickX2.tick(); 553 tickX3.tick(); 554 tickX1.waitOn(); 555 556 PR.enterReadAccess(); 557 done[1] = true; 558 PR.exitReadAccess(); 559 } 560 }}; 561 562 Thread C = new Thread ("C") { public void run() { 563 PR.enterReadAccess(); 564 M.postWriteRequest(new Runnable () {public void run() { 565 done[2] = true; 566 }}); 567 PR.exitReadAccess(); 568 }}; 569 570 A.start(); 571 tickX1.waitOn(); 572 574 B.start(); 575 tickX3.waitOn(); 576 578 C.start(); 579 Thread.sleep(100); 582 tickX1.tick(); 583 585 A.join(2000); 587 B.join(2000); 588 C.join(2000); 589 590 if (!done[0] || !done[1] || !done[2]) { 591 StringBuffer sb = new StringBuffer (); 592 sb.append("A: "); sb.append(done[0]); 593 sb.append(" B: "); sb.append(done[1]); 594 sb.append(" C: "); sb.append(done[2]); 595 sb.append("\n"); 596 dumpStrackTrace(A, sb); 597 dumpStrackTrace(B, sb); 598 dumpStrackTrace(C, sb); 599 600 fail(sb.toString()); 601 } 602 } 603 604 605 617 public void testStarvation49466() throws Exception { 618 final Mutex.Privileged pr1 = new Mutex.Privileged(); 619 final Mutex mutex1 = new Mutex(pr1); 620 621 final Mutex.Privileged pr2 = new Mutex.Privileged(); 622 final Mutex mutex2 = new Mutex(pr2); 623 624 final boolean[] done = new boolean[3]; 625 626 final Ticker tick0 = new Ticker(); 627 final Ticker tick1 = new Ticker(); 628 final Ticker tick2 = new Ticker(); 629 final Ticker tick3 = new Ticker(); 630 631 Thread A = new Thread () { 632 public void run() { 633 pr1.enterWriteAccess(); 634 tick0.tick(); 635 636 tick1.waitOn(); 637 638 pr2.enterReadAccess(); 639 done[0] = true; 640 pr2.exitReadAccess(); 641 642 pr1.exitWriteAccess(); 643 } 644 }; 645 646 A.start(); 648 tick0.waitOn(); 649 650 651 Thread B = new Thread () { 652 public void run() { 653 pr2.enterWriteAccess(); 654 655 mutex2.postReadRequest(new Runnable () { 656 public void run() { 657 tick0.tick(); 658 pr1.enterWriteAccess(); 659 done[1] = true; 660 pr1.exitWriteAccess(); 661 } 662 }); 663 664 tick0.tick(); 665 666 tick2.waitOn(); 667 668 pr2.exitWriteAccess(); 669 } 670 }; 671 672 B.start(); 674 tick0.waitOn(); 675 676 693 694 tick1.tick(); Thread.sleep(1000); 698 tick2.tick(); 700 701 tick0.waitOn(); 703 704 Thread.sleep(2000); 707 assertTrue("Thread A finished", done[0]); 708 assertTrue("Thread B finished", done[1]); 709 710 } 712 713 714 public void testReadEnterAfterPostWriteWasContended87932() throws Exception { 715 final Logger LOG = Logger.getLogger("org.openide.util.test"); 717 final Mutex.Privileged pr = new Mutex.Privileged(); 718 final Mutex mutex = new Mutex(pr); 719 final Ticker tick = new Ticker(); 720 final AtomicBoolean inWrite = new AtomicBoolean (); 721 722 Thread t = new Thread ("testReadEnterAfterPostWriteWasContended87932-reader") { 723 public void run() { 724 pr.enterReadAccess(); 725 tick.tick(); 726 727 LOG.log(Level.FINE, "wait for exploitable place in Mutex"); 729 730 pr.exitReadAccess(); 731 732 LOG.log(Level.FINE, "Let the other thread continue"); 734 735 MutexTest.sleep(50); 737 pr.enterReadAccess(); 738 pr.exitReadAccess(); 740 741 742 } 743 }; 744 String str = "THREAD:testReadEnterAfterPostWriteWasContended87932-reader MSG:wait for exploitable place in Mutex" + 745 "THREAD:main MSG:.*Processing posted requests: 2" + 746 "THREAD:testReadEnterAfterPostWriteWasContended87932-reader MSG:Let the other thread continue"; 747 Log.controlFlow(Logger.getLogger("org.openide.util"), null, str, 100); 748 749 pr.enterReadAccess(); 750 t.start(); 751 752 tick.waitOn(); 753 mutex.postWriteRequest(new Runnable () { 754 public void run() { 755 inWrite.set(true); 756 sleep(1000); 758 inWrite.set(false); 759 } 760 }); 761 pr.exitReadAccess(); 762 763 t.join(10000); 764 } 765 766 private static class Ticker { 767 boolean state; 768 769 public void waitOn() { 770 synchronized(this) { 771 while (!state) { 772 try { 773 wait(); 774 } catch (InterruptedException e) { 775 throw new InternalError (); 776 } 777 } 778 state = false; } 780 } 781 782 public void tick() { 783 synchronized(this) { 784 state = true; 785 notifyAll(); 786 } 787 } 788 } 789 790 791 792 797 public void testXPsContendedX() throws Exception { 798 final State s = new State (); 799 800 asyncEnter(p, true, 2000, new Runnable () { 801 public void run() { 802 try { 803 Thread.sleep(1000); 804 } catch (Exception e) { 805 e.printStackTrace(); 806 } 807 m.postReadRequest(s); 808 809 if (s.state == 1) { 810 fail ("Read request run: " + s.state); 811 } 812 } 813 }); 814 815 p.enterWriteAccess(); 816 Thread.sleep(4000); 817 p.exitWriteAccess(); 818 819 consistencyCheck(); 820 } 821 822 823 private void consistencyCheck() { 824 p.enterWriteAccess(); 825 p.exitWriteAccess(); 826 } 827 828 public void testNoWayToDoReadAndThenWrite () { 829 class R implements Runnable { 830 public void run () { 831 m.writeAccess (this); 832 } 833 } 834 835 try { 836 m.readAccess (new R ()); 837 fail ("This is supposed to throw an IllegalStateException"); 838 } catch (IllegalStateException ex) { 839 } 841 } 842 843 public void testNoWayToDoWriteThenReadAndThenWrite () { 844 class R implements Runnable { 845 public boolean second; 846 public boolean end; 847 public boolean ending; 848 849 public void run () { 850 if (end) { 851 ending = true; 852 return; 853 } 854 855 if (second) { 856 end = true; 857 m.writeAccess (this); 858 } else { 859 second = true; 860 m.readAccess (this); 861 } 862 } 863 } 864 R r = new R (); 865 try { 866 m.writeAccess (r); 867 fail ("This is supposed to throw an IllegalStateException"); 868 } catch (IllegalStateException ex) { 869 assertTrue ("We were in the write access section", r.second); 871 assertTrue ("We were before the writeAcess(this)", r.end); 872 assertFalse ("We never reached ending", r.ending); 873 } 874 } 875 876 public void testIsOrIsNotInReadOrWriteAccess () { 877 new ReadWriteChecking ("No r/w", Boolean.FALSE, Boolean.FALSE).run (); 878 m.readAccess (new ReadWriteChecking ("r but no w", Boolean.TRUE, Boolean.FALSE)); 879 m.writeAccess (new ReadWriteChecking ("w but no r", Boolean.FALSE, Boolean.TRUE)); 880 m.readAccess (new Runnable () { 881 public void run () { 882 m.postReadRequest (new ReadWriteChecking ("+r -w", Boolean.TRUE, Boolean.FALSE)); 883 } 884 }); 885 m.readAccess (new Runnable () { 886 public void run () { 887 m.postWriteRequest (new ReadWriteChecking ("-r +w", Boolean.FALSE, Boolean.TRUE)); 888 } 889 }); 890 m.writeAccess (new Runnable () { 891 public void run () { 892 m.postReadRequest (new ReadWriteChecking ("+r -w", Boolean.TRUE, Boolean.FALSE)); 893 } 894 }); 895 m.writeAccess (new Runnable () { 896 public void run () { 897 m.postWriteRequest (new ReadWriteChecking ("-r +w", Boolean.FALSE, Boolean.TRUE)); 898 } 899 }); 900 901 m.writeAccess (new Runnable () { 903 public boolean second; 904 905 public void run () { 906 if (!second) { 907 second = true; 908 m.readAccess (this); 909 return; 910 } 911 912 class P implements Runnable { 913 public boolean exec; 914 public void run () { 915 exec = true; 916 } 917 } 918 P r = new P (); 919 P w = new P (); 920 m.postWriteRequest (w); 921 m.postReadRequest (r); 922 assertFalse ("Writer not executed", w.exec); 923 assertFalse ("Reader not executed", r.exec); 924 925 m.readAccess (new ReadWriteChecking ("+r +w", Boolean.TRUE, Boolean.TRUE)); 926 } 927 }); 928 929 new ReadWriteChecking ("None at the end", Boolean.FALSE, Boolean.FALSE).run (); 930 } 931 932 public void testReaderCannotEnterWriteChainedMutex() throws Exception { 936 final Mutex.Privileged PR = new Mutex.Privileged(); 937 final Mutex M = new Mutex(PR); 938 final boolean[] done = new boolean[2]; 939 940 final Ticker tickX1 = new Ticker(); 941 final Ticker tickX2 = new Ticker(); 942 final Ticker tickX3 = new Ticker(); 943 944 PR.enterWriteAccess(); 945 946 Thread A = new Thread ("A") { public void run() { 947 PR.enterReadAccess(); 948 done[0] = true; 949 PR.exitReadAccess(); 950 }}; 951 952 Thread B = new Thread ("B") { public void run() { 953 PR.enterReadAccess(); 954 done[1] = true; 955 PR.exitReadAccess(); 956 }}; 957 958 A.start(); 959 Thread.sleep(100); 961 B.start(); 962 Thread.sleep(100);; 964 assertFalse ("B should chain-wait", done[1]); 965 966 PR.exitWriteAccess(); 968 A.join(1000); 969 B.join(1000); 970 assertTrue("A finished after unblocking M", done[0]); 971 assertTrue("B finished after unblocking M", done[1]); 972 } 973 974 public void testIsReadOrWriteForEventMutex () throws Exception { 975 class DoTheWork implements Runnable { 976 public boolean isRead; 977 public boolean isWrite; 978 979 public void run () { 980 isRead = Mutex.EVENT.isReadAccess (); 981 isWrite = Mutex.EVENT.isWriteAccess (); 982 } 983 } 984 985 DoTheWork rp = new DoTheWork (); 986 org.openide.util.RequestProcessor.getDefault ().post(rp).waitFinished (); 987 988 DoTheWork awt = new DoTheWork (); 989 javax.swing.SwingUtilities.invokeAndWait (awt); 990 991 assertFalse ("Nothing in RP", rp.isRead); 992 assertFalse ("No in RP", rp.isWrite); 993 994 assertTrue ("Is read in ", awt.isRead); 995 assertTrue ("is also write", awt.isWrite); 996 } 997 998 private void exceptionsReporting(final Throwable t) throws Exception { 999 final IOException e1 = new IOException (); 1000 final Mutex mm = m; 1001 final Runnable secondRequest = new Runnable () { 1002 public void run() { 1003 if (t instanceof RuntimeException ) { 1004 throw (RuntimeException )t; 1005 } else { 1006 throw (Error )t; 1007 } 1008 } 1009 }; 1010 Mutex.ExceptionAction<Object > firstRequest = new Mutex.ExceptionAction<Object >() { 1011 public Object run () throws Exception { 1012 mm.postWriteRequest(secondRequest); 1013 throw e1; 1014 } 1015 }; 1016 try { 1017 m.readAccess(firstRequest); 1018 } catch (MutexException mu) { 1019 Exception e = mu.getException(); 1020 assertEquals("IOException correctly reported", e, e1); 1021 return; 1022 } catch (Throwable e) { 1023 fail("a problem in postWriteRequest() should not swallow any " + 1024 "exception thrown in readAccess() because that might be " + 1025 "the cause of the problem. "+e.toString()); 1026 } 1027 fail("should never get here"); 1028 } 1029 1030 public void testThrowingAssertionErrorInSpecialCase() throws Exception { 1031 exceptionsReporting(new AssertionError ()); 1032 } 1033 1034 public void testThrowingRuntimeExceptionInSpecialCase() throws Exception { 1035 exceptionsReporting(new RuntimeException ()); 1036 } 1037 1038 private void dumpStrackTrace(Thread thread, StringBuffer sb) throws IllegalAccessException , InvocationTargetException { 1039 sb.append("StackTrace for thread: " + thread.getName() + "\n"); 1040 1041 StackTraceElement [] arr = thread.getStackTrace(); 1042 1043 for (int i = 0; i < arr.length; i++) { 1044 sb.append(arr[i].toString()); 1045 sb.append("\n"); 1046 } 1047 } 1048 1049 private class ReadWriteChecking implements Runnable { 1050 public Boolean read; 1051 public Boolean write; 1052 public String msg; 1053 1054 public ReadWriteChecking (String msg, Boolean read, Boolean write) { 1055 assertNotNull ("Msg cannot be null", msg); 1056 this.msg = msg; 1057 this.read = read; 1058 this.write = write; 1059 } 1060 1061 protected void finalize () { 1062 assertNull ("Run method was not called!", msg); 1063 } 1064 1065 public void run () { 1066 if (write != null) assertEquals (msg, write.booleanValue (), m.isWriteAccess ()); 1067 if (read != null) assertEquals (msg, read.booleanValue (), m.isReadAccess ()); 1068 msg = null; 1069 } 1070 } 1071 1072 1073 private static class State implements Runnable { 1074 public int state; 1075 1076 public void run () { 1077 state++; 1078 } 1079 1080 } 1082 private static final void sleep(long ms) { 1083 try { 1084 Thread.sleep(ms); 1085 } catch (InterruptedException ex) { 1086 ex.printStackTrace(); 1087 } 1088 } 1089 1090 protected Level logLevel() { 1091 return Level.FINEST; 1092 } 1093} 1094 | Popular Tags |