1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package art; 18 19 import java.util.concurrent.Semaphore; 20 import java.util.Objects; 21 22 public class Test1934 { 23 private final static boolean isDalvik = System.getProperty("java.vm.name").equals("Dalvik"); 24 25 public static final boolean PRINT_STACK_TRACE = false; 26 run()27 public static void run() throws Exception { 28 ensureClassesLoaded(); 29 30 System.out.println("Interrupt before start"); 31 testInterruptBeforeStart(); 32 33 System.out.println("Stop before start"); 34 testStopBeforeStart(); 35 36 System.out.println("Interrupt recur"); 37 testInterruptRecur(); 38 39 System.out.println("Stop Recur"); 40 testStopRecur(); 41 42 System.out.println("Interrupt spinning"); 43 testInterruptSpinning(); 44 45 System.out.println("Stop spinning"); 46 testStopSpinning(); 47 48 System.out.println("Interrupt wait"); 49 testInterruptWait(); 50 51 System.out.println("Stop wait"); 52 testStopWait(); 53 54 System.out.println("Stop in native"); 55 testStopInNative(); 56 } 57 ensureInitialized(Class c)58 private static void ensureInitialized(Class c) { 59 try { 60 Class.forName(c.getName()); 61 } catch (Exception e) { 62 throw new Error("Failed to initialize " + c, e); 63 } 64 } 65 ensureClassesLoaded()66 private static void ensureClassesLoaded() { 67 // Depending on timing this class might (or might not) be loaded during testing of Stop. If it 68 // is and the StopThread occurs inside of it we will get a ExceptionInInitializerError which is 69 // not what we are looking for. In order to avoid this ever happening simply initialize the 70 // class that can cause it early. 71 ensureInitialized(java.util.concurrent.locks.LockSupport.class); 72 } 73 createThread(Runnable r, String name)74 public static Thread createThread(Runnable r, String name) { 75 return new Thread(Thread.currentThread().getThreadGroup(), r, name, /* 10 mb */ 10 * 1000000); 76 } 77 testStopBeforeStart()78 public static void testStopBeforeStart() throws Exception { 79 final Throwable[] out_err = new Throwable[] { null, }; 80 final Object tst = new Object(); 81 Thread target = createThread(() -> { while (true) { } }, "waiting thread!"); 82 target.setUncaughtExceptionHandler((t, e) -> { out_err[0] = e; }); 83 System.out.println("stopping other thread before starting"); 84 try { 85 Threads.stopThread(target, new Error("AWESOME")); 86 target.start(); 87 target.join(); 88 System.out.println("Other thread Stopped by: " + out_err[0]); 89 if (PRINT_STACK_TRACE && out_err[0] != null) { 90 out_err[0].printStackTrace(); 91 } 92 } catch (Exception e) { 93 System.out.println("Caught exception " + e); 94 } 95 } 96 testInterruptBeforeStart()97 public static void testInterruptBeforeStart() throws Exception { 98 final Throwable[] out_err = new Throwable[] { null, }; 99 final Object tst = new Object(); 100 Thread target = createThread(() -> { while (true) { } }, "waiting thread!"); 101 target.setUncaughtExceptionHandler((t, e) -> { out_err[0] = e; }); 102 System.out.println("interrupting other thread before starting"); 103 try { 104 Threads.interruptThread(target); 105 target.start(); 106 target.join(); 107 System.out.println("Other thread interrupted. err: " + out_err[0]); 108 if (PRINT_STACK_TRACE && out_err[0] != null) { 109 out_err[0].printStackTrace(); 110 } 111 } catch (Exception e) { 112 System.out.println("Caught exception " + e); 113 } 114 } 115 testStopWait()116 public static void testStopWait() throws Exception { 117 final Throwable[] out_err = new Throwable[] { null, }; 118 final Object tst = new Object(); 119 final Semaphore sem = new Semaphore(0); 120 Thread target = createThread(() -> { 121 sem.release(); 122 while (true) { 123 try { 124 synchronized (tst) { 125 tst.wait(); 126 } 127 } catch (InterruptedException e) { throw new Error("Interrupted!", e); } 128 } 129 }, "waiting thread!"); 130 target.setUncaughtExceptionHandler((t, e) -> { out_err[0] = e; }); 131 target.start(); 132 sem.acquire(); 133 while (!Objects.equals(Monitors.getCurrentContendedMonitor(target), tst)) {} 134 System.out.println("stopping other thread waiting"); 135 Threads.stopThread(target, new Error("AWESOME")); 136 target.join(); 137 System.out.println("Other thread Stopped by: " + out_err[0]); 138 if (PRINT_STACK_TRACE && out_err[0] != null) { 139 out_err[0].printStackTrace(); 140 } 141 } 142 testInterruptWait()143 public static void testInterruptWait() throws Exception { 144 final Throwable[] out_err = new Throwable[] { null, }; 145 final Object tst = new Object(); 146 final Semaphore sem = new Semaphore(0); 147 Thread target = createThread(() -> { 148 sem.release(); 149 while (true) { 150 try { 151 synchronized (tst) { 152 tst.wait(); 153 } 154 } catch (InterruptedException e) { throw new Error("Interrupted!", e); } 155 } 156 }, "waiting thread!"); 157 target.setUncaughtExceptionHandler((t, e) -> { out_err[0] = e; }); 158 target.start(); 159 sem.acquire(); 160 while (!Objects.equals(Monitors.getCurrentContendedMonitor(target), tst)) {} 161 System.out.println("interrupting other thread waiting"); 162 Threads.interruptThread(target); 163 target.join(); 164 System.out.println("Other thread interrupted. err: " + out_err[0]); 165 if (PRINT_STACK_TRACE && out_err[0] != null) { 166 out_err[0].printStackTrace(); 167 } 168 } 169 doNothing()170 public static void doNothing() {} allocNativeMonitor()171 public static native long allocNativeMonitor(); nativeWaitForOtherThread(long id)172 public static native void nativeWaitForOtherThread(long id); nativeDoInterleaved(long id, Runnable op)173 public static native void nativeDoInterleaved(long id, Runnable op); destroyNativeMonitor(long id)174 public static native void destroyNativeMonitor(long id); testStopInNative()175 public static void testStopInNative() throws Exception { 176 final Throwable[] out_err = new Throwable[] { null, }; 177 final long native_monitor_id = allocNativeMonitor(); 178 final Semaphore sem = new Semaphore(0); 179 Thread target = createThread(() -> { 180 sem.release(); 181 nativeWaitForOtherThread(native_monitor_id); 182 // We need to make sure we do something that can get the exception to be actually noticed. 183 doNothing(); 184 }, "native waiting thread!"); 185 target.setUncaughtExceptionHandler((t, e) -> { out_err[0] = e; }); 186 target.start(); 187 sem.acquire(); 188 System.out.println("stopping other thread"); 189 nativeDoInterleaved( 190 native_monitor_id, 191 () -> { Threads.stopThread(target, new Error("AWESOME")); }); 192 target.join(); 193 194 String out_err_msg; 195 if (isDalvik || out_err[0] != null) { 196 out_err_msg = out_err[0].toString(); 197 } else { 198 // JVM appears to have a flaky bug with the native monitor wait, 199 // causing exception not to be handled about 10% of the time. 200 out_err_msg = "java.lang.Error: AWESOME"; 201 } 202 System.out.println("Other thread Stopped by: " + out_err_msg); 203 if (PRINT_STACK_TRACE && out_err[0] != null) { 204 out_err[0].printStackTrace(); 205 } 206 destroyNativeMonitor(native_monitor_id); 207 } 208 doRecurCnt(Runnable r, int cnt)209 public static void doRecurCnt(Runnable r, int cnt) { 210 if (r != null) { 211 r.run(); 212 } 213 if (cnt != 0) { 214 doRecurCnt(r, cnt - 1); 215 } 216 } 217 testStopRecur()218 public static void testStopRecur() throws Exception { 219 final Throwable[] out_err = new Throwable[] { null, }; 220 final Semaphore sem = new Semaphore(0); 221 Thread target = createThread(() -> { 222 sem.release(); 223 while (true) { 224 doRecurCnt(null, 50); 225 } 226 }, "recuring thread!"); 227 target.setUncaughtExceptionHandler((t, e) -> { out_err[0] = e; }); 228 target.start(); 229 sem.acquire(); 230 System.out.println("stopping other thread recurring"); 231 Threads.stopThread(target, new Error("AWESOME!")); 232 target.join(); 233 System.out.println("Other thread Stopped by: " + out_err[0]); 234 if (PRINT_STACK_TRACE && out_err[0] != null) { 235 out_err[0].printStackTrace(); 236 } 237 } 238 testInterruptRecur()239 public static void testInterruptRecur() throws Exception { 240 final Throwable[] out_err = new Throwable[] { null, }; 241 final Semaphore sem = new Semaphore(0); 242 Thread target = createThread(() -> { 243 sem.release(); 244 while (true) { 245 doRecurCnt(() -> { 246 if (Thread.currentThread().isInterrupted()) { throw new Error("Interrupted!"); } 247 }, 50); 248 } 249 }, "recuring thread!"); 250 target.setUncaughtExceptionHandler((t, e) -> { out_err[0] = e; }); 251 target.start(); 252 sem.acquire(); 253 System.out.println("Interrupting other thread recurring"); 254 Threads.interruptThread(target); 255 target.join(); 256 System.out.println("Other thread Interrupted. err: " + out_err[0]); 257 if (PRINT_STACK_TRACE && out_err[0] != null) { 258 out_err[0].printStackTrace(); 259 } 260 } 261 testStopSpinning()262 public static void testStopSpinning() throws Exception { 263 final Throwable[] out_err = new Throwable[] { null, }; 264 final Semaphore sem = new Semaphore(0); 265 Thread target = createThread(() -> { sem.release(); while (true) {} }, "Spinning thread!"); 266 target.setUncaughtExceptionHandler((t, e) -> { out_err[0] = e; }); 267 target.start(); 268 sem.acquire(); 269 System.out.println("stopping other thread spinning"); 270 Threads.stopThread(target, new Error("AWESOME!")); 271 target.join(); 272 System.out.println("Other thread Stopped by: " + out_err[0]); 273 if (PRINT_STACK_TRACE && out_err[0] != null) { 274 out_err[0].printStackTrace(); 275 } 276 } 277 testInterruptSpinning()278 public static void testInterruptSpinning() throws Exception { 279 final Semaphore sem = new Semaphore(0); 280 Thread target = createThread(() -> { 281 sem.release(); 282 while (!Thread.currentThread().isInterrupted()) { } 283 }, "Spinning thread!"); 284 target.start(); 285 sem.acquire(); 286 System.out.println("Interrupting other thread spinning"); 287 Threads.interruptThread(target); 288 target.join(); 289 System.out.println("Other thread Interrupted."); 290 } 291 } 292