test/java/util/logging/DrainFindDeadlockTest.java
Print this page
*** 56,65 ****
--- 56,68 ----
private final static ThreadMXBean threadMXBean =
ManagementFactory.getThreadMXBean();
private final boolean threadMXBeanDeadlockSupported =
threadMXBean.isSynchronizerUsageSupported();
+ private volatile boolean terminate = false;
+ private volatile Exception failed = null;
+
public static void main(String... args) throws IOException, Exception {
new DrainFindDeadlockTest().testForDeadlock();
}
public static void randomDelay() {
*** 69,78 ****
--- 72,90 ----
for (int i=0; i<runs; ++i) {
c=c+i;
}
}
+ public void fail(Exception failure) {
+ if (failed == null) {
+ failed = failure;
+ } else {
+ failure.printStackTrace();
+ }
+ terminate = true;
+ }
+
public void testForDeadlock() throws IOException, Exception {
System.out.println("Deadlock detection "
+ (threadMXBeanDeadlockSupported ? "is" : "is not") +
" available.");
Thread setup = new Thread(new SetupLogger(), "SetupLogger");
*** 90,177 ****
try {
check.join();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
try {
readConfig.join();
setup.join();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
System.out.println("Test passed");
}
class SetupLogger implements Runnable {
Logger logger = null;
@Override
public void run() {
System.out.println("Running " + Thread.currentThread().getName());
!
! for (int i=0; i < MAX_ITERATIONS; i++) {
! logger = Logger.getLogger("DrainFindDeadlockTest"+i);
DrainFindDeadlockTest.randomDelay();
}
}
}
class ReadConfig implements Runnable {
@Override
public void run() {
System.out.println("Running " + Thread.currentThread().getName());
! for (int i=0; i < MAX_ITERATIONS; i++) {
try {
mgr.readConfiguration();
} catch (IOException | SecurityException ex) {
! throw new RuntimeException("FAILED: test setup problem", ex);
}
DrainFindDeadlockTest.randomDelay();
}
}
}
class DeadlockChecker implements Runnable {
! Thread t1, t2;
!
DeadlockChecker(Thread t1, Thread t2) {
! this.t1 = t1;
! this.t2 = t2;
}
! void checkState(Thread x, Thread y) {
// System.out.println("checkstate");
boolean isXblocked = x.getState().equals(State.BLOCKED);
boolean isYblocked = y.getState().equals(State.BLOCKED);
long[] deadlockedThreads = null;
if (isXblocked && isYblocked) {
System.out.println("threads blocked");
// they are both blocked, but this doesn't necessarily mean
// they are deadlocked
if (threadMXBeanDeadlockSupported) {
! System.out.println("checking for deadlock");
! deadlockedThreads = threadMXBean.findDeadlockedThreads();
} else {
System.out.println("Can't check for deadlock");
}
if (deadlockedThreads != null) {
System.out.println("We detected a deadlock! ");
ThreadInfo[] threadInfos = threadMXBean.getThreadInfo(
deadlockedThreads, true, true);
for (ThreadInfo threadInfo: threadInfos) {
! System.out.println(threadInfo);
}
! throw new RuntimeException("TEST FAILED: Deadlock detected");
}
System.out.println("We may have a deadlock");
Map<Thread, StackTraceElement[]> threadMap =
Thread.getAllStackTraces();
dumpStack(threadMap.get(x), x);
dumpStack(threadMap.get(y), y);
}
}
private void dumpStack(StackTraceElement[] aStackElt, Thread aThread) {
if (aStackElt != null) {
System.out.println("Thread:" + aThread.getName() + ": " +
aThread.getState());
--- 102,244 ----
try {
check.join();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
+
+ if (failed == null) {
+ terminate = true;
try {
readConfig.join();
setup.join();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
System.out.println("Test passed");
+ } else {
+ System.err.println("Test Failed: " + failed);
+ throw failed;
+ }
}
class SetupLogger implements Runnable {
Logger logger = null;
@Override
public void run() {
System.out.println("Running " + Thread.currentThread().getName());
! int i = 0;
! while (!terminate) {
! logger = Logger.getLogger("DrainFindDeadlockTest"+(i++));
DrainFindDeadlockTest.randomDelay();
}
}
}
class ReadConfig implements Runnable {
@Override
public void run() {
System.out.println("Running " + Thread.currentThread().getName());
! while (!terminate) {
try {
mgr.readConfiguration();
} catch (IOException | SecurityException ex) {
! fail(new RuntimeException("FAILED: test setup problem", ex));
}
DrainFindDeadlockTest.randomDelay();
}
}
}
class DeadlockChecker implements Runnable {
! final Thread x, y;
! final long[] threadIds;
DeadlockChecker(Thread t1, Thread t2) {
! this.x = t1;
! this.y = t2;
! threadIds = new long[] { t1.getId(), t2.getId() };
! }
!
! boolean threadsBlocked(ThreadInfo[] xyThreadInfos) {
! for (ThreadInfo threadInfo : xyThreadInfos) {
! switch (threadInfo.getThreadState()) {
! case BLOCKED:
! case WAITING:
! case TIMED_WAITING:
! continue;
! default:
! System.out.println("Thread " + threadInfo.getThreadName() +
! " is not blocked: " + threadInfo.getThreadState());
! return false;
! }
! }
! return xyThreadInfos.length > 0;
! }
!
! long[] findDeadlockedThreads() {
! // It seems that calling ThreadMXBean.findDeadlockedThreads()
! // is not always reliable. Until that is fixed we will only
! // call it if we find that our two threads are simultaneously
! // BLOCKED or WAITING.
! System.out.println("checking thread infos");
! ThreadInfo[] xyThreadInfos = threadMXBean.getThreadInfo(threadIds, true, true);
! if (!threadsBlocked(xyThreadInfos)) return null;
! /*
! if (xyThreadInfo != null && xyThreadInfos.length == 2) {
! if (xyThreadInfo[0].getLockOwnerId() != xyThreadInfo[1].getThreadId()) {
! return null;
! }
! if (xyThreadInfo[1].getLockOwnerId() != xyThreadInfo[0].getThreadId()) {
! return null;
! }
! }
! */
! System.out.println("checking for deadlock");
! long[] deadlockedThreads = threadMXBean.findDeadlockedThreads();
! if (deadlockedThreads != null) {
! xyThreadInfos = threadMXBean.getThreadInfo(deadlockedThreads, true, true);
! if (!threadsBlocked(xyThreadInfos)) return null;
! }
! return deadlockedThreads;
}
! void checkState() {
// System.out.println("checkstate");
boolean isXblocked = x.getState().equals(State.BLOCKED);
boolean isYblocked = y.getState().equals(State.BLOCKED);
long[] deadlockedThreads = null;
if (isXblocked && isYblocked) {
System.out.println("threads blocked");
// they are both blocked, but this doesn't necessarily mean
// they are deadlocked
if (threadMXBeanDeadlockSupported) {
! deadlockedThreads = findDeadlockedThreads();
} else {
System.out.println("Can't check for deadlock");
}
if (deadlockedThreads != null) {
System.out.println("We detected a deadlock! ");
ThreadInfo[] threadInfos = threadMXBean.getThreadInfo(
deadlockedThreads, true, true);
for (ThreadInfo threadInfo: threadInfos) {
! System.out.println("Thread " + threadInfo.getThreadName() + " blocked on " +
! threadInfo.getLockName() + " owned by " + threadInfo.getLockOwnerName());
}
! for (ThreadInfo threadInfo: threadInfos) {
! System.out.println(threadInfo);
}
+ fail(new RuntimeException("TEST FAILED: Deadlock detected"));
+ } else if (!threadMXBeanDeadlockSupported) {
System.out.println("We may have a deadlock");
Map<Thread, StackTraceElement[]> threadMap =
Thread.getAllStackTraces();
dumpStack(threadMap.get(x), x);
dumpStack(threadMap.get(y), y);
}
}
+ }
private void dumpStack(StackTraceElement[] aStackElt, Thread aThread) {
if (aStackElt != null) {
System.out.println("Thread:" + aThread.getName() + ": " +
aThread.getState());
*** 183,193 ****
@Override
public void run() {
System.out.println("Running " + Thread.currentThread().getName());
for (int i=0; i < MAX_ITERATIONS*2; i++) {
! checkState(t1, t2);
try {
Thread.sleep(10);
} catch (InterruptedException ex) {
};
}
--- 250,261 ----
@Override
public void run() {
System.out.println("Running " + Thread.currentThread().getName());
for (int i=0; i < MAX_ITERATIONS*2; i++) {
! if (terminate) return;
! checkState();
try {
Thread.sleep(10);
} catch (InterruptedException ex) {
};
}