001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.test.classloader.test;
023:
024: import java.net.URL;
025: import java.io.File;
026: import java.util.List;
027: import java.util.ArrayList;
028: import java.util.Iterator;
029: import org.jboss.logging.Logger;
030: import org.jboss.mx.loading.UnifiedLoaderRepository3;
031: import org.jboss.mx.loading.UnifiedClassLoader3;
032: import org.jboss.mx.loading.LoaderRepository;
033: import org.jboss.mx.loading.LoadMgr3;
034: import org.jboss.test.classloader.circularity.test.MyClassLoadingTask;
035: import org.jboss.test.util.ClassMover;
036:
037: /** Additional deadlock scenario tests of the UnifiedClassLoader3
038:
039: .....................................
040: : +-------+ +-------+ :
041: : | TestA | | TestA2| :
042: : +---+---+ +---+---+ :
043: '''''''''|'''''''''''''''''''|'''''''
044: | extends |
045: ''''|'''''' |
046: ......|.........|.............|.........
047: : +--+----+ +--+----+ +--+----+ :
048: : | TestB | | TestB3| | TestB2| :
049: : +-------+ +-------+ +-------+ :
050: :......................................:
051:
052: @author Frank.Gamerdinger@Sun.COM
053: @author Scott.Stark@jboss.org
054: @version $Revision: 57211 $
055: */
056: public class DeadlockTests32 {
057: private static Logger log = Logger.getLogger(DeadlockTests32.class);
058: private SyncEvent syncEvent = new SyncEvent();
059: private TestClassLoader loaders[];
060: private UnifiedLoaderRepository3 mainRep;
061: private TestClassLoader blockingLoader;
062: private String blockname;
063:
064: /**
065: [starksm@banshee testsuite]$ jar -tf output/lib/dl-a.jar
066: org/jboss/test/classloader/test/abc/TestA.class
067: org/jboss/test/classloader/test/abc/TestA2.class
068: [starksm@banshee testsuite]$ jar -tf output/lib/dl-b.jar
069: org/jboss/test/classloader/test/abc/TestB.class
070: org/jboss/test/classloader/test/abc/TestB2.class
071: org/jboss/test/classloader/test/abc/TestB3.class
072: @param libDir
073: @throws Exception
074: */
075: public DeadlockTests32(File libDir) throws Exception {
076: ClassLoader appCl = this .getClass().getClassLoader();
077: URL u1 = new File(libDir, "dl-a.jar").toURL();
078: URL u2 = new File(libDir, "dl-b.jar").toURL();
079: loaders = new TestClassLoader[2];
080: mainRep = new UnifiedLoaderRepository3();
081: loaders[0] = new TestClassLoader(u1, appCl, mainRep);
082: loaders[1] = new TestClassLoader(u2, appCl, mainRep);
083: }
084:
085: /** Scenario:
086:
087: Thread T1 Thread T2
088: classLoader 1 [a.jar] classLoader 2 [b.jar]
089:
090: . .
091: t0 ------------------------------------------------------------
092: | | loadClass(abc.TestB)
093: | |----+
094: | +----+ registered,
095: | |
096: | |----+
097: | +----+ wait in beforeTaskLoop
098: t1 ------------------------------------------------------------
099: | load abc.TestB2 |
100: | schedule abc.TestB2 --------->|
101: | |
102: |-----+ |
103: | | nextTask(WAIT_ON_EVENT) |
104: +-----+ |
105: t2 ------------------------------------------------------------
106: | | <--- release beforeTaskLoop lock
107: t3 ------------------------------------------------------------
108: | | loadClassLocally(abc.TestB2)
109: | |
110: | |
111: |<+---------- schedule abc.TestA -----|
112: | |-----+ nextTask
113: | | |
114: | +-----+
115: | |
116: | | loadClassLocally
117: |<+---------- schedule abc.TestA2-----| abc.TestB
118: | |
119: | |-----+
120: | | | nextTask
121: | +-----+ wait
122: | |
123: t4 -------------------- Dead-Lock ----------------------------
124: @throws Exception
125: */
126: public void testDeadLock() throws Exception {
127: log.info("RUNNING: testDeadLock");
128: File TestAclass = ClassMover
129: .move("org.jboss.test.classloader.test.abc.TestA");
130: File TestBclass = ClassMover
131: .move("org.jboss.test.classloader.test.abc.TestB");
132: File TestB2class = ClassMover
133: .move("org.jboss.test.classloader.test.abc.TestB2");
134:
135: /* Indicate that CL2 will wait after acquring the UCL registration monitor
136: and that the class its loading is TestB
137: */
138: blockingLoader = loaders[1];
139: blockname = "org.jboss.test.classloader.test.abc.TestB";
140: ClassLoader cl1 = loaders[0];
141: ClassLoader cl2 = loaders[1];
142: Runner t2 = new Runner("T2", blockname, cl2);
143: ThreadList threads = new ThreadList();
144: threads.add(t2);
145:
146: log.info("t0, Waiting for T2 to start");
147: t2.start();
148: Thread.sleep(2000);
149: log.info("t1, T2 should be waiting in beforeTaskLoop");
150:
151: /* Load B2 through T1/CL1 which requires CL2 held by T2
152: */
153: Runner t1 = new Runner("T1",
154: "org.jboss.test.classloader.test.abc.TestB2", cl1);
155: threads.add(t1);
156: log.info("t2, Waiting for T1 to start");
157: t1.start();
158: Thread.sleep(4000);
159: log.info("t3, Now releasing T2/CL2");
160: syncEvent.set();
161: log.info("t4, Waiting for T1, T2 to complete");
162: threads.waitAll();
163:
164: ClassMover.restore(TestAclass);
165: ClassMover.restore(TestBclass);
166: ClassMover.restore(TestB2class);
167: }
168:
169: /** Scenario:
170:
171: Thread T1 Thread T2
172: classLoader 1 [a.jar] classLoader 2 [b.jar]
173:
174: . .
175: t0 ------------------------------------------------------------
176: | | loadClass(abc.TestB)
177: | |----+
178: | +----+ registered,
179: | |
180: | |----+
181: | +----+ wait in beforeTaskLoop
182: t1 ------------------------------------------------------------
183: | load abc.TestB3 |
184: | schedule abc.TestB3 --------->|
185: | |
186: |-----+ |
187: | | nextTask(WAIT_ON_EVENT) |
188: +-----+ |
189: t2 ------------------------------------------------------------
190: | | <--- release beforeTaskLoop lock
191: t3 ------------------------------------------------------------
192: | | loadClassLocally(abc.TestB3)
193: | |
194: | |
195: |<+---------- schedule abc.TestA -----|
196: | loadClassLocally(abc.TestA) |
197: |-----+ |
198: | | nextTask(WAIT_ON_EVENT) |
199: +-----+ |
200: | | loadClassLocally(abc.TestB)
201: | | CCE(abc.TestA)
202: | |
203: | |-----+
204: | | | nextTask
205: | +-----+ wait(WAIT_ON_EVENT)
206: | |
207: t4 -------------------- Dead-Lock ----------------------------
208: @throws Exception
209: */
210: public void testDeadLockAndCircularity() throws Exception {
211: log.info("RUNNING: testDeadLockAndCircularity");
212: File TestAclass = ClassMover
213: .move("org.jboss.test.classloader.test.abc.TestA");
214: File TestBclass = ClassMover
215: .move("org.jboss.test.classloader.test.abc.TestB");
216: File TestB3class = ClassMover
217: .move("org.jboss.test.classloader.test.abc.TestB3");
218:
219: /* Indicate that CL2 will wait after acquring the UCL registration monitor
220: and that the class its loading is TestB
221: */
222: blockingLoader = loaders[1];
223: blockname = "org.jboss.test.classloader.test.abc.TestB";
224: ClassLoader cl1 = loaders[0];
225: ClassLoader cl2 = loaders[1];
226: Runner t2 = new Runner("T2", blockname, cl2);
227: ThreadList threads = new ThreadList();
228: threads.add(t2);
229: // Start t2 so that it blocks
230: log.info("t0, Waiting for T2 to start");
231: t2.start();
232: Thread.sleep(2000);
233: log.info("t1, T2 should be waiting in beforeTaskLoop");
234:
235: Runner t1 = new Runner("T1",
236: "org.jboss.test.classloader.test.abc.TestB3", cl1);
237: threads.add(t1);
238: log.info("t2, Waiting for T1 to start");
239: t1.start();
240: Thread.sleep(4000);
241: log.info("t3, Now releasing T2/CL2");
242: syncEvent.set();
243: threads.waitAll();
244:
245: ClassMover.restore(TestAclass);
246: ClassMover.restore(TestBclass);
247: ClassMover.restore(TestB3class);
248: }
249:
250: private class Runner extends Thread {
251: private String clsname;
252: private ClassLoader loader;
253:
254: public Runner(String name, String clsname, ClassLoader cl) {
255: super (name);
256: this .clsname = clsname;
257: this .loader = cl;
258: }
259:
260: private Throwable savedEx;
261:
262: public Throwable getThrowable() {
263: return savedEx;
264: }
265:
266: public void showException() {
267: if (savedEx != null) {
268: log.error("Exception for: " + getName(), savedEx);
269: }
270: }
271:
272: public void run() {
273: try {
274: Class cls = Class.forName(clsname, true, loader);
275: cls.newInstance();
276: } catch (Throwable ex) {
277: savedEx = ex;
278: }
279: }
280:
281: }
282:
283: public void beforeTaskLoop(UnifiedClassLoader3 cl, String clsname) {
284: log.info("BeforeTaskLoop: " + clsname);
285: if (cl == blockingLoader && clsname.equals(blockname)) {
286: log.info("Waiting in beforeTaskLoop: " + cl + " on "
287: + blockname);
288: try {
289: syncEvent.aquire();
290: } catch (InterruptedException e) {
291: log.error("Interrupted", e);
292: }
293: log.info("End beforeTaskLoop: " + cl);
294: }
295: }
296:
297: public class TestClassLoader extends UnifiedClassLoader3 {
298: public TestClassLoader(URL url, ClassLoader parent,
299: LoaderRepository repository) {
300: super (url, null, parent, null);
301: repository.addClassLoader(this );
302: }
303:
304: public synchronized Class loadClassImpl(String name,
305: boolean resolve) throws ClassNotFoundException {
306: boolean trace = log.isTraceEnabled();
307:
308: /* Since loadClass can be called from loadClassInternal with the monitor
309: already held, we need to determine if there is a ClassLoadingTask
310: which requires this UCL. If there is, we release the UCL monitor
311: so that the ClassLoadingTask can use the UCL.
312: */
313: boolean acquired = attempt(1);
314: while (acquired == false) {
315: /* Another thread needs this UCL to load a class so release the
316: monitor acquired by the synchronized method. We loop until
317: we can acquire the class loading lock.
318: */
319: try {
320: if (trace)
321: log.trace("Waiting for loadClass lock");
322: this .wait();
323: } catch (InterruptedException ignore) {
324: }
325: acquired = attempt(1);
326: }
327:
328: MyClassLoadingTask task = null;
329: try {
330: Thread t = Thread.currentThread();
331: // Register this thread as owning this UCL
332: if (loadLock.holds() == 1)
333: LoadMgr3.registerLoaderThread(this , t);
334: // Callout to cause blocking with UCL monitor held
335: beforeTaskLoop(name);
336:
337: // Create a class loading task and submit it to the repository
338: task = new MyClassLoadingTask(name, this , t);
339: /* Process class loading tasks needing this UCL until our task has
340: been completed by the thread owning the required UCL(s).
341: */
342: UnifiedLoaderRepository3 ulr3 = (UnifiedLoaderRepository3) repository;
343: if (LoadMgr3.beginLoadTask(task, ulr3) == false) {
344: while (task.threadTaskCount() != 0) {
345: try {
346: LoadMgr3.nextTask(t, task, ulr3);
347: } catch (InterruptedException e) {
348: // Abort the load or retry?
349: break;
350: }
351: }
352: }
353: } finally {
354: // Unregister as the UCL owner to reschedule any remaining load tasks
355: if (loadLock.holds() == 1)
356: LoadMgr3.endLoadTask(task);
357: // Notify any threads waiting to use this UCL
358: this .release();
359: this .notifyAll();
360: }
361:
362: if (task.loadedClass() == null) {
363: if (task.loadException() instanceof ClassNotFoundException)
364: throw (ClassNotFoundException) task.loadException();
365: else if (task.loadException() != null) {
366: if (log.isTraceEnabled())
367: log.trace("Unexpected error during load of:"
368: + name, task.loadException());
369: String msg = "Unexpected error during load of: "
370: + name + ", msg="
371: + task.loadException().getMessage();
372: throw new ClassNotFoundException(msg);
373: }
374: // Assert that loadedClass is not null
375: else
376: throw new IllegalStateException(
377: "ClassLoadingTask.loadedTask is null, name: "
378: + name);
379: }
380:
381: return task.loadedClass();
382: }
383:
384: protected void beforeTaskLoop(String clsname) {
385: log.info("Calling taskLoop");
386: DeadlockTests32.this .beforeTaskLoop(this , clsname);
387: }
388:
389: }
390:
391: private class ThreadList {
392: List list = new ArrayList();
393:
394: public ThreadList() {
395: }
396:
397: public void add(Thread t) {
398: list.add(t);
399: }
400:
401: public void waitAll() throws Exception {
402: Iterator it = list.iterator();
403: Throwable ex = null;
404: StringBuffer buf = new StringBuffer();
405: while (it.hasNext()) {
406: Runner t = (Runner) it.next();
407: t.join();
408: //t.showException();
409: Throwable e = t.getThrowable();
410: if (e != null) {
411: buf.append("Failure for: ").append(t.getName());
412: buf.append('\n').append(e);
413: if (ex == null) {
414: ex = e;
415: }
416: }
417: }
418: if (ex != null) {
419: log.info(buf.toString());
420: if (ex instanceof Exception) {
421: throw (Exception) ex;
422: } else if (ex instanceof Error) {
423: throw (Error) ex;
424: }
425: }
426: }
427:
428: }
429:
430: private class SyncEvent {
431: private boolean cond;
432:
433: public SyncEvent() {
434: this (false);
435: }
436:
437: public SyncEvent(boolean initialValue) {
438: cond = initialValue;
439: }
440:
441: public void aquire() throws InterruptedException {
442: synchronized (this ) {
443: while (!cond) {
444: wait();
445: }
446: }
447: }
448:
449: public synchronized void set() {
450: cond = true;
451: notifyAll();
452: }
453:
454: public synchronized void unset() {
455: cond = false;
456: }
457:
458: }
459: }
|