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