xref: /aosp_15_r20/art/test/168-vmstack-annotated/src/Main.java (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
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