blob: 58695f7e65f0357c23511b1c390715972ac9cedf [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 Gampe72c19832017-01-12 13:22:16 -080059 }
60
61 private static class Holder {
62 volatile boolean flag = false;
63 }
64
65 private static void doStateTests() throws Exception {
66 System.out.println(Integer.toHexString(getThreadState(null)));
67 System.out.println(Integer.toHexString(getThreadState(Thread.currentThread())));
68
69 final CountDownLatch cdl1 = new CountDownLatch(1);
70 final CountDownLatch cdl2 = new CountDownLatch(1);
71 final CountDownLatch cdl3_1 = new CountDownLatch(1);
72 final CountDownLatch cdl3_2 = new CountDownLatch(1);
73 final CountDownLatch cdl4 = new CountDownLatch(1);
74 final CountDownLatch cdl5 = new CountDownLatch(1);
75 final Holder h = new Holder();
76 Runnable r = new Runnable() {
77 @Override
78 public void run() {
79 try {
80 cdl1.countDown();
81 synchronized(cdl1) {
82 cdl1.wait();
83 }
84
85 cdl2.countDown();
86 synchronized(cdl2) {
87 cdl2.wait(1000); // Wait a second.
88 }
89
90 cdl3_1.await();
91 cdl3_2.countDown();
92 synchronized(cdl3_2) {
93 // Nothing, just wanted to block on cdl3.
94 }
95
96 cdl4.countDown();
97 Thread.sleep(1000);
98
99 cdl5.countDown();
100 while (!h.flag) {
101 // Busy-loop.
102 }
103 } catch (Exception e) {
104 throw new RuntimeException(e);
105 }
106 }
107 };
108
109 Thread t = new Thread(r);
110 printThreadState(t);
111 t.start();
112
113 // Waiting.
114 cdl1.await();
115 Thread.yield();
116 Thread.sleep(100);
117 printThreadState(t);
118 synchronized(cdl1) {
119 cdl1.notifyAll();
120 }
121
122 // Timed waiting.
123 cdl2.await();
124 Thread.yield();
125 Thread.sleep(100);
126 printThreadState(t);
127 synchronized(cdl2) {
128 cdl2.notifyAll();
129 }
130
131 // Blocked on monitor.
132 synchronized(cdl3_2) {
133 cdl3_1.countDown();
134 cdl3_2.await();
135 Thread.yield();
136 Thread.sleep(100);
137 printThreadState(t);
138 }
139
140 // Sleeping.
141 cdl4.await();
142 Thread.yield();
143 Thread.sleep(100);
144 printThreadState(t);
145
146 // Running.
147 cdl5.await();
148 Thread.yield();
149 Thread.sleep(100);
150 printThreadState(t);
151 h.flag = true;
152
153 // Dying.
154 t.join();
155 Thread.yield();
156 Thread.sleep(100);
157
158 printThreadState(t);
159 }
160
Andreas Gampe85807442017-01-13 14:40:58 -0800161 private static void doAllThreadsTests() {
162 Thread[] threads = getAllThreads();
163 Arrays.sort(threads, THREAD_COMP);
164 System.out.println(Arrays.toString(threads));
165 }
166
Andreas Gampe7b3b3262017-01-19 20:40:42 -0800167 private static void doTLSTests() throws Exception {
168 doTLSNonLiveTests();
169 doTLSLiveTests();
170 }
171
172 private static void doTLSNonLiveTests() throws Exception {
173 Thread t = new Thread();
174 try {
175 setTLS(t, 1);
176 System.out.println("Expected failure setting TLS for non-live thread");
177 } catch (Exception e) {
178 System.out.println(e.getMessage());
179 }
180 t.start();
181 t.join();
182 try {
183 setTLS(t, 1);
184 System.out.println("Expected failure setting TLS for non-live thread");
185 } catch (Exception e) {
186 System.out.println(e.getMessage());
187 }
188 }
189
190 private static void doTLSLiveTests() throws Exception {
191 setTLS(Thread.currentThread(), 1);
192
193 long l = getTLS(Thread.currentThread());
194 if (l != 1) {
195 throw new RuntimeException("Unexpected TLS value: " + l);
196 };
197
198 final CountDownLatch cdl1 = new CountDownLatch(1);
199 final CountDownLatch cdl2 = new CountDownLatch(1);
200
201 Runnable r = new Runnable() {
202 @Override
203 public void run() {
204 try {
205 cdl1.countDown();
206 cdl2.await();
207 setTLS(Thread.currentThread(), 2);
208 if (getTLS(Thread.currentThread()) != 2) {
209 throw new RuntimeException("Different thread issue");
210 }
211 } catch (Exception e) {
212 throw new RuntimeException(e);
213 }
214 }
215 };
216
217 Thread t = new Thread(r);
218 t.start();
219 cdl1.await();
220 setTLS(Thread.currentThread(), 1);
221 cdl2.countDown();
222
223 t.join();
224 if (getTLS(Thread.currentThread()) != 1) {
225 throw new RuntimeException("Got clobbered");
226 }
227 }
228
Andreas Gampe85807442017-01-13 14:40:58 -0800229 private final static Comparator<Thread> THREAD_COMP = new Comparator<Thread>() {
230 public int compare(Thread o1, Thread o2) {
231 return o1.getName().compareTo(o2.getName());
232 }
233 };
234
Andreas Gampe72c19832017-01-12 13:22:16 -0800235 private final static Map<Integer, String> STATE_NAMES = new HashMap<Integer, String>();
236 private final static List<Integer> STATE_KEYS = new ArrayList<Integer>();
237 static {
238 STATE_NAMES.put(0x1, "ALIVE");
239 STATE_NAMES.put(0x2, "TERMINATED");
240 STATE_NAMES.put(0x4, "RUNNABLE");
241 STATE_NAMES.put(0x400, "BLOCKED_ON_MONITOR_ENTER");
242 STATE_NAMES.put(0x80, "WAITING");
243 STATE_NAMES.put(0x10, "WAITING_INDEFINITELY");
244 STATE_NAMES.put(0x20, "WAITING_WITH_TIMEOUT");
245 STATE_NAMES.put(0x40, "SLEEPING");
246 STATE_NAMES.put(0x100, "IN_OBJECT_WAIT");
247 STATE_NAMES.put(0x200, "PARKED");
248 STATE_NAMES.put(0x100000, "SUSPENDED");
249 STATE_NAMES.put(0x200000, "INTERRUPTED");
250 STATE_NAMES.put(0x400000, "IN_NATIVE");
251 STATE_KEYS.addAll(STATE_NAMES.keySet());
252 Collections.sort(STATE_KEYS);
253 }
254
255 private static void printThreadState(Thread t) {
256 int state = getThreadState(t);
257
258 StringBuilder sb = new StringBuilder();
259
260 for (Integer i : STATE_KEYS) {
261 if ((state & i) != 0) {
262 if (sb.length()>0) {
263 sb.append('|');
264 }
265 sb.append(STATE_NAMES.get(i));
266 }
267 }
268
269 if (sb.length() == 0) {
270 sb.append("NEW");
271 }
272
273 System.out.println(Integer.toHexString(state) + " = " + sb.toString());
Andreas Gampeaf13ab92017-01-11 20:57:40 -0800274 }
275
276 private static void printThreadInfo(Thread t) {
277 Object[] threadInfo = getThreadInfo(t);
278 if (threadInfo == null || threadInfo.length != 5) {
279 System.out.println(Arrays.toString(threadInfo));
280 throw new RuntimeException("threadInfo length wrong");
281 }
282
283 System.out.println(threadInfo[0]); // Name
284 System.out.println(threadInfo[1]); // Priority
285 System.out.println(threadInfo[2]); // Daemon
286 System.out.println(threadInfo[3]); // Threadgroup
287 System.out.println(threadInfo[4] == null ? "null" : threadInfo[4].getClass()); // Context CL.
288 }
289
290 private static native Thread getCurrentThread();
291 private static native Object[] getThreadInfo(Thread t);
Andreas Gampe72c19832017-01-12 13:22:16 -0800292 private static native int getThreadState(Thread t);
Andreas Gampe85807442017-01-13 14:40:58 -0800293 private static native Thread[] getAllThreads();
Andreas Gampe7b3b3262017-01-19 20:40:42 -0800294 private static native void setTLS(Thread t, long l);
295 private static native long getTLS(Thread t);
Andreas Gampeaf13ab92017-01-11 20:57:40 -0800296}