1 /* 2 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package jdk.testlibrary; 25 26 import java.lang.management.ManagementFactory; 27 import java.lang.management.ThreadInfo; 28 import java.lang.management.ThreadMXBean; 29 import java.util.concurrent.TimeoutException; 30 31 /** 32 * Thread which catches exceptions thrown during the execution 33 * and stores them for later analysis. 34 * 35 * <pre> 36 * {@code 37 * TestThread thread = new TestThread(new XRun() { 38 * public void run() { 39 * // do something 40 * } 41 * }); 42 * thread.start(); 43 * // do something 44 * Throwable uncaught = thread.getUncaught(); 45 * } 46 * </pre> 47 */ 48 public class TestThread extends Thread { 49 50 private final Runnable runnable; 51 private volatile Throwable uncaught; 52 53 /** 54 * Returns {@link Runnable} the thread has been created with. 55 * 56 * @return The object whose {@code run} method is called 57 */ 58 public Runnable getRunnable() { 59 return runnable; 60 } 61 62 /** 63 * Creates a new {@code TestThread} object. 64 * 65 * @param target The object whose {@code run} method is called 66 * @param name The thread name 67 */ 68 public TestThread(Runnable target, String name) { 69 super(target, name); 70 this.runnable = target; 71 } 72 73 /** 74 * Creates a new {@code TestThread} object. 75 * 76 * @param target The object whose {@code run} method is called 77 */ 78 public TestThread(Runnable target) { 79 super(target); 80 this.runnable = target; 81 } 82 83 /** 84 * Creates a new {@code TestThread} object. 85 * 86 * @param group The thread group 87 * @param target The object whose {@code run} method is called 88 * @param name The thread name 89 * @param stackSize Stack size 90 */ 91 public TestThread(ThreadGroup group, Runnable target, String name, 92 long stackSize) { 93 super(group, target, name, stackSize); 94 this.runnable = target; 95 } 96 97 /** 98 * Creates a new {@code TestThread} object. 99 * 100 * @param group The thread group 101 * @param target The object whose {@code run} method is called 102 * @param name The thread name 103 */ 104 public TestThread(ThreadGroup group, Runnable target, String name) { 105 super(group, target, name); 106 this.runnable = target; 107 } 108 109 /** 110 * Creates a new {@code TestThread} object. 111 * 112 * @param group The thread group 113 * @param target The object whose {@code run} method is called 114 */ 115 public TestThread(ThreadGroup group, Runnable target) { 116 super(group, target); 117 this.runnable = target; 118 } 119 120 /** 121 * The thread executor. 122 */ 123 @Override 124 public void run() { 125 try { 126 super.run(); 127 } catch (Throwable t) { 128 uncaught = t; 129 } 130 } 131 132 /** 133 * Returns exception caught during the execution. 134 * 135 * @return {@link Throwable} 136 */ 137 public Throwable getUncaught() { 138 return uncaught; 139 } 140 141 /** 142 * Waits for {@link TestThread} to die 143 * and throws exception caught during the execution. 144 * 145 * @throws InterruptedException 146 * @throws Throwable 147 */ 148 public void joinAndThrow() throws InterruptedException, Throwable { 149 join(); 150 if (uncaught != null) { 151 throw uncaught; 152 } 153 } 154 155 /** 156 * Waits during {@code timeout} for {@link TestThread} to die 157 * and throws exception caught during the execution. 158 * 159 * @param timeout The time to wait in milliseconds 160 * @throws InterruptedException 161 * @throws Throwable 162 */ 163 public void joinAndThrow(long timeout) throws InterruptedException, 164 Throwable { 165 join(timeout); 166 if (isAlive()) { 167 throw new TimeoutException(); 168 } 169 if (uncaught != null) { 170 throw uncaught; 171 } 172 } 173 174 /** 175 * Waits for {@link TestThread} to die 176 * and returns exception caught during the execution. 177 * 178 * @return Exception caught during the execution 179 * @throws InterruptedException 180 */ 181 public Throwable joinAndReturn() throws InterruptedException { 182 join(); 183 if (uncaught != null) { 184 return uncaught; 185 } 186 return null; 187 } 188 189 /** 190 * Waits during {@code timeout} for {@link TestThread} to die 191 * and returns exception caught during the execution. 192 * 193 * @param timeout The time to wait in milliseconds 194 * @return Exception caught during the execution 195 * @throws InterruptedException 196 */ 197 public Throwable joinAndReturn(long timeout) throws InterruptedException { 198 join(timeout); 199 if (isAlive()) { 200 return new TimeoutException(); 201 } 202 if (uncaught != null) { 203 return uncaught; 204 } 205 return null; 206 } 207 208 /** 209 * Waits until {@link TestThread} is in the certain {@link State} 210 * and blocking on {@code object}. 211 * 212 * @param state The thread state 213 * @param object The object to block on 214 */ 215 public void waitUntilBlockingOnObject(Thread.State state, Object object) { 216 String want = object == null ? null : object.getClass().getName() + '@' 217 + Integer.toHexString(System.identityHashCode(object)); 218 ThreadMXBean tmx = ManagementFactory.getThreadMXBean(); 219 while (isAlive()) { 220 ThreadInfo ti = tmx.getThreadInfo(getId()); 221 if (ti.getThreadState() == state 222 && (want == null || want.equals(ti.getLockName()))) { 223 return; 224 } 225 try { 226 Thread.sleep(1); 227 } catch (InterruptedException e) { 228 } 229 } 230 } 231 232 /** 233 * Waits until {@link TestThread} is in native. 234 */ 235 public void waitUntilInNative() { 236 ThreadMXBean tmx = ManagementFactory.getThreadMXBean(); 237 while (isAlive()) { 238 ThreadInfo ti = tmx.getThreadInfo(getId()); 239 if (ti.isInNative()) { 240 return; 241 } 242 try { 243 Thread.sleep(1); 244 } catch (InterruptedException e) { 245 } 246 } 247 } 248 249 }