0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * The Original Software is NetBeans. The Initial Developer of the Original
0027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
0028: * Microsystems, Inc. All Rights Reserved.
0029: *
0030: * If you wish your version of this file to be governed by only the CDDL
0031: * or only the GPL Version 2, indicate your decision by adding
0032: * "[Contributor] elects to include this software in this distribution
0033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034: * single choice of license, a recipient has the option to distribute
0035: * your version of this file under either the CDDL, the GPL Version 2 or
0036: * to extend the choice of license to its licensees as provided above.
0037: * However, if you add GPL Version 2 code and therefore, elected the GPL
0038: * Version 2 license, then the option applies only if the new code is
0039: * made subject to such option by the copyright holder.
0040: */
0041:
0042: package org.openide.util;
0043:
0044: import java.io.IOException;
0045: import java.lang.ref.*;
0046: import java.lang.reflect.InvocationTargetException;
0047: import java.util.*;
0048: import java.util.concurrent.atomic.AtomicBoolean;
0049: import java.util.logging.Level;
0050: import java.util.logging.Logger;
0051: import junit.framework.*;
0052: import org.netbeans.junit.*;
0053:
0054: public class MutexTest extends NbTestCase {
0055: Mutex.Privileged p;
0056: Mutex m;
0057:
0058: public MutexTest(java.lang.String testName) {
0059: super (testName);
0060: }
0061:
0062: public static Test suite() {
0063: NbTestSuite suite = new NbTestSuite(MutexTest.class);
0064:
0065: return suite;
0066: }
0067:
0068: /** Sets up the test.
0069: */
0070: @Override
0071: protected void setUp() {
0072: p = new Mutex.Privileged();
0073: m = new Mutex(p);
0074: Mutex.beStrict = true;
0075: }
0076:
0077: @Override
0078: protected Level logLevel() {
0079: return Level.FINEST;
0080: }
0081:
0082: public void testReadWriteRead() throws Exception {
0083:
0084: final Object lock = new Object();
0085: final Mutex.Privileged mPriv = new Mutex.Privileged();
0086: final Mutex tmpMutex = new Mutex(mPriv);
0087:
0088: synchronized (lock) {
0089: mPriv.enterReadAccess();
0090:
0091: new Thread() {
0092: public void run() {
0093: synchronized (lock) {
0094: lock.notifyAll();
0095: }
0096: mPriv.enterWriteAccess();
0097: synchronized (lock) {
0098: lock.notifyAll();
0099: mPriv.exitWriteAccess();
0100: }
0101: }
0102: }.start();
0103:
0104: lock.wait();
0105:
0106: }
0107: Thread.sleep(100);
0108:
0109: mPriv.enterReadAccess();
0110:
0111: mPriv.exitReadAccess();
0112:
0113: synchronized (lock) {
0114: mPriv.exitReadAccess();
0115: lock.wait();
0116: }
0117: }
0118:
0119: /** Simple test to execute read access and write access imediatelly.
0120: */
0121: public void testPostImmediatelly() {
0122: State s = new State();
0123:
0124: m.postReadRequest(s);
0125:
0126: if (s.state != 1) {
0127: fail("Read request not started immediatelly");
0128: }
0129:
0130: m.postWriteRequest(s);
0131:
0132: if (s.state != 2) {
0133: fail("Write request not started immediately");
0134: }
0135: }
0136:
0137: /** Behaviour of postWriteRequest is defined by this test.
0138: */
0139: public void testPostWriteRequest() {
0140:
0141: State s = new State();
0142:
0143: // first enter
0144: p.enterWriteAccess();
0145: p.enterReadAccess();
0146:
0147: m.postWriteRequest(s);
0148:
0149: if (s.state != 0) {
0150: fail("Write request started when we are in read access");
0151: }
0152:
0153: p.exitReadAccess();
0154:
0155: if (s.state != 1) {
0156: fail("Write request not run when leaving read access: "
0157: + s.state);
0158: }
0159:
0160: // exiting
0161: p.exitWriteAccess();
0162:
0163: if (s.state != 1) {
0164: fail("Run more times?: " + s.state);
0165: }
0166: }
0167:
0168: /** Behaviour of postReadRequest is defined by this test.
0169: */
0170: public void testPostReadRequest() {
0171:
0172: State s = new State();
0173:
0174: // first enter
0175: p.enterWriteAccess();
0176:
0177: m.postReadRequest(s);
0178:
0179: if (s.state != 0) {
0180: fail("Read request started when we are in write access");
0181: }
0182:
0183: p.exitWriteAccess();
0184:
0185: if (s.state != 1) {
0186: fail("Read request not run when leaving write access: "
0187: + s.state);
0188: }
0189:
0190: if (s.state != 1) {
0191: fail("Run more times?: " + s.state);
0192: }
0193: }
0194:
0195: /** Test enter from S mode to X mode *
0196: public void testXtoS() {
0197: State s = new State ();
0198:
0199: p.enterReadAccess ();
0200: p.enterWriteAccess ();
0201: s.run();
0202: p.exitWriteAccess();
0203: p.exitReadAccess();
0204: if (s.state != 1) {
0205: fail ("Run more times?: " + s.state);
0206: }
0207: }
0208: */
0209:
0210: /** Tests posting write and read requests while the Mutex is held
0211: * in X mode and was entered in S mode as well
0212: */
0213: public void testPostWriteReadRequests() {
0214: State s = new State();
0215:
0216: // first enter
0217: p.enterWriteAccess();
0218: p.enterReadAccess();
0219:
0220: m.postWriteRequest(s);
0221:
0222: if (s.state != 0) {
0223: fail("Write request started when we are in read access");
0224: }
0225:
0226: m.postReadRequest(s);
0227:
0228: if (s.state != 0) {
0229: fail("Read request started when we are in write access");
0230: }
0231:
0232: p.exitReadAccess();
0233:
0234: if (s.state != 1) {
0235: fail("Write request not run when leaving read access: "
0236: + s.state);
0237: }
0238:
0239: // exiting
0240: p.exitWriteAccess();
0241:
0242: if (s.state != 2) {
0243: fail("Read request not run when leaving write access: "
0244: + s.state);
0245: }
0246:
0247: consistencyCheck();
0248: }
0249:
0250: /** Tests simple postWriteRequest */
0251: public void testSimplePostWriteRequest() {
0252: State s = new State();
0253:
0254: m.postWriteRequest(s);
0255:
0256: if (s.state != 1) {
0257: fail("Write request not run: " + s.state);
0258: }
0259:
0260: consistencyCheck();
0261: }
0262:
0263: /** Tests simple postReadRequest */
0264: public void testSimplePostReadRequest() {
0265: State s = new State();
0266:
0267: m.postReadRequest(s);
0268:
0269: if (s.state != 1) {
0270: fail("Read request not run: " + s.state);
0271: }
0272:
0273: consistencyCheck();
0274: }
0275:
0276: // starts a new thread, after return the thread will hold lock "p" in
0277: // mode X for timeout milliseconds
0278: private static void asyncEnter(final Mutex.Privileged p,
0279: final boolean X, final long timeout)
0280: throws InterruptedException {
0281: asyncEnter(p, X, timeout, null);
0282: }
0283:
0284: // starts a new thread, after return the thread will hold lock "p" in
0285: // mode X for timeout milliseconds, the new thread execs "run" first
0286: private static void asyncEnter(final Mutex.Privileged p,
0287: final boolean X, final long timeout, final Runnable run)
0288: throws InterruptedException {
0289: final Object lock = new Object();
0290:
0291: synchronized (lock) {
0292: new Thread(new Runnable() {
0293: public void run() {
0294: if (X) {
0295: p.enterWriteAccess();
0296: } else {
0297: p.enterReadAccess();
0298: }
0299:
0300: synchronized (lock) {
0301: lock.notify();
0302: }
0303:
0304: if (run != null) {
0305: run.run();
0306: }
0307:
0308: try {
0309: Thread.sleep(timeout);
0310: } catch (InterruptedException e) {
0311: e.printStackTrace();
0312: }
0313:
0314: if (X) {
0315: p.exitWriteAccess();
0316: } else {
0317: p.exitReadAccess();
0318: }
0319:
0320: }
0321: }).start();
0322:
0323: lock.wait();
0324: }
0325: }
0326:
0327: /** Tests enterWriteAccess while the Mutex is contended in X mode by
0328: * another thread
0329: */
0330: public void testXContendedX() throws InterruptedException {
0331: asyncEnter(p, true, 2000);
0332:
0333: // first enter
0334: p.enterWriteAccess();
0335: p.exitWriteAccess();
0336:
0337: consistencyCheck();
0338: }
0339:
0340: /** Tests enterReadAccess while the Mutex is contended in X mode by
0341: * another thread
0342: */
0343: public void testXContendedS() throws InterruptedException {
0344: asyncEnter(p, true, 2000);
0345:
0346: // first enter
0347: p.enterReadAccess();
0348: p.exitReadAccess();
0349:
0350: consistencyCheck();
0351: }
0352:
0353: /** Tests enterWriteAccess while the Mutex is contended in S mode by
0354: * another thread
0355: */
0356: public void testSContendedX() throws InterruptedException {
0357: asyncEnter(p, false, 2000);
0358:
0359: // first enter
0360: p.enterWriteAccess();
0361: p.exitWriteAccess();
0362:
0363: consistencyCheck();
0364: }
0365:
0366: /** Tests enterReadAccess while the Mutex is contended in S mode by
0367: * another thread
0368: */
0369: public void testSContendedS() throws InterruptedException {
0370: asyncEnter(p, false, 2000);
0371:
0372: // first enter
0373: p.enterReadAccess();
0374: p.exitReadAccess();
0375:
0376: consistencyCheck();
0377: }
0378:
0379: /** Tests postWriteRequest while the Mutex is contended in X mode by
0380: * another thread
0381: */
0382: public void testXContendedPx() throws InterruptedException {
0383: asyncEnter(p, true, 2000);
0384:
0385: State s = new State();
0386:
0387: m.postWriteRequest(s);
0388:
0389: if (s.state != 1) {
0390: fail("Write request not run: " + s.state);
0391: }
0392:
0393: consistencyCheck();
0394: }
0395:
0396: /** Tests postReadRequest while the Mutex is contended in X mode by
0397: * another thread
0398: */
0399: public void testXContendedPs() throws InterruptedException {
0400: asyncEnter(p, true, 2000);
0401:
0402: State s = new State();
0403:
0404: m.postReadRequest(s);
0405:
0406: if (s.state != 1) {
0407: fail("Read request not run: " + s.state);
0408: }
0409:
0410: consistencyCheck();
0411: }
0412:
0413: /** Tests postWriteRequest while the Mutex is contended in S mode by
0414: * another thread
0415: */
0416: public void testSContendedPx() throws InterruptedException {
0417: asyncEnter(p, false, 2000);
0418:
0419: State s = new State();
0420:
0421: m.postWriteRequest(s);
0422:
0423: if (s.state != 1) {
0424: fail("Write request not run: " + s.state);
0425: }
0426:
0427: consistencyCheck();
0428: }
0429:
0430: /** Tests postReadRequest while the Mutex is contended in S mode by
0431: * another thread
0432: */
0433: public void testSContendedPs() throws InterruptedException {
0434: asyncEnter(p, false, 2000);
0435:
0436: State s = new State();
0437:
0438: m.postReadRequest(s);
0439:
0440: if (s.state != 1) {
0441: fail("Write request not run: " + s.state);
0442: }
0443:
0444: consistencyCheck();
0445: }
0446:
0447: /** Tests postWriteRequest and postReadRequest while the Mutex is contended in S mode by
0448: * another thread as well as this thread.
0449: */
0450: public void testSContendedSPsPx() throws InterruptedException {
0451: asyncEnter(p, false, 2000);
0452:
0453: State s = new State();
0454:
0455: p.enterReadAccess();
0456: m.postReadRequest(s);
0457:
0458: if (s.state != 1) {
0459: fail("Read request not run: " + s.state);
0460: }
0461:
0462: m.postWriteRequest(s);
0463:
0464: if (s.state != 1) {
0465: fail("Write request run: " + s.state);
0466: }
0467:
0468: p.exitReadAccess();
0469:
0470: if (s.state != 2) {
0471: fail("Write request not run: " + s.state);
0472: }
0473:
0474: consistencyCheck();
0475: }
0476:
0477: /** The Mutex is held in S mode by a thread which also posted a
0478: * write request. Another thread tries enterWriteAccess.
0479: */
0480: public void testSPxContendedX() throws Exception {
0481: final State s = new State();
0482:
0483: asyncEnter(p, false, 2000, new Runnable() {
0484: public void run() {
0485: try {
0486: Thread.sleep(1000);
0487: } catch (Exception e) {
0488: e.printStackTrace();
0489: }
0490: m.postWriteRequest(s);
0491: if (s.state == 1) {
0492: fail("Write request run: " + s.state);
0493: }
0494: }
0495: });
0496:
0497: p.enterWriteAccess();
0498: if (s.state != 1) {
0499: fail("Write request not run: " + s.state);
0500: }
0501: p.exitWriteAccess();
0502:
0503: consistencyCheck();
0504: }
0505:
0506: /**
0507: * Test case for #16577. Grab X,S and post X request,
0508: * the second thread waits for X, causing the mutex to be
0509: * in CHAINED.
0510: */
0511: public void testXSPxContendedX() throws Exception {
0512: final State s = new State();
0513:
0514: asyncEnter(p, true, 2000, new Runnable() {
0515: public void run() {
0516: p.enterReadAccess();
0517: try {
0518: Thread.sleep(1000);
0519: } catch (Exception e) {
0520: e.printStackTrace();
0521: }
0522: m.postWriteRequest(s);
0523: p.exitReadAccess();
0524:
0525: if (s.state != 1) {
0526: fail("Write request not run: " + s.state);
0527: }
0528: }
0529: });
0530:
0531: p.enterWriteAccess();
0532: p.exitWriteAccess();
0533:
0534: consistencyCheck();
0535: }
0536:
0537: /**
0538: * The scenario:
0539: * Cast:
0540: * Thread A: M.reader [X] trying to lock(L)
0541: * Thread B: L owner [X] trying to enter M.read
0542: * Thread C: M.reader trying to M.writeReenter on leave
0543: *
0544: * Actions:
0545: * - first let A and B reach point [X]
0546: * - unfuse A so it block on lock(L)
0547: * - start C, it will reach exitReadAccess and block on reenter as writer
0548: * - unfuse B so it should perform its legitimate read access
0549: *
0550: * What should happen then (if Mutex works OK):
0551: * - B unlocks L and die
0552: * - A locks/unlocks L, leave readAccess and die
0553: * - C performs its write and die
0554: */
0555: public void testStarvation68106() throws Exception {
0556: final Mutex.Privileged PR = new Mutex.Privileged();
0557: final Mutex M = new Mutex(PR);
0558: final Object L = new Object();
0559: final boolean[] done = new boolean[3];
0560:
0561: final Ticker tickX1 = new Ticker();
0562: final Ticker tickX2 = new Ticker();
0563: final Ticker tickX3 = new Ticker();
0564:
0565: Thread A = new Thread("A") {
0566: public @Override
0567: void run() {
0568: PR.enterReadAccess();
0569:
0570: tickX1.tick();
0571: tickX2.waitOn();
0572:
0573: synchronized (L) {
0574: done[0] = true;
0575: }
0576:
0577: PR.exitReadAccess();
0578: }
0579: };
0580:
0581: Thread B = new Thread("B") {
0582: public @Override
0583: void run() {
0584: synchronized (L) {
0585:
0586: tickX2.tick();
0587: tickX3.tick();
0588: tickX1.waitOn();
0589:
0590: PR.enterReadAccess();
0591: done[1] = true;
0592: PR.exitReadAccess();
0593: }
0594: }
0595: };
0596:
0597: Thread C = new Thread("C") {
0598: public @Override
0599: void run() {
0600: PR.enterReadAccess();
0601: M.postWriteRequest(new Runnable() {
0602: public void run() {
0603: done[2] = true;
0604: }
0605: });
0606: PR.exitReadAccess();
0607: }
0608: };
0609:
0610: A.start();
0611: tickX1.waitOn();
0612: // A reached point X
0613:
0614: B.start();
0615: tickX3.waitOn();
0616: // B reached point X, unlocked A so in would block on lock(L)
0617:
0618: C.start();
0619: Thread.sleep(100); // wait for C to perform exitReadAccess (can't
0620: // tick as it will block in case of failure...)
0621:
0622: tickX1.tick();
0623: // push B, everything should finish after this
0624:
0625: // wait for them for a while
0626: A.join(2000);
0627: B.join(2000);
0628: C.join(2000);
0629:
0630: if (!done[0] || !done[1] || !done[2]) {
0631: StringBuffer sb = new StringBuffer();
0632: sb.append("A: ");
0633: sb.append(done[0]);
0634: sb.append(" B: ");
0635: sb.append(done[1]);
0636: sb.append(" C: ");
0637: sb.append(done[2]);
0638: sb.append("\n");
0639: dumpStrackTrace(A, sb);
0640: dumpStrackTrace(B, sb);
0641: dumpStrackTrace(C, sb);
0642:
0643: fail(sb.toString());
0644: }
0645: }
0646:
0647: /**
0648: * The scenario:
0649: * - Have 3 threads, A, B and C
0650: * - writeLock mutex1 in A
0651: * - writeLock mutex2 in B
0652: * - postReadLock mutex2 in B
0653: * - writeLock mutex1 in B
0654: * - writeLock mutex2 in C
0655: * - readLock mutex2 in A
0656: * - leaveWriteLock mutex2 in B
0657: *
0658: */
0659: public void testStarvation49466() throws Exception {
0660: final Mutex.Privileged pr1 = new Mutex.Privileged();
0661: final Mutex mutex1 = new Mutex(pr1);
0662:
0663: final Mutex.Privileged pr2 = new Mutex.Privileged();
0664: final Mutex mutex2 = new Mutex(pr2);
0665:
0666: final boolean[] done = new boolean[3];
0667:
0668: final Ticker tick0 = new Ticker();
0669: final Ticker tick1 = new Ticker();
0670: final Ticker tick2 = new Ticker();
0671: final Ticker tick3 = new Ticker();
0672:
0673: Thread A = new Thread() {
0674: public @Override
0675: void run() {
0676: pr1.enterWriteAccess();
0677: tick0.tick();
0678:
0679: tick1.waitOn();
0680:
0681: pr2.enterReadAccess();
0682: done[0] = true;
0683: pr2.exitReadAccess();
0684:
0685: pr1.exitWriteAccess();
0686: }
0687: };
0688:
0689: // writeLock mutex1 in A
0690: A.start();
0691: tick0.waitOn();
0692:
0693: Thread B = new Thread() {
0694: public @Override
0695: void run() {
0696: pr2.enterWriteAccess();
0697:
0698: mutex2.postReadRequest(new Runnable() {
0699: public void run() {
0700: tick0.tick();
0701: pr1.enterWriteAccess();
0702: done[1] = true;
0703: pr1.exitWriteAccess();
0704: }
0705: });
0706:
0707: tick0.tick();
0708:
0709: tick2.waitOn();
0710:
0711: pr2.exitWriteAccess();
0712: }
0713: };
0714:
0715: // writeLock mutex2 in B
0716: B.start();
0717: tick0.waitOn();
0718:
0719: /*
0720: * The test fails even when using only first two threads.
0721: *
0722: Thread C = new Thread() {
0723: public void run() {
0724: tick0.tick(); // have to tick in advance and wait :-(
0725: pr2.enterWriteAccess();
0726: done[2] = true;
0727: pr2.exitWriteAccess();
0728: }
0729: };
0730:
0731: // writeLock mutex2 in C
0732: C.start();
0733: tick0.waitOn();
0734: Thread.sleep(1000); // between tick and C enqueued ...
0735: */
0736:
0737: // readLock mutex2 in A
0738: tick1.tick(); // enqueues A in mutex2's queue
0739: Thread.sleep(1000); // between tick and A enqueued ...
0740:
0741: // leaveWriteLock mutex2 in B
0742: tick2.tick();
0743:
0744: // postReadLock mutex2 in B
0745: tick0.waitOn();
0746:
0747: // System.err.println("Do a thread dump now!");
0748: Thread.sleep(2000); // give them some time ...
0749:
0750: assertTrue("Thread A finished", done[0]);
0751: assertTrue("Thread B finished", done[1]);
0752:
0753: // assertTrue("Thread C succeed", done[2]);
0754: }
0755:
0756: public void testReadEnterAfterPostWriteWasContended87932()
0757: throws Exception {
0758: final Logger LOG = Logger.getLogger("org.openide.util.test");//testReadEnterAfterPostWriteWasContended87932");
0759:
0760: final Mutex.Privileged pr = new Mutex.Privileged();
0761: final Mutex mutex = new Mutex(pr);
0762: final Ticker tick = new Ticker();
0763: class WR implements Runnable {
0764: boolean inWrite;
0765:
0766: public void run() {
0767: inWrite = true;
0768: // just keep the write lock for a while
0769: MutexTest.sleep(1000);
0770: inWrite = false;
0771: }
0772: }
0773: WR wr = new WR();
0774:
0775: class T extends Thread {
0776: public T() {
0777: super (
0778: "testReadEnterAfterPostWriteWasContended87932-reader");
0779: }
0780:
0781: @Override
0782: public void run() {
0783: pr.enterReadAccess();
0784: tick.tick();
0785:
0786: // wait for exploitable place in Mutex
0787: LOG.log(Level.FINE,
0788: "wait for exploitable place in Mutex");
0789:
0790: pr.exitReadAccess();
0791:
0792: //Let the othe thread continue
0793: LOG.log(Level.FINE, "Let the other thread continue");
0794:
0795: // the writer gets in now, lets' give him some time.
0796: MutexTest.sleep(50);
0797: pr.enterReadAccess();
0798: // if (inWrite.get()) fail("Another reader inside while writer keeps lock");
0799: pr.exitReadAccess();
0800:
0801: }
0802: }
0803:
0804: Thread t = new T();
0805: String str = "THREAD:testReadEnterAfterPostWriteWasContended87932-reader MSG:wait for exploitable place in Mutex"
0806: + "THREAD:main MSG:.*Processing posted requests: 2"
0807: + "THREAD:testReadEnterAfterPostWriteWasContended87932-reader MSG:Let the other thread continue";
0808: Log.controlFlow(Logger.getLogger("org.openide.util"), null,
0809: str, 100);
0810:
0811: pr.enterReadAccess();
0812: t.start();
0813:
0814: tick.waitOn();
0815:
0816: mutex.postWriteRequest(wr);
0817: pr.exitReadAccess();
0818:
0819: t.join(10000);
0820: }
0821:
0822: private static class Ticker {
0823: boolean state;
0824:
0825: public void waitOn() {
0826: synchronized (this ) {
0827: while (!state) {
0828: try {
0829: wait();
0830: } catch (InterruptedException e) {
0831: throw new InternalError();
0832: }
0833: }
0834: state = false; // reusable
0835: }
0836: }
0837:
0838: public void tick() {
0839: synchronized (this ) {
0840: state = true;
0841: notifyAll();
0842: }
0843: }
0844: }
0845:
0846: /**
0847: * Grab X and post S request,
0848: * the second thread waits for X, causing the mutex to be
0849: * in CHAINED.
0850: */
0851: public void testXPsContendedX() throws Exception {
0852: final State s = new State();
0853:
0854: asyncEnter(p, true, 2000, new Runnable() {
0855: public void run() {
0856: try {
0857: Thread.sleep(1000);
0858: } catch (Exception e) {
0859: e.printStackTrace();
0860: }
0861: m.postReadRequest(s);
0862:
0863: if (s.state == 1) {
0864: fail("Read request run: " + s.state);
0865: }
0866: }
0867: });
0868:
0869: p.enterWriteAccess();
0870: Thread.sleep(4000);
0871: p.exitWriteAccess();
0872:
0873: consistencyCheck();
0874: }
0875:
0876: /** Checks the Mutex is in the consistent state, i.e. enterWriteAccess must pass */
0877: private void consistencyCheck() {
0878: p.enterWriteAccess();
0879: p.exitWriteAccess();
0880: }
0881:
0882: public void testNoWayToDoReadAndThenWrite() {
0883: class R implements Runnable {
0884: public void run() {
0885: m.writeAccess(this );
0886: }
0887: }
0888:
0889: try {
0890: m.readAccess(new R());
0891: fail("This is supposed to throw an IllegalStateException");
0892: } catch (IllegalStateException ex) {
0893: // ok, this is expected
0894: }
0895: }
0896:
0897: public void testNoWayToDoWriteThenReadAndThenWrite() {
0898: class R implements Runnable {
0899: public boolean second;
0900: public boolean end;
0901: public boolean ending;
0902:
0903: public void run() {
0904: if (end) {
0905: ending = true;
0906: return;
0907: }
0908:
0909: if (second) {
0910: end = true;
0911: m.writeAccess(this );
0912: } else {
0913: second = true;
0914: m.readAccess(this );
0915: }
0916: }
0917: }
0918: R r = new R();
0919: try {
0920: m.writeAccess(r);
0921: fail("This is supposed to throw an IllegalStateException");
0922: } catch (IllegalStateException ex) {
0923: // ok, this is expected
0924: assertTrue("We were in the write access section", r.second);
0925: assertTrue("We were before the writeAcess(this)", r.end);
0926: assertFalse("We never reached ending", r.ending);
0927: }
0928: }
0929:
0930: public void testIsOrIsNotInReadOrWriteAccess() {
0931: new ReadWriteChecking("No r/w", Boolean.FALSE, Boolean.FALSE)
0932: .run();
0933: m.readAccess(new ReadWriteChecking("r but no w", Boolean.TRUE,
0934: Boolean.FALSE));
0935: m.writeAccess(new ReadWriteChecking("w but no r",
0936: Boolean.FALSE, Boolean.TRUE));
0937: m.readAccess(new Runnable() {
0938: public void run() {
0939: m.postReadRequest(new ReadWriteChecking("+r -w",
0940: Boolean.TRUE, Boolean.FALSE));
0941: }
0942: });
0943: m.readAccess(new Runnable() {
0944: public void run() {
0945: m.postWriteRequest(new ReadWriteChecking("-r +w",
0946: Boolean.FALSE, Boolean.TRUE));
0947: }
0948: });
0949: m.writeAccess(new Runnable() {
0950: public void run() {
0951: m.postReadRequest(new ReadWriteChecking("+r -w",
0952: Boolean.TRUE, Boolean.FALSE));
0953: }
0954: });
0955: m.writeAccess(new Runnable() {
0956: public void run() {
0957: m.postWriteRequest(new ReadWriteChecking("-r +w",
0958: Boolean.FALSE, Boolean.TRUE));
0959: }
0960: });
0961:
0962: // write->read->test (downgrade from write to read)
0963: m.writeAccess(new Runnable() {
0964: public boolean second;
0965:
0966: public void run() {
0967: if (!second) {
0968: second = true;
0969: m.readAccess(this );
0970: return;
0971: }
0972:
0973: class P implements Runnable {
0974: public boolean exec;
0975:
0976: public void run() {
0977: exec = true;
0978: }
0979: }
0980: P r = new P();
0981: P w = new P();
0982: m.postWriteRequest(w);
0983: m.postReadRequest(r);
0984: assertFalse("Writer not executed", w.exec);
0985: assertFalse("Reader not executed", r.exec);
0986:
0987: m.readAccess(new ReadWriteChecking("+r +w",
0988: Boolean.TRUE, Boolean.TRUE));
0989: }
0990: });
0991:
0992: new ReadWriteChecking("None at the end", Boolean.FALSE,
0993: Boolean.FALSE).run();
0994: }
0995:
0996: // [pnejedly:] There was an attempt to fix Starvation68106 by allowing read
0997: // enter while Mutex is currently in CHAIN mode, but that's wrong, as it can
0998: // be CHAIN/W (write granted, readers waiting). Let's cover this with a test.
0999: public void testReaderCannotEnterWriteChainedMutex()
1000: throws Exception {
1001: final Mutex.Privileged PR = new Mutex.Privileged();
1002: final Mutex M = new Mutex(PR);
1003: final boolean[] done = new boolean[2];
1004:
1005: final Ticker tickX1 = new Ticker();
1006: final Ticker tickX2 = new Ticker();
1007: final Ticker tickX3 = new Ticker();
1008:
1009: PR.enterWriteAccess();
1010:
1011: Thread A = new Thread("A") {
1012: public @Override
1013: void run() {
1014: PR.enterReadAccess();
1015: done[0] = true;
1016: PR.exitReadAccess();
1017: }
1018: };
1019:
1020: Thread B = new Thread("B") {
1021: public @Override
1022: void run() {
1023: PR.enterReadAccess();
1024: done[1] = true;
1025: PR.exitReadAccess();
1026: }
1027: };
1028:
1029: A.start();
1030: Thread.sleep(100); // wait for A to chain in M
1031:
1032: B.start();
1033: Thread.sleep(100); // B should chain as well
1034:
1035: assertFalse("B should chain-wait", done[1]);
1036:
1037: // final cleanup and consistency check:
1038: PR.exitWriteAccess();
1039: A.join(1000);
1040: B.join(1000);
1041: assertTrue("A finished after unblocking M", done[0]);
1042: assertTrue("B finished after unblocking M", done[1]);
1043: }
1044:
1045: public void testIsReadOrWriteForEventMutex() throws Exception {
1046: class DoTheWork implements Runnable {
1047: public boolean isRead;
1048: public boolean isWrite;
1049:
1050: public void run() {
1051: isRead = Mutex.EVENT.isReadAccess();
1052: isWrite = Mutex.EVENT.isWriteAccess();
1053: }
1054: }
1055:
1056: DoTheWork rp = new DoTheWork();
1057: org.openide.util.RequestProcessor.getDefault().post(rp)
1058: .waitFinished();
1059:
1060: DoTheWork awt = new DoTheWork();
1061: javax.swing.SwingUtilities.invokeAndWait(awt);
1062:
1063: assertFalse("Nothing in RP", rp.isRead);
1064: assertFalse("No in RP", rp.isWrite);
1065:
1066: assertTrue("Is read in ", awt.isRead);
1067: assertTrue("is also write", awt.isWrite);
1068: }
1069:
1070: private void exceptionsReporting(final Throwable t)
1071: throws Exception {
1072: final IOException e1 = new IOException();
1073: final Mutex mm = m;
1074: final Runnable secondRequest = new Runnable() {
1075: public void run() {
1076: if (t instanceof RuntimeException) {
1077: throw (RuntimeException) t;
1078: } else {
1079: throw (Error) t;
1080: }
1081: }
1082: };
1083: Mutex.ExceptionAction<Object> firstRequest = new Mutex.ExceptionAction<Object>() {
1084: public Object run() throws Exception {
1085: mm.postWriteRequest(secondRequest);
1086: throw e1;
1087: }
1088: };
1089: try {
1090: m.readAccess(firstRequest);
1091: } catch (MutexException mu) {
1092: Exception e = mu.getException();
1093: assertEquals("IOException correctly reported", e, e1);
1094: return;
1095: } catch (Throwable e) {
1096: fail("a problem in postWriteRequest() should not swallow any "
1097: + "exception thrown in readAccess() because that might be "
1098: + "the cause of the problem. " + e.toString());
1099: }
1100: fail("should never get here");
1101: }
1102:
1103: public void testThrowingAssertionErrorInSpecialCase()
1104: throws Exception {
1105: exceptionsReporting(new AssertionError());
1106: }
1107:
1108: public void testThrowingRuntimeExceptionInSpecialCase()
1109: throws Exception {
1110: exceptionsReporting(new RuntimeException());
1111: }
1112:
1113: private void dumpStrackTrace(Thread thread, StringBuffer sb)
1114: throws IllegalAccessException, InvocationTargetException {
1115: sb.append("StackTrace for thread: " + thread.getName() + "\n");
1116:
1117: StackTraceElement[] arr = thread.getStackTrace();
1118:
1119: for (int i = 0; i < arr.length; i++) {
1120: sb.append(arr[i].toString());
1121: sb.append("\n");
1122: }
1123: }
1124:
1125: private class ReadWriteChecking implements Runnable {
1126: public Boolean read;
1127: public Boolean write;
1128: public String msg;
1129:
1130: public ReadWriteChecking(String msg, Boolean read, Boolean write) {
1131: assertNotNull("Msg cannot be null", msg);
1132: this .msg = msg;
1133: this .read = read;
1134: this .write = write;
1135: }
1136:
1137: @Override
1138: protected void finalize() {
1139: assertNull("Run method was not called!", msg);
1140: }
1141:
1142: public void run() {
1143: if (write != null)
1144: assertEquals(msg, write.booleanValue(), m
1145: .isWriteAccess());
1146: if (read != null)
1147: assertEquals(msg, read.booleanValue(), m.isReadAccess());
1148: msg = null;
1149: }
1150: }
1151:
1152: private static class State implements Runnable {
1153: public int state;
1154:
1155: public void run() {
1156: state++;
1157: }
1158:
1159: } // end of State
1160:
1161: private static final void sleep(long ms) {
1162: try {
1163: Thread.sleep(ms);
1164: } catch (InterruptedException ex) {
1165: ex.printStackTrace();
1166: }
1167: }
1168: }
|