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 27 public static void run() throws Exception { 28 System.out.println("Interrupt before start"); 29 testInterruptBeforeStart(); 30 31 System.out.println("Stop before start"); 32 testStopBeforeStart(); 33 34 System.out.println("Interrupt recur"); 35 testInterruptRecur(); 36 37 System.out.println("Stop Recur"); 38 testStopRecur(); 39 40 System.out.println("Interrupt spinning"); 41 testInterruptSpinning(); 42 43 System.out.println("Stop spinning"); 44 testStopSpinning(); 45 46 System.out.println("Interrupt wait"); 47 testInterruptWait(); 48 49 System.out.println("Stop wait"); 50 testStopWait(); 51 52 System.out.println("Stop in native"); 53 testStopInNative(); 54 } 55 56 public static void testStopBeforeStart() throws Exception { 57 final Throwable[] out_err = new Throwable[] { null, }; 58 final Object tst = new Object(); 59 Thread target = new Thread(() -> { while (true) { } }, "waiting thread!"); 60 target.setUncaughtExceptionHandler((t, e) -> { out_err[0] = e; }); 61 System.out.println("stopping other thread before starting"); 62 try { 63 Threads.stopThread(target, new Error("AWESOME")); 64 target.start(); 65 target.join(); 66 System.out.println("Other thread Stopped by: " + out_err[0]); 67 if (PRINT_STACK_TRACE && out_err[0] != null) { 68 out_err[0].printStackTrace(); 69 } 70 } catch (Exception e) { 71 System.out.println("Caught exception " + e); 72 } 73 } 74 75 public static void testInterruptBeforeStart() throws Exception { 76 final Throwable[] out_err = new Throwable[] { null, }; 77 final Object tst = new Object(); 78 Thread target = new Thread(() -> { while (true) { } }, "waiting thread!"); 79 target.setUncaughtExceptionHandler((t, e) -> { out_err[0] = e; }); 80 System.out.println("interrupting other thread before starting"); 81 try { 82 Threads.interruptThread(target); 83 target.start(); 84 target.join(); 85 System.out.println("Other thread interrupted. err: " + out_err[0]); 86 if (PRINT_STACK_TRACE && out_err[0] != null) { 87 out_err[0].printStackTrace(); 88 } 89 } catch (Exception e) { 90 System.out.println("Caught exception " + e); 91 } 92 } 93 94 public static void testStopWait() throws Exception { 95 final Throwable[] out_err = new Throwable[] { null, }; 96 final Object tst = new Object(); 97 final Semaphore sem = new Semaphore(0); 98 Thread target = new Thread(() -> { 99 sem.release(); 100 while (true) { 101 try { 102 synchronized (tst) { 103 tst.wait(); 104 } 105 } catch (InterruptedException e) { throw new Error("Interrupted!", e); } 106 } 107 }, "waiting thread!"); 108 target.setUncaughtExceptionHandler((t, e) -> { out_err[0] = e; }); 109 target.start(); 110 sem.acquire(); 111 while (!Objects.equals(Monitors.getCurrentContendedMonitor(target), tst)) {} 112 System.out.println("stopping other thread waiting"); 113 Threads.stopThread(target, new Error("AWESOME")); 114 target.join(); 115 System.out.println("Other thread Stopped by: " + out_err[0]); 116 if (PRINT_STACK_TRACE && out_err[0] != null) { 117 out_err[0].printStackTrace(); 118 } 119 } 120 121 public static void testInterruptWait() throws Exception { 122 final Throwable[] out_err = new Throwable[] { null, }; 123 final Object tst = new Object(); 124 final Semaphore sem = new Semaphore(0); 125 Thread target = new Thread(() -> { 126 sem.release(); 127 while (true) { 128 try { 129 synchronized (tst) { 130 tst.wait(); 131 } 132 } catch (InterruptedException e) { throw new Error("Interrupted!", e); } 133 } 134 }, "waiting thread!"); 135 target.setUncaughtExceptionHandler((t, e) -> { out_err[0] = e; }); 136 target.start(); 137 sem.acquire(); 138 while (!Objects.equals(Monitors.getCurrentContendedMonitor(target), tst)) {} 139 System.out.println("interrupting other thread waiting"); 140 Threads.interruptThread(target); 141 target.join(); 142 System.out.println("Other thread interrupted. err: " + out_err[0]); 143 if (PRINT_STACK_TRACE && out_err[0] != null) { 144 out_err[0].printStackTrace(); 145 } 146 } 147 148 public static void doNothing() {} 149 public static native long allocNativeMonitor(); 150 public static native void nativeWaitForOtherThread(long id); 151 public static native void nativeDoInterleaved(long id, Runnable op); 152 public static native void destroyNativeMonitor(long id); 153 public static void testStopInNative() throws Exception { 154 final Throwable[] out_err = new Throwable[] { null, }; 155 final long native_monitor_id = allocNativeMonitor(); 156 final Semaphore sem = new Semaphore(0); 157 Thread target = new Thread(() -> { 158 sem.release(); 159 nativeWaitForOtherThread(native_monitor_id); 160 // We need to make sure we do something that can get the exception to be actually noticed. 161 doNothing(); 162 }, "native waiting thread!"); 163 target.setUncaughtExceptionHandler((t, e) -> { out_err[0] = e; }); 164 target.start(); 165 sem.acquire(); 166 System.out.println("stopping other thread"); 167 nativeDoInterleaved( 168 native_monitor_id, 169 () -> { Threads.stopThread(target, new Error("AWESOME")); }); 170 target.join(); 171 172 String out_err_msg; 173 if (isDalvik || out_err[0] != null) { 174 out_err_msg = out_err[0].toString(); 175 } else { 176 // JVM appears to have a flaky bug with the native monitor wait, 177 // causing exception not to be handled about 10% of the time. 178 out_err_msg = "java.lang.Error: AWESOME"; 179 } 180 System.out.println("Other thread Stopped by: " + out_err_msg); 181 if (PRINT_STACK_TRACE && out_err[0] != null) { 182 out_err[0].printStackTrace(); 183 } 184 destroyNativeMonitor(native_monitor_id); 185 } 186 187 public static void doRecurCnt(Runnable r, int cnt) { 188 if (r != null) { 189 r.run(); 190 } 191 if (cnt != 0) { 192 doRecurCnt(r, cnt - 1); 193 } 194 } 195 196 public static void testStopRecur() throws Exception { 197 final Throwable[] out_err = new Throwable[] { null, }; 198 final Semaphore sem = new Semaphore(0); 199 Thread target = new Thread(() -> { 200 sem.release(); 201 while (true) { 202 doRecurCnt(null, 50); 203 } 204 }, "recuring thread!"); 205 target.setUncaughtExceptionHandler((t, e) -> { out_err[0] = e; }); 206 target.start(); 207 sem.acquire(); 208 System.out.println("stopping other thread recurring"); 209 Threads.stopThread(target, new Error("AWESOME!")); 210 target.join(); 211 System.out.println("Other thread Stopped by: " + out_err[0]); 212 if (PRINT_STACK_TRACE && out_err[0] != null) { 213 out_err[0].printStackTrace(); 214 } 215 } 216 217 public static void testInterruptRecur() throws Exception { 218 final Throwable[] out_err = new Throwable[] { null, }; 219 final Semaphore sem = new Semaphore(0); 220 Thread target = new Thread(() -> { 221 sem.release(); 222 while (true) { 223 doRecurCnt(() -> { 224 if (Thread.currentThread().isInterrupted()) { throw new Error("Interrupted!"); } 225 }, 50); 226 } 227 }, "recuring thread!"); 228 target.setUncaughtExceptionHandler((t, e) -> { out_err[0] = e; }); 229 target.start(); 230 sem.acquire(); 231 System.out.println("Interrupting other thread recurring"); 232 Threads.interruptThread(target); 233 target.join(); 234 System.out.println("Other thread Interrupted. err: " + out_err[0]); 235 if (PRINT_STACK_TRACE && out_err[0] != null) { 236 out_err[0].printStackTrace(); 237 } 238 } 239 240 public static void testStopSpinning() throws Exception { 241 final Throwable[] out_err = new Throwable[] { null, }; 242 final Semaphore sem = new Semaphore(0); 243 Thread target = new Thread(() -> { sem.release(); while (true) {} }, "Spinning thread!"); 244 target.setUncaughtExceptionHandler((t, e) -> { out_err[0] = e; }); 245 target.start(); 246 sem.acquire(); 247 System.out.println("stopping other thread spinning"); 248 Threads.stopThread(target, new Error("AWESOME!")); 249 target.join(); 250 System.out.println("Other thread Stopped by: " + out_err[0]); 251 if (PRINT_STACK_TRACE && out_err[0] != null) { 252 out_err[0].printStackTrace(); 253 } 254 } 255 256 public static void testInterruptSpinning() throws Exception { 257 final Semaphore sem = new Semaphore(0); 258 Thread target = new Thread(() -> { 259 sem.release(); 260 while (!Thread.currentThread().isInterrupted()) { } 261 }, "Spinning thread!"); 262 target.start(); 263 sem.acquire(); 264 System.out.println("Interrupting other thread spinning"); 265 Threads.interruptThread(target); 266 target.join(); 267 System.out.println("Other thread Interrupted."); 268 } 269 } 270