blob: 29c4aa330c3f8464f8a6351a693a735a1a6a7b2a [file] [log] [blame]
Andreas Gampeaf13ab92017-01-11 20:57:40 -08001/*
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
17import java.util.Arrays;
Andreas Gampe72c19832017-01-12 13:22:16 -080018import java.util.ArrayList;
19import java.util.Collections;
Andreas Gampe85807442017-01-13 14:40:58 -080020import java.util.Comparator;
Andreas Gampe72c19832017-01-12 13:22:16 -080021import java.util.concurrent.CountDownLatch;
22import java.util.HashMap;
23import java.util.List;
24import java.util.Map;
Andreas Gampeaf13ab92017-01-11 20:57:40 -080025
26public class Main {
27 public static void main(String[] args) throws Exception {
Andreas Gampeaf13ab92017-01-11 20:57:40 -080028 doTest();
29 }
30
31 private static void doTest() throws Exception {
32 Thread t1 = Thread.currentThread();
33 Thread t2 = getCurrentThread();
34
35 if (t1 != t2) {
36 throw new RuntimeException("Expected " + t1 + " but got " + t2);
37 }
38 System.out.println("currentThread OK");
39
40 printThreadInfo(t1);
41 printThreadInfo(null);
42
43 Thread t3 = new Thread("Daemon Thread");
44 t3.setDaemon(true);
45 // Do not start this thread, yet.
46 printThreadInfo(t3);
47 // Start, and wait for it to die.
48 t3.start();
49 t3.join();
Andreas Gampe72c19832017-01-12 13:22:16 -080050 Thread.sleep(500); // Wait a little bit.
Andreas Gampeaf13ab92017-01-11 20:57:40 -080051 // Thread has died, check that we can still get info.
52 printThreadInfo(t3);
Andreas Gampe72c19832017-01-12 13:22:16 -080053
54 doStateTests();
Andreas Gampe85807442017-01-13 14:40:58 -080055
56 doAllThreadsTests();
Andreas Gampe7b3b3262017-01-19 20:40:42 -080057
58 doTLSTests();
Andreas Gampeeafaf572017-01-20 12:34:15 -080059
60 doTestEvents();
Andreas Gampe72c19832017-01-12 13:22:16 -080061 }
62
63 private static class Holder {
64 volatile boolean flag = false;
65 }
66
67 private static void doStateTests() throws Exception {
68 System.out.println(Integer.toHexString(getThreadState(null)));
69 System.out.println(Integer.toHexString(getThreadState(Thread.currentThread())));
70
71 final CountDownLatch cdl1 = new CountDownLatch(1);
72 final CountDownLatch cdl2 = new CountDownLatch(1);
73 final CountDownLatch cdl3_1 = new CountDownLatch(1);
74 final CountDownLatch cdl3_2 = new CountDownLatch(1);
75 final CountDownLatch cdl4 = new CountDownLatch(1);
76 final CountDownLatch cdl5 = new CountDownLatch(1);
77 final Holder h = new Holder();
78 Runnable r = new Runnable() {
79 @Override
80 public void run() {
81 try {
82 cdl1.countDown();
83 synchronized(cdl1) {
84 cdl1.wait();
85 }
86
87 cdl2.countDown();
88 synchronized(cdl2) {
89 cdl2.wait(1000); // Wait a second.
90 }
91
92 cdl3_1.await();
93 cdl3_2.countDown();
94 synchronized(cdl3_2) {
95 // Nothing, just wanted to block on cdl3.
96 }
97
98 cdl4.countDown();
99 Thread.sleep(1000);
100
101 cdl5.countDown();
102 while (!h.flag) {
103 // Busy-loop.
104 }
105 } catch (Exception e) {
106 throw new RuntimeException(e);
107 }
108 }
109 };
110
111 Thread t = new Thread(r);
112 printThreadState(t);
113 t.start();
114
115 // Waiting.
116 cdl1.await();
117 Thread.yield();
118 Thread.sleep(100);
119 printThreadState(t);
120 synchronized(cdl1) {
121 cdl1.notifyAll();
122 }
123
124 // Timed waiting.
125 cdl2.await();
126 Thread.yield();
127 Thread.sleep(100);
128 printThreadState(t);
129 synchronized(cdl2) {
130 cdl2.notifyAll();
131 }
132
133 // Blocked on monitor.
134 synchronized(cdl3_2) {
135 cdl3_1.countDown();
136 cdl3_2.await();
137 Thread.yield();
138 Thread.sleep(100);
139 printThreadState(t);
140 }
141
142 // Sleeping.
143 cdl4.await();
144 Thread.yield();
145 Thread.sleep(100);
146 printThreadState(t);
147
148 // Running.
149 cdl5.await();
150 Thread.yield();
151 Thread.sleep(100);
152 printThreadState(t);
153 h.flag = true;
154
155 // Dying.
156 t.join();
157 Thread.yield();
158 Thread.sleep(100);
159
160 printThreadState(t);
161 }
162
Andreas Gampe85807442017-01-13 14:40:58 -0800163 private static void doAllThreadsTests() {
164 Thread[] threads = getAllThreads();
165 Arrays.sort(threads, THREAD_COMP);
166 System.out.println(Arrays.toString(threads));
167 }
168
Andreas Gampe7b3b3262017-01-19 20:40:42 -0800169 private static void doTLSTests() throws Exception {
170 doTLSNonLiveTests();
171 doTLSLiveTests();
172 }
173
174 private static void doTLSNonLiveTests() throws Exception {
175 Thread t = new Thread();
176 try {
177 setTLS(t, 1);
178 System.out.println("Expected failure setting TLS for non-live thread");
179 } catch (Exception e) {
180 System.out.println(e.getMessage());
181 }
182 t.start();
183 t.join();
184 try {
185 setTLS(t, 1);
186 System.out.println("Expected failure setting TLS for non-live thread");
187 } catch (Exception e) {
188 System.out.println(e.getMessage());
189 }
190 }
191
192 private static void doTLSLiveTests() throws Exception {
193 setTLS(Thread.currentThread(), 1);
194
195 long l = getTLS(Thread.currentThread());
196 if (l != 1) {
197 throw new RuntimeException("Unexpected TLS value: " + l);
198 };
199
200 final CountDownLatch cdl1 = new CountDownLatch(1);
201 final CountDownLatch cdl2 = new CountDownLatch(1);
202
203 Runnable r = new Runnable() {
204 @Override
205 public void run() {
206 try {
207 cdl1.countDown();
208 cdl2.await();
209 setTLS(Thread.currentThread(), 2);
210 if (getTLS(Thread.currentThread()) != 2) {
211 throw new RuntimeException("Different thread issue");
212 }
213 } catch (Exception e) {
214 throw new RuntimeException(e);
215 }
216 }
217 };
218
219 Thread t = new Thread(r);
220 t.start();
221 cdl1.await();
222 setTLS(Thread.currentThread(), 1);
223 cdl2.countDown();
224
225 t.join();
226 if (getTLS(Thread.currentThread()) != 1) {
227 throw new RuntimeException("Got clobbered");
228 }
229 }
230
Andreas Gampeeafaf572017-01-20 12:34:15 -0800231 private static void doTestEvents() throws Exception {
232 enableThreadEvents(true);
233
234 Thread t = new Thread("EventTestThread");
235
236 System.out.println("Constructed thread");
237 Thread.yield();
238
239 t.start();
240 t.join();
241
242 System.out.println("Thread joined");
243
244 enableThreadEvents(false);
245 }
246
Andreas Gampe85807442017-01-13 14:40:58 -0800247 private final static Comparator<Thread> THREAD_COMP = new Comparator<Thread>() {
248 public int compare(Thread o1, Thread o2) {
249 return o1.getName().compareTo(o2.getName());
250 }
251 };
252
Andreas Gampe72c19832017-01-12 13:22:16 -0800253 private final static Map<Integer, String> STATE_NAMES = new HashMap<Integer, String>();
254 private final static List<Integer> STATE_KEYS = new ArrayList<Integer>();
255 static {
256 STATE_NAMES.put(0x1, "ALIVE");
257 STATE_NAMES.put(0x2, "TERMINATED");
258 STATE_NAMES.put(0x4, "RUNNABLE");
259 STATE_NAMES.put(0x400, "BLOCKED_ON_MONITOR_ENTER");
260 STATE_NAMES.put(0x80, "WAITING");
261 STATE_NAMES.put(0x10, "WAITING_INDEFINITELY");
262 STATE_NAMES.put(0x20, "WAITING_WITH_TIMEOUT");
263 STATE_NAMES.put(0x40, "SLEEPING");
264 STATE_NAMES.put(0x100, "IN_OBJECT_WAIT");
265 STATE_NAMES.put(0x200, "PARKED");
266 STATE_NAMES.put(0x100000, "SUSPENDED");
267 STATE_NAMES.put(0x200000, "INTERRUPTED");
268 STATE_NAMES.put(0x400000, "IN_NATIVE");
269 STATE_KEYS.addAll(STATE_NAMES.keySet());
270 Collections.sort(STATE_KEYS);
271 }
272
273 private static void printThreadState(Thread t) {
274 int state = getThreadState(t);
275
276 StringBuilder sb = new StringBuilder();
277
278 for (Integer i : STATE_KEYS) {
279 if ((state & i) != 0) {
280 if (sb.length()>0) {
281 sb.append('|');
282 }
283 sb.append(STATE_NAMES.get(i));
284 }
285 }
286
287 if (sb.length() == 0) {
288 sb.append("NEW");
289 }
290
291 System.out.println(Integer.toHexString(state) + " = " + sb.toString());
Andreas Gampeaf13ab92017-01-11 20:57:40 -0800292 }
293
294 private static void printThreadInfo(Thread t) {
295 Object[] threadInfo = getThreadInfo(t);
296 if (threadInfo == null || threadInfo.length != 5) {
297 System.out.println(Arrays.toString(threadInfo));
298 throw new RuntimeException("threadInfo length wrong");
299 }
300
301 System.out.println(threadInfo[0]); // Name
302 System.out.println(threadInfo[1]); // Priority
303 System.out.println(threadInfo[2]); // Daemon
304 System.out.println(threadInfo[3]); // Threadgroup
305 System.out.println(threadInfo[4] == null ? "null" : threadInfo[4].getClass()); // Context CL.
306 }
307
308 private static native Thread getCurrentThread();
309 private static native Object[] getThreadInfo(Thread t);
Andreas Gampe72c19832017-01-12 13:22:16 -0800310 private static native int getThreadState(Thread t);
Andreas Gampe85807442017-01-13 14:40:58 -0800311 private static native Thread[] getAllThreads();
Andreas Gampe7b3b3262017-01-19 20:40:42 -0800312 private static native void setTLS(Thread t, long l);
313 private static native long getTLS(Thread t);
Andreas Gampeeafaf572017-01-20 12:34:15 -0800314 private static native void enableThreadEvents(boolean b);
Andreas Gampeaf13ab92017-01-11 20:57:40 -0800315}