1*795d594fSAndroid Build Coastguard Worker /* 2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2017 The Android Open Source Project 3*795d594fSAndroid Build Coastguard Worker * 4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*795d594fSAndroid Build Coastguard Worker * 8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*795d594fSAndroid Build Coastguard Worker * 10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*795d594fSAndroid Build Coastguard Worker * limitations under the License. 15*795d594fSAndroid Build Coastguard Worker */ 16*795d594fSAndroid Build Coastguard Worker 17*795d594fSAndroid Build Coastguard Worker import java.lang.Thread.State; 18*795d594fSAndroid Build Coastguard Worker import java.lang.reflect.Method; 19*795d594fSAndroid Build Coastguard Worker import java.util.Arrays; 20*795d594fSAndroid Build Coastguard Worker import java.util.LinkedList; 21*795d594fSAndroid Build Coastguard Worker import java.util.List; 22*795d594fSAndroid Build Coastguard Worker import java.util.Map; 23*795d594fSAndroid Build Coastguard Worker import java.util.concurrent.BrokenBarrierException; 24*795d594fSAndroid Build Coastguard Worker import java.util.concurrent.CyclicBarrier; 25*795d594fSAndroid Build Coastguard Worker import java.util.concurrent.ForkJoinPool; 26*795d594fSAndroid Build Coastguard Worker 27*795d594fSAndroid Build Coastguard Worker public class Main { 28*795d594fSAndroid Build Coastguard Worker 29*795d594fSAndroid Build Coastguard Worker static class Runner implements Runnable { 30*795d594fSAndroid Build Coastguard Worker List<Object> locks; 31*795d594fSAndroid Build Coastguard Worker List<CyclicBarrier> barriers; 32*795d594fSAndroid Build Coastguard Worker Runner(List<Object> locks, List<CyclicBarrier> barriers)33*795d594fSAndroid Build Coastguard Worker public Runner(List<Object> locks, List<CyclicBarrier> barriers) { 34*795d594fSAndroid Build Coastguard Worker this.locks = locks; 35*795d594fSAndroid Build Coastguard Worker this.barriers = barriers; 36*795d594fSAndroid Build Coastguard Worker } 37*795d594fSAndroid Build Coastguard Worker 38*795d594fSAndroid Build Coastguard Worker @Override run()39*795d594fSAndroid Build Coastguard Worker public void run() { 40*795d594fSAndroid Build Coastguard Worker step(locks, barriers); 41*795d594fSAndroid Build Coastguard Worker } 42*795d594fSAndroid Build Coastguard Worker step(List<Object> l, List<CyclicBarrier> b)43*795d594fSAndroid Build Coastguard Worker private void step(List<Object> l, List<CyclicBarrier> b) { 44*795d594fSAndroid Build Coastguard Worker if (l.isEmpty()) { 45*795d594fSAndroid Build Coastguard Worker // Nothing to do, sleep indefinitely. 46*795d594fSAndroid Build Coastguard Worker try { 47*795d594fSAndroid Build Coastguard Worker Thread.sleep(100000000); 48*795d594fSAndroid Build Coastguard Worker } catch (InterruptedException e) { 49*795d594fSAndroid Build Coastguard Worker throw new RuntimeException(e); 50*795d594fSAndroid Build Coastguard Worker } 51*795d594fSAndroid Build Coastguard Worker } else { 52*795d594fSAndroid Build Coastguard Worker Object lockObject = l.remove(0); 53*795d594fSAndroid Build Coastguard Worker CyclicBarrier barrierObject = b.remove(0); 54*795d594fSAndroid Build Coastguard Worker 55*795d594fSAndroid Build Coastguard Worker if (lockObject == null) { 56*795d594fSAndroid Build Coastguard Worker // No lock object: only take barrier, recurse. 57*795d594fSAndroid Build Coastguard Worker try { 58*795d594fSAndroid Build Coastguard Worker barrierObject.await(); 59*795d594fSAndroid Build Coastguard Worker } catch (InterruptedException | BrokenBarrierException e) { 60*795d594fSAndroid Build Coastguard Worker throw new RuntimeException(e); 61*795d594fSAndroid Build Coastguard Worker } 62*795d594fSAndroid Build Coastguard Worker step(l, b); 63*795d594fSAndroid Build Coastguard Worker } else if (barrierObject != null) { 64*795d594fSAndroid Build Coastguard Worker // Have barrier: sync, wait and recurse. 65*795d594fSAndroid Build Coastguard Worker synchronized(lockObject) { 66*795d594fSAndroid Build Coastguard Worker try { 67*795d594fSAndroid Build Coastguard Worker barrierObject.await(); 68*795d594fSAndroid Build Coastguard Worker } catch (InterruptedException | BrokenBarrierException e) { 69*795d594fSAndroid Build Coastguard Worker throw new RuntimeException(e); 70*795d594fSAndroid Build Coastguard Worker } 71*795d594fSAndroid Build Coastguard Worker step(l, b); 72*795d594fSAndroid Build Coastguard Worker } 73*795d594fSAndroid Build Coastguard Worker } else { 74*795d594fSAndroid Build Coastguard Worker // Sync, and get next step (which is assumed to have object and barrier). 75*795d594fSAndroid Build Coastguard Worker synchronized (lockObject) { 76*795d594fSAndroid Build Coastguard Worker Object lockObject2 = l.remove(0); 77*795d594fSAndroid Build Coastguard Worker CyclicBarrier barrierObject2 = b.remove(0); 78*795d594fSAndroid Build Coastguard Worker synchronized(lockObject2) { 79*795d594fSAndroid Build Coastguard Worker try { 80*795d594fSAndroid Build Coastguard Worker barrierObject2.await(); 81*795d594fSAndroid Build Coastguard Worker } catch (InterruptedException | BrokenBarrierException e) { 82*795d594fSAndroid Build Coastguard Worker throw new RuntimeException(e); 83*795d594fSAndroid Build Coastguard Worker } 84*795d594fSAndroid Build Coastguard Worker step(l, b); 85*795d594fSAndroid Build Coastguard Worker } 86*795d594fSAndroid Build Coastguard Worker } 87*795d594fSAndroid Build Coastguard Worker } 88*795d594fSAndroid Build Coastguard Worker } 89*795d594fSAndroid Build Coastguard Worker } 90*795d594fSAndroid Build Coastguard Worker } 91*795d594fSAndroid Build Coastguard Worker main(String[] args)92*795d594fSAndroid Build Coastguard Worker public static void main(String[] args) throws Exception { 93*795d594fSAndroid Build Coastguard Worker // Eagerly initialize ForkJoinPool as we've seen the class initialization code interfere 94*795d594fSAndroid Build Coastguard Worker // with the logic of the test when waiting for threads to be non-runnable. 95*795d594fSAndroid Build Coastguard Worker Class.forName(ForkJoinPool.class.getName(), true, ForkJoinPool.class.getClassLoader()); 96*795d594fSAndroid Build Coastguard Worker try { 97*795d594fSAndroid Build Coastguard Worker testCluster1(); 98*795d594fSAndroid Build Coastguard Worker } catch (Exception e) { 99*795d594fSAndroid Build Coastguard Worker Map<Thread,StackTraceElement[]> stacks = Thread.getAllStackTraces(); 100*795d594fSAndroid Build Coastguard Worker for (Map.Entry<Thread,StackTraceElement[]> entry : stacks.entrySet()) { 101*795d594fSAndroid Build Coastguard Worker System.out.println(entry.getKey()); 102*795d594fSAndroid Build Coastguard Worker System.out.println(Arrays.toString(entry.getValue())); 103*795d594fSAndroid Build Coastguard Worker } 104*795d594fSAndroid Build Coastguard Worker throw e; 105*795d594fSAndroid Build Coastguard Worker } 106*795d594fSAndroid Build Coastguard Worker } 107*795d594fSAndroid Build Coastguard Worker testCluster1()108*795d594fSAndroid Build Coastguard Worker private static void testCluster1() throws Exception { 109*795d594fSAndroid Build Coastguard Worker // Test setup (at deadlock): 110*795d594fSAndroid Build Coastguard Worker // 111*795d594fSAndroid Build Coastguard Worker // Thread 1: 112*795d594fSAndroid Build Coastguard Worker // #0 step: synchornized(o3) { synchronized(o2) } 113*795d594fSAndroid Build Coastguard Worker // #1 step: synchronized(o1) 114*795d594fSAndroid Build Coastguard Worker // 115*795d594fSAndroid Build Coastguard Worker // Thread 2: 116*795d594fSAndroid Build Coastguard Worker // #0 step: synchronized(o1) 117*795d594fSAndroid Build Coastguard Worker // #1 step: synchronized(o4) { synchronized(o2) } 118*795d594fSAndroid Build Coastguard Worker // 119*795d594fSAndroid Build Coastguard Worker LinkedList<Object> l1 = new LinkedList<>(); 120*795d594fSAndroid Build Coastguard Worker LinkedList<CyclicBarrier> b1 = new LinkedList<>(); 121*795d594fSAndroid Build Coastguard Worker LinkedList<Object> l2 = new LinkedList<>(); 122*795d594fSAndroid Build Coastguard Worker LinkedList<CyclicBarrier> b2 = new LinkedList<>(); 123*795d594fSAndroid Build Coastguard Worker 124*795d594fSAndroid Build Coastguard Worker Object o1 = new Object(); 125*795d594fSAndroid Build Coastguard Worker Object o2 = new Object(); 126*795d594fSAndroid Build Coastguard Worker Object o3 = new Object(); 127*795d594fSAndroid Build Coastguard Worker Object o4 = new Object(); 128*795d594fSAndroid Build Coastguard Worker 129*795d594fSAndroid Build Coastguard Worker l1.add(o1); 130*795d594fSAndroid Build Coastguard Worker l1.add(o3); 131*795d594fSAndroid Build Coastguard Worker l1.add(o2); 132*795d594fSAndroid Build Coastguard Worker l2.add(o4); 133*795d594fSAndroid Build Coastguard Worker l2.add(o2); 134*795d594fSAndroid Build Coastguard Worker l2.add(o1); 135*795d594fSAndroid Build Coastguard Worker 136*795d594fSAndroid Build Coastguard Worker CyclicBarrier c1 = new CyclicBarrier(3); 137*795d594fSAndroid Build Coastguard Worker CyclicBarrier c2 = new CyclicBarrier(2); 138*795d594fSAndroid Build Coastguard Worker b1.add(c1); 139*795d594fSAndroid Build Coastguard Worker b1.add(null); 140*795d594fSAndroid Build Coastguard Worker b1.add(c2); 141*795d594fSAndroid Build Coastguard Worker b2.add(null); 142*795d594fSAndroid Build Coastguard Worker b2.add(c1); 143*795d594fSAndroid Build Coastguard Worker b2.add(c2); 144*795d594fSAndroid Build Coastguard Worker 145*795d594fSAndroid Build Coastguard Worker Thread t1 = new Thread(new Runner(l1, b1)); 146*795d594fSAndroid Build Coastguard Worker t1.setDaemon(true); 147*795d594fSAndroid Build Coastguard Worker t1.start(); 148*795d594fSAndroid Build Coastguard Worker Thread t2 = new Thread(new Runner(l2, b2)); 149*795d594fSAndroid Build Coastguard Worker t2.setDaemon(true); 150*795d594fSAndroid Build Coastguard Worker t2.start(); 151*795d594fSAndroid Build Coastguard Worker 152*795d594fSAndroid Build Coastguard Worker c1.await(); 153*795d594fSAndroid Build Coastguard Worker 154*795d594fSAndroid Build Coastguard Worker waitNotRunnable(t1); 155*795d594fSAndroid Build Coastguard Worker waitNotRunnable(t2); 156*795d594fSAndroid Build Coastguard Worker Thread.sleep(250); // Unfortunately this seems necessary. :-( 157*795d594fSAndroid Build Coastguard Worker 158*795d594fSAndroid Build Coastguard Worker // Thread 1. 159*795d594fSAndroid Build Coastguard Worker { 160*795d594fSAndroid Build Coastguard Worker Object[] stack1 = getAnnotatedStack(t1); 161*795d594fSAndroid Build Coastguard Worker assertBlockedOn(stack1[0], o2); // Blocked on o2. 162*795d594fSAndroid Build Coastguard Worker assertLocks(stack1[0], o3); // Locked o3. 163*795d594fSAndroid Build Coastguard Worker assertStackTraceElementStep(stack1[0]); 164*795d594fSAndroid Build Coastguard Worker 165*795d594fSAndroid Build Coastguard Worker assertBlockedOn(stack1[1], null); // Frame can't be blocked. 166*795d594fSAndroid Build Coastguard Worker assertLocks(stack1[1], o1); // Locked o1. 167*795d594fSAndroid Build Coastguard Worker assertStackTraceElementStep(stack1[1]); 168*795d594fSAndroid Build Coastguard Worker } 169*795d594fSAndroid Build Coastguard Worker 170*795d594fSAndroid Build Coastguard Worker // Thread 2. 171*795d594fSAndroid Build Coastguard Worker { 172*795d594fSAndroid Build Coastguard Worker Object[] stack2 = getAnnotatedStack(t2); 173*795d594fSAndroid Build Coastguard Worker assertBlockedOn(stack2[0], o1); // Blocked on o1. 174*795d594fSAndroid Build Coastguard Worker assertLocks(stack2[0]); // Nothing locked. 175*795d594fSAndroid Build Coastguard Worker assertStackTraceElementStep(stack2[0]); 176*795d594fSAndroid Build Coastguard Worker 177*795d594fSAndroid Build Coastguard Worker assertBlockedOn(stack2[1], null); // Frame can't be blocked. 178*795d594fSAndroid Build Coastguard Worker assertLocks(stack2[1], o4, o2); // Locked o4, o2. 179*795d594fSAndroid Build Coastguard Worker assertStackTraceElementStep(stack2[1]); 180*795d594fSAndroid Build Coastguard Worker } 181*795d594fSAndroid Build Coastguard Worker } 182*795d594fSAndroid Build Coastguard Worker waitNotRunnable(Thread t)183*795d594fSAndroid Build Coastguard Worker private static void waitNotRunnable(Thread t) throws InterruptedException { 184*795d594fSAndroid Build Coastguard Worker while (t.getState() == State.RUNNABLE) { 185*795d594fSAndroid Build Coastguard Worker Thread.sleep(100); 186*795d594fSAndroid Build Coastguard Worker } 187*795d594fSAndroid Build Coastguard Worker } 188*795d594fSAndroid Build Coastguard Worker getAnnotatedStack(Thread t)189*795d594fSAndroid Build Coastguard Worker private static Object[] getAnnotatedStack(Thread t) throws Exception { 190*795d594fSAndroid Build Coastguard Worker Class<?> vmStack = Class.forName("dalvik.system.VMStack"); 191*795d594fSAndroid Build Coastguard Worker Method m = vmStack.getDeclaredMethod("getAnnotatedThreadStackTrace", Thread.class); 192*795d594fSAndroid Build Coastguard Worker return (Object[]) m.invoke(null, t); 193*795d594fSAndroid Build Coastguard Worker } 194*795d594fSAndroid Build Coastguard Worker assertEquals(Object o1, Object o2)195*795d594fSAndroid Build Coastguard Worker private static void assertEquals(Object o1, Object o2) { 196*795d594fSAndroid Build Coastguard Worker if (o1 != o2) { 197*795d594fSAndroid Build Coastguard Worker throw new RuntimeException("Expected " + o1 + " == " + o2); 198*795d594fSAndroid Build Coastguard Worker } 199*795d594fSAndroid Build Coastguard Worker } assertLocks(Object fromTrace, Object... locks)200*795d594fSAndroid Build Coastguard Worker private static void assertLocks(Object fromTrace, Object... locks) throws Exception { 201*795d594fSAndroid Build Coastguard Worker Object fieldValue = fromTrace.getClass().getDeclaredMethod("getHeldLocks"). 202*795d594fSAndroid Build Coastguard Worker invoke(fromTrace); 203*795d594fSAndroid Build Coastguard Worker assertEquals((Object[]) fieldValue, 204*795d594fSAndroid Build Coastguard Worker (locks == null) ? null : (locks.length == 0 ? null : locks)); 205*795d594fSAndroid Build Coastguard Worker } assertBlockedOn(Object fromTrace, Object block)206*795d594fSAndroid Build Coastguard Worker private static void assertBlockedOn(Object fromTrace, Object block) throws Exception { 207*795d594fSAndroid Build Coastguard Worker Object fieldValue = fromTrace.getClass().getDeclaredMethod("getBlockedOn"). 208*795d594fSAndroid Build Coastguard Worker invoke(fromTrace); 209*795d594fSAndroid Build Coastguard Worker assertEquals(fieldValue, block); 210*795d594fSAndroid Build Coastguard Worker } assertEquals(Object[] o1, Object[] o2)211*795d594fSAndroid Build Coastguard Worker private static void assertEquals(Object[] o1, Object[] o2) { 212*795d594fSAndroid Build Coastguard Worker if (!Arrays.equals(o1, o2)) { 213*795d594fSAndroid Build Coastguard Worker throw new RuntimeException( 214*795d594fSAndroid Build Coastguard Worker "Expected " + Arrays.toString(o1) + " == " + Arrays.toString(o2)); 215*795d594fSAndroid Build Coastguard Worker } 216*795d594fSAndroid Build Coastguard Worker } assertStackTraceElementStep(Object o)217*795d594fSAndroid Build Coastguard Worker private static void assertStackTraceElementStep(Object o) throws Exception { 218*795d594fSAndroid Build Coastguard Worker Object fieldValue = o.getClass().getDeclaredMethod("getStackTraceElement").invoke(o); 219*795d594fSAndroid Build Coastguard Worker if (fieldValue instanceof StackTraceElement) { 220*795d594fSAndroid Build Coastguard Worker StackTraceElement elem = (StackTraceElement) fieldValue; 221*795d594fSAndroid Build Coastguard Worker if (!elem.getMethodName().equals("step")) { 222*795d594fSAndroid Build Coastguard Worker throw new RuntimeException("Expected step method"); 223*795d594fSAndroid Build Coastguard Worker } 224*795d594fSAndroid Build Coastguard Worker return; 225*795d594fSAndroid Build Coastguard Worker } 226*795d594fSAndroid Build Coastguard Worker throw new RuntimeException("Expected StackTraceElement " + fieldValue + " / " + o); 227*795d594fSAndroid Build Coastguard Worker } 228*795d594fSAndroid Build Coastguard Worker } 229*795d594fSAndroid Build Coastguard Worker 230