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