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.io.PrintWriter;
20 import java.io.StringWriter;
21 import java.lang.reflect.Executable;
22 import java.lang.reflect.Method;
23 import java.lang.reflect.Field;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Collection;
27 import java.util.HashSet;
28 import java.util.List;
29 import java.util.concurrent.Semaphore;
30 import java.util.Vector;
31 import java.util.function.Function;
32 import java.util.function.Predicate;
33 import java.util.function.Supplier;
34 import java.util.function.Consumer;
35 
36 public class Test1917 {
37   public final static boolean TEST_PRINT_ALL = false;
38 
39   public static class ThreadPauser implements Runnable {
40     public Semaphore sem_wakeup_main = new Semaphore(0);
41     public Semaphore sem_wait = new Semaphore(0);
42 
run()43     public void run() {
44       try {
45         sem_wakeup_main.release();
46         sem_wait.acquire();
47       } catch (Exception e) {
48         throw new Error("Error with semaphores!", e);
49       }
50     }
51 
waitForOtherThreadToPause()52     public void waitForOtherThreadToPause() throws Exception {
53       sem_wakeup_main.acquire();
54       while (!sem_wait.hasQueuedThreads()) {}
55     }
56 
wakeupOtherThread()57     public void wakeupOtherThread() throws Exception {
58       sem_wait.release();
59     }
60   }
61 
62   public static class StackTraceGenerator implements Runnable {
63     private final Thread thr;
64     private final Consumer<StackTrace.StackFrameData> con;
StackTraceGenerator(Thread thr, Consumer<StackTrace.StackFrameData> con)65     public StackTraceGenerator(Thread thr, Consumer<StackTrace.StackFrameData> con) {
66       this.thr = thr;
67       this.con = con;
68     }
69 
StackTraceGenerator(Consumer<StackTrace.StackFrameData> con)70     public StackTraceGenerator(Consumer<StackTrace.StackFrameData> con) {
71       this(null, con);
72     }
73 
getThread()74     public Thread getThread() {
75       if (thr == null) {
76         return Thread.currentThread();
77       } else {
78         return thr;
79       }
80     }
run()81     public void run() {
82       for (StackTrace.StackFrameData s : StackTrace.GetStackTrace(getThread())) {
83         con.accept(s);
84       }
85     }
86   }
87 
88   public static class RecurCount implements Runnable {
89     private final int cnt;
90     private final Runnable then;
RecurCount(int cnt, Runnable then)91     public RecurCount(int cnt, Runnable then) {
92       this.cnt = cnt;
93       this.then = then;
94     }
95 
run()96     public void run() {
97       doRecur(0);
98     }
99 
doRecur(int n)100     public void doRecur(int n) {
101       if (n < cnt) {
102         doRecur(n + 1);
103       } else {
104         then.run();
105       }
106     }
107   }
108 
makePrintStackFramesConsumer()109   public static Consumer<StackTrace.StackFrameData> makePrintStackFramesConsumer()
110       throws Exception {
111     final Method end_method = Test1917.class.getDeclaredMethod("run");
112     return new Consumer<StackTrace.StackFrameData>() {
113       public void accept(StackTrace.StackFrameData data) {
114         if (TEST_PRINT_ALL) {
115           System.out.println(data);
116         } else {
117           Package p = data.method.getDeclaringClass().getPackage();
118           // Filter out anything to do with the testing harness.
119           if (p != null && p.equals(Test1917.class.getPackage())) {
120             System.out.printf("'%s' line: %d\n",
121                 data.method,
122                 Breakpoint.locationToLine(data.method, data.current_location));
123           } else if (data.method.getDeclaringClass().equals(Semaphore.class)) {
124             System.out.printf("'%s' line: <NOT-DETERMINISTIC>\n", data.method);
125           }
126         }
127       }
128     };
129   }
130 
131   public static void run() throws Exception {
132     System.out.println("Recurring 5 times");
133     new RecurCount(5, new StackTraceGenerator(makePrintStackFramesConsumer())).run();
134 
135     System.out.println("Recurring 5 times on another thread");
136     Thread thr = new Thread(
137         Thread.currentThread().getThreadGroup(),
138         new RecurCount(5, new StackTraceGenerator(makePrintStackFramesConsumer())),
139         "Recurring Thread 1",
140         10*1000000 /* 10 mb*/);
141     thr.start();
142     thr.join();
143 
144     System.out.println("Recurring 5 times on another thread. Stack trace from main thread!");
145     ThreadPauser pause = new ThreadPauser();
146     Thread thr2 = new Thread(
147         Thread.currentThread().getThreadGroup(),
148         new RecurCount(5, pause),
149         "Recurring Thread 2",
150         10*1000000 /* 10 mb*/);
151     thr2.start();
152     pause.waitForOtherThreadToPause();
153     new StackTraceGenerator(thr2, makePrintStackFramesConsumer()).run();
154     pause.wakeupOtherThread();
155     thr2.join();
156   }
157 }
158