001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package threaddemo.locking;
043:
044: import junit.framework.TestCase;
045: import threaddemo.locking.RWLock;
046: import threaddemo.locking.Locks;
047: import threaddemo.locking.PrivilegedLock;
048:
049: /**
050: * Test behavior of Locks.readWrite and PrivilegedLock.
051: * @author Jaroslav Tulach, Ales Novak, Petr Hrebejk, Jesse Glick
052: */
053: public class ReadWriteLockTest extends TestCase {
054:
055: private PrivilegedLock p;
056: private RWLock m;
057:
058: public ReadWriteLockTest(String testName) {
059: super (testName);
060: }
061:
062: protected void setUp() {
063: p = new PrivilegedLock();
064: m = Locks.readWrite(p);
065: }
066:
067: public void testReadWriteRead() throws Exception {
068:
069: final Object lock = new Object();
070:
071: synchronized (lock) {
072: p.enterRead();
073:
074: new Thread() {
075: public void run() {
076: synchronized (lock) {
077: lock.notifyAll();
078: }
079: p.enterWrite();
080: synchronized (lock) {
081: lock.notifyAll();
082: p.exitWrite();
083: }
084: }
085: }.start();
086:
087: lock.wait();
088:
089: }
090: Thread.sleep(100);
091:
092: p.enterRead();
093:
094: p.exitRead();
095:
096: synchronized (lock) {
097: p.exitRead();
098: lock.wait();
099: }
100:
101: assertTrue(!m.canRead());
102: assertTrue(!m.canWrite());
103: }
104:
105: /** Simple test to execute read access and write access immediately.
106: */
107: public void testPostImmediately() {
108: State s = new State();
109:
110: m.read(s);
111:
112: if (s.state != 1) {
113: fail("Read request not started immediatelly");
114: }
115:
116: m.write(s);
117:
118: if (s.state != 2) {
119: fail("Write request not started immediately");
120: }
121: }
122:
123: // starts a new thread, after return the thread will hold lock "p" in
124: // mode X for timeout milliseconds
125: private static void asyncEnter(final PrivilegedLock p,
126: final boolean X, final long timeout)
127: throws InterruptedException {
128: asyncEnter(p, X, timeout, null);
129: }
130:
131: // starts a new thread, after return the thread will hold lock "p" in
132: // mode X for timeout milliseconds, the new thread execs "run" first
133: private static void asyncEnter(final PrivilegedLock p,
134: final boolean X, final long timeout, final Runnable run)
135: throws InterruptedException {
136: final Object lock = new Object();
137:
138: synchronized (lock) {
139: new Thread(new Runnable() {
140: public void run() {
141: if (X) {
142: p.enterWrite();
143: } else {
144: p.enterRead();
145: }
146:
147: synchronized (lock) {
148: lock.notify();
149: }
150:
151: if (run != null) {
152: run.run();
153: }
154:
155: try {
156: Thread.sleep(timeout);
157: } catch (InterruptedException e) {
158: e.printStackTrace();
159: }
160:
161: if (X) {
162: p.exitWrite();
163: } else {
164: p.exitRead();
165: }
166:
167: }
168: }).start();
169:
170: lock.wait();
171: }
172: }
173:
174: /** Tests enterWrite while the Lock is contended in X mode by
175: * another thread
176: */
177: public void testXContendedX() throws InterruptedException {
178: asyncEnter(p, true, 2000);
179:
180: // first enter
181: p.enterWrite();
182: p.exitWrite();
183:
184: consistencyCheck();
185: }
186:
187: /** Tests enterRead while the Lock is contended in X mode by
188: * another thread
189: */
190: public void testXContendedS() throws InterruptedException {
191: asyncEnter(p, true, 2000);
192:
193: // first enter
194: p.enterRead();
195: p.exitRead();
196:
197: consistencyCheck();
198: }
199:
200: /** Tests enterWrite while the Lock is contended in S mode by
201: * another thread
202: */
203: public void testSContendedX() throws InterruptedException {
204: asyncEnter(p, false, 2000);
205:
206: // first enter
207: p.enterWrite();
208: p.exitWrite();
209:
210: consistencyCheck();
211: }
212:
213: /** Tests enterRead while the Lock is contended in S mode by
214: * another thread
215: */
216: public void testSContendedS() throws InterruptedException {
217: asyncEnter(p, false, 2000);
218:
219: // first enter
220: p.enterRead();
221: p.exitRead();
222:
223: consistencyCheck();
224: }
225:
226: /** Checks the Lock is in the consistent state, i.e. enterWrite must pass */
227: private void consistencyCheck() {
228: p.enterWrite();
229: p.exitWrite();
230: }
231:
232: private static class State implements Runnable {
233: public int state;
234:
235: public void run() {
236: state++;
237: }
238:
239: } // end of State
240:
241: // --- TESTS ADDED BY JGLICK ---
242:
243: public void testNestedEntries() throws Exception {
244: // can go write -> read
245: p.enterWrite();
246: try {
247: p.enterRead();
248: p.exitRead();
249: } finally {
250: p.exitWrite();
251: }
252: // and write -> write -> read
253: p.enterWrite();
254: try {
255: p.enterWrite();
256: try {
257: p.enterRead();
258: p.exitRead();
259: } finally {
260: p.exitWrite();
261: }
262: } finally {
263: p.exitWrite();
264: }
265: // and write -> read -> read
266: p.enterWrite();
267: try {
268: p.enterRead();
269: try {
270: p.enterRead();
271: p.exitRead();
272: } finally {
273: p.exitRead();
274: }
275: } finally {
276: p.exitWrite();
277: }
278: // and even write -> write -> read -> read
279: p.enterWrite();
280: try {
281: p.enterWrite();
282: try {
283: p.enterRead();
284: try {
285: p.enterRead();
286: p.exitRead();
287: } finally {
288: p.exitRead();
289: }
290: } finally {
291: p.exitWrite();
292: }
293: } finally {
294: p.exitWrite();
295: }
296: /* Don't bother testing this, it just deadlocks...
297: // but read -> write is forbidden
298: p.enterRead();
299: try {
300: boolean ok = true;
301: try {
302: p.enterWrite();
303: ok = false;
304: p.exitWrite();
305: } catch (IllegalStateException e) {
306: assertTrue(ok);
307: }
308: } finally {
309: p.exitRead();
310: }
311: // so is write -> read -> write!
312: p.enterWrite();
313: try {
314: p.enterRead();
315: try {
316: boolean ok = true;
317: try {
318: p.enterWrite();
319: ok = false;
320: p.exitWrite();
321: } catch (IllegalStateException e) {
322: assertTrue(ok);
323: }
324: } finally {
325: p.exitRead();
326: }
327: } finally {
328: p.exitWrite();
329: }
330: */
331: }
332:
333: public void testWriteLater() throws Exception {
334: assertTrue(!m.canWrite());
335: assertTrue(!m.canRead());
336: final boolean[] b = new boolean[1];
337: synchronized (b) {
338: m.writeLater(new Runnable() {
339: public void run() {
340: synchronized (b) {
341: b[0] = m.canWrite();
342: }
343: }
344: });
345: b.wait(1000);
346: assertTrue(b[0]);
347: }
348: b[0] = false;
349: synchronized (b) {
350: p.enterRead();
351: try {
352: m.writeLater(new Runnable() {
353: public void run() {
354: synchronized (b) {
355: b[0] = m.canWrite();
356: }
357: }
358: });
359: } finally {
360: p.exitRead();
361: }
362: b.wait(1000);
363: assertTrue(b[0]);
364: }
365: }
366:
367: }
|