1af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe/*
2af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe * Copyright (C) 2017 The Android Open Source Project
3af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe *
4af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe * Licensed under the Apache License, Version 2.0 (the "License");
5af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe * you may not use this file except in compliance with the License.
6af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe * You may obtain a copy of the License at
7af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe *
8af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe *      http://www.apache.org/licenses/LICENSE-2.0
9af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe *
10af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe * Unless required by applicable law or agreed to in writing, software
11af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe * distributed under the License is distributed on an "AS IS" BASIS,
12af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe * See the License for the specific language governing permissions and
14af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe * limitations under the License.
15af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe */
16af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe
174665167ddc34008dfa78a2873685fe7a98772eabAndreas Gampepackage art;
184665167ddc34008dfa78a2873685fe7a98772eabAndreas Gampe
19af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampeimport java.util.Arrays;
2072c19834136c81eace33687e06f5daf92a5a7583Andreas Gampeimport java.util.ArrayList;
2172c19834136c81eace33687e06f5daf92a5a7583Andreas Gampeimport java.util.Collections;
228580744607a963d408956c3eb712b0e070c139b0Andreas Gampeimport java.util.Comparator;
2372c19834136c81eace33687e06f5daf92a5a7583Andreas Gampeimport java.util.concurrent.CountDownLatch;
24ba461c3c5b588b0b65d3cc99aa12fe46a673962cAlex Lightimport java.util.function.Function;
2572c19834136c81eace33687e06f5daf92a5a7583Andreas Gampeimport java.util.HashMap;
264471e4f7c5874bdaf93762b6047d4a4bebc465dfAndreas Gampeimport java.util.Iterator;
2772c19834136c81eace33687e06f5daf92a5a7583Andreas Gampeimport java.util.List;
2872c19834136c81eace33687e06f5daf92a5a7583Andreas Gampeimport java.util.Map;
29447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampeimport java.util.Set;
30af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe
314665167ddc34008dfa78a2873685fe7a98772eabAndreas Gampepublic class Test924 {
324665167ddc34008dfa78a2873685fe7a98772eabAndreas Gampe  public static void run() throws Exception {
33447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe    // Run the test on its own thread, so we have a known state for the "current" thread.
34447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe    Thread t = new Thread("TestThread") {
35447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe      @Override
36447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe      public void run() {
37447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe        try {
38447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe          doTest();
39447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe        } catch (Exception e) {
40447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe          throw new RuntimeException(e);
41447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe        }
42447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe      }
43447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe    };
44447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe    t.start();
45447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe    t.join();
46af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe  }
47af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe
48af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe  private static void doTest() throws Exception {
49af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe    Thread t1 = Thread.currentThread();
50af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe    Thread t2 = getCurrentThread();
51af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe
52447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe    // Need to adjust priority, as on-device this may be unexpected (and we prefer not
53447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe    // to special-case this.)
54447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe    t1.setPriority(5);
55447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe
56af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe    if (t1 != t2) {
57af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe      throw new RuntimeException("Expected " + t1 + " but got " + t2);
58af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe    }
59af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe    System.out.println("currentThread OK");
60af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe
61af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe    printThreadInfo(t1);
62af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe    printThreadInfo(null);
63af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe
64af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe    Thread t3 = new Thread("Daemon Thread");
65af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe    t3.setDaemon(true);
66af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe    // Do not start this thread, yet.
67af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe    printThreadInfo(t3);
68af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe    // Start, and wait for it to die.
69af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe    t3.start();
70af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe    t3.join();
7172c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    Thread.sleep(500);  // Wait a little bit.
72af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe    // Thread has died, check that we can still get info.
73af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe    printThreadInfo(t3);
7472c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe
75db6c2ab29ef6ebe89c9ea43dae3b899a935fa74eAndreas Gampe    // Try a subclass of thread.
76db6c2ab29ef6ebe89c9ea43dae3b899a935fa74eAndreas Gampe    Thread t4 = new Thread("Subclass") {
77db6c2ab29ef6ebe89c9ea43dae3b899a935fa74eAndreas Gampe    };
78db6c2ab29ef6ebe89c9ea43dae3b899a935fa74eAndreas Gampe    printThreadInfo(t4);
79db6c2ab29ef6ebe89c9ea43dae3b899a935fa74eAndreas Gampe
80ba461c3c5b588b0b65d3cc99aa12fe46a673962cAlex Light    doCurrentThreadStateTests();
81ba461c3c5b588b0b65d3cc99aa12fe46a673962cAlex Light    doStateTests(Thread::new);
82ba461c3c5b588b0b65d3cc99aa12fe46a673962cAlex Light    doStateTests(ExtThread::new);
838580744607a963d408956c3eb712b0e070c139b0Andreas Gampe
848580744607a963d408956c3eb712b0e070c139b0Andreas Gampe    doAllThreadsTests();
857b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe
867b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe    doTLSTests();
87eafaf57557939bcabeb7a7388fb4951e74661a53Andreas Gampe
88eafaf57557939bcabeb7a7388fb4951e74661a53Andreas Gampe    doTestEvents();
8972c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe  }
9072c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe
91ba461c3c5b588b0b65d3cc99aa12fe46a673962cAlex Light  private static final class ExtThread extends Thread {
92ba461c3c5b588b0b65d3cc99aa12fe46a673962cAlex Light    public ExtThread(Runnable r) { super(r); }
93ba461c3c5b588b0b65d3cc99aa12fe46a673962cAlex Light  }
94ba461c3c5b588b0b65d3cc99aa12fe46a673962cAlex Light
9572c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe  private static class Holder {
9672c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    volatile boolean flag = false;
9772c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe  }
9872c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe
99ba461c3c5b588b0b65d3cc99aa12fe46a673962cAlex Light  private static void doCurrentThreadStateTests() throws Exception {
10072c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    System.out.println(Integer.toHexString(getThreadState(null)));
10172c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    System.out.println(Integer.toHexString(getThreadState(Thread.currentThread())));
102ba461c3c5b588b0b65d3cc99aa12fe46a673962cAlex Light  }
10372c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe
104ba461c3c5b588b0b65d3cc99aa12fe46a673962cAlex Light  private static void doStateTests(Function<Runnable, Thread> mkThread) throws Exception {
10572c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    final CountDownLatch cdl1 = new CountDownLatch(1);
10672c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    final CountDownLatch cdl2 = new CountDownLatch(1);
10772c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    final CountDownLatch cdl3_1 = new CountDownLatch(1);
10872c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    final CountDownLatch cdl3_2 = new CountDownLatch(1);
10972c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    final CountDownLatch cdl4 = new CountDownLatch(1);
11072c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    final CountDownLatch cdl5 = new CountDownLatch(1);
11172c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    final Holder h = new Holder();
112597adad749499bc2da85851273e7623f6b249d1eAlex Light    final NativeWaiter w = new NativeWaiter();
11372c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    Runnable r = new Runnable() {
11472c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe      @Override
11572c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe      public void run() {
11672c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe        try {
11772c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe          cdl1.countDown();
11872c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe          synchronized(cdl1) {
11972c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe            cdl1.wait();
12072c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe          }
12172c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe
12272c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe          cdl2.countDown();
12372c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe          synchronized(cdl2) {
12472c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe            cdl2.wait(1000);  // Wait a second.
12572c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe          }
12672c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe
12772c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe          cdl3_1.await();
12872c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe          cdl3_2.countDown();
12972c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe          synchronized(cdl3_2) {
13072c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe            // Nothing, just wanted to block on cdl3.
13172c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe          }
13272c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe
13372c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe          cdl4.countDown();
13472c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe          Thread.sleep(1000);
13572c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe
13672c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe          cdl5.countDown();
13772c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe          while (!h.flag) {
13872c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe            // Busy-loop.
13972c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe          }
140597adad749499bc2da85851273e7623f6b249d1eAlex Light
141597adad749499bc2da85851273e7623f6b249d1eAlex Light          nativeLoop(w.struct);
14272c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe        } catch (Exception e) {
14372c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe          throw new RuntimeException(e);
14472c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe        }
14572c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe      }
14672c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    };
14772c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe
148ba461c3c5b588b0b65d3cc99aa12fe46a673962cAlex Light    Thread t = mkThread.apply(r);
149ba461c3c5b588b0b65d3cc99aa12fe46a673962cAlex Light    System.out.println("Thread type is " + t.getClass());
15072c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    printThreadState(t);
15172c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    t.start();
15272c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe
15372c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    // Waiting.
15472c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    cdl1.await();
15572c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    Thread.yield();
15672c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    Thread.sleep(100);
15772c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    printThreadState(t);
15872c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    synchronized(cdl1) {
15972c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe      cdl1.notifyAll();
16072c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    }
16172c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe
16272c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    // Timed waiting.
16372c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    cdl2.await();
16472c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    Thread.yield();
16572c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    Thread.sleep(100);
16672c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    printThreadState(t);
16772c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    synchronized(cdl2) {
16872c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe      cdl2.notifyAll();
16972c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    }
17072c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe
17172c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    // Blocked on monitor.
17272c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    synchronized(cdl3_2) {
17372c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe      cdl3_1.countDown();
17472c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe      cdl3_2.await();
175d59695c324f949115a609948a893ef8a9bdbca9fAndreas Gampe      // While the latch improves the chances to make good progress, scheduling might still be
176d59695c324f949115a609948a893ef8a9bdbca9fAndreas Gampe      // messy. Wait till we get the right Java-side Thread state.
177d59695c324f949115a609948a893ef8a9bdbca9fAndreas Gampe      do {
178d59695c324f949115a609948a893ef8a9bdbca9fAndreas Gampe        Thread.yield();
179d59695c324f949115a609948a893ef8a9bdbca9fAndreas Gampe      } while (t.getState() != Thread.State.BLOCKED);
180ed3a357e6b28dbc00a60b72af8bb846775348172Alex Light      // Since internal thread suspension (For GC or other cases) can happen at any time and changes
181ed3a357e6b28dbc00a60b72af8bb846775348172Alex Light      // the thread state we just have it print the majority thread state across 11 calls over 55
182ed3a357e6b28dbc00a60b72af8bb846775348172Alex Light      // milliseconds.
183ed3a357e6b28dbc00a60b72af8bb846775348172Alex Light      printMajorityThreadState(t, 11, 5);
18472c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    }
18572c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe
18672c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    // Sleeping.
18772c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    cdl4.await();
18872c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    Thread.yield();
18972c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    Thread.sleep(100);
19072c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    printThreadState(t);
19172c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe
19272c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    // Running.
19372c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    cdl5.await();
19472c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    Thread.yield();
19572c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    Thread.sleep(100);
19672c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    printThreadState(t);
19772c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    h.flag = true;
19872c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe
199597adad749499bc2da85851273e7623f6b249d1eAlex Light    // Native
200597adad749499bc2da85851273e7623f6b249d1eAlex Light    w.waitForNative();
201597adad749499bc2da85851273e7623f6b249d1eAlex Light    printThreadState(t);
202597adad749499bc2da85851273e7623f6b249d1eAlex Light    w.finish();
203597adad749499bc2da85851273e7623f6b249d1eAlex Light
20472c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    // Dying.
20572c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    t.join();
20672c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    Thread.yield();
20772c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    Thread.sleep(100);
20872c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe
20972c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    printThreadState(t);
21072c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe  }
21172c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe
2128580744607a963d408956c3eb712b0e070c139b0Andreas Gampe  private static void doAllThreadsTests() {
2138580744607a963d408956c3eb712b0e070c139b0Andreas Gampe    Thread[] threads = getAllThreads();
2144471e4f7c5874bdaf93762b6047d4a4bebc465dfAndreas Gampe    List<Thread> threadList = new ArrayList<>(Arrays.asList(threads));
2154471e4f7c5874bdaf93762b6047d4a4bebc465dfAndreas Gampe
2164471e4f7c5874bdaf93762b6047d4a4bebc465dfAndreas Gampe    // Filter out JIT thread. It may or may not be there depending on configuration.
2174471e4f7c5874bdaf93762b6047d4a4bebc465dfAndreas Gampe    Iterator<Thread> it = threadList.iterator();
2184471e4f7c5874bdaf93762b6047d4a4bebc465dfAndreas Gampe    while (it.hasNext()) {
2194471e4f7c5874bdaf93762b6047d4a4bebc465dfAndreas Gampe      Thread t = it.next();
2204471e4f7c5874bdaf93762b6047d4a4bebc465dfAndreas Gampe      if (t.getName().startsWith("Jit thread pool worker")) {
2214471e4f7c5874bdaf93762b6047d4a4bebc465dfAndreas Gampe        it.remove();
2224471e4f7c5874bdaf93762b6047d4a4bebc465dfAndreas Gampe        break;
2234471e4f7c5874bdaf93762b6047d4a4bebc465dfAndreas Gampe      }
2244471e4f7c5874bdaf93762b6047d4a4bebc465dfAndreas Gampe    }
2254471e4f7c5874bdaf93762b6047d4a4bebc465dfAndreas Gampe
2264471e4f7c5874bdaf93762b6047d4a4bebc465dfAndreas Gampe    Collections.sort(threadList, THREAD_COMP);
227447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe
228447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe    List<Thread> expectedList = new ArrayList<>();
229447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe    Set<Thread> threadsFromTraces = Thread.getAllStackTraces().keySet();
230447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe
231447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe    expectedList.add(findThreadByName(threadsFromTraces, "FinalizerDaemon"));
232447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe    expectedList.add(findThreadByName(threadsFromTraces, "FinalizerWatchdogDaemon"));
233447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe    expectedList.add(findThreadByName(threadsFromTraces, "HeapTaskDaemon"));
234447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe    expectedList.add(findThreadByName(threadsFromTraces, "ReferenceQueueDaemon"));
235447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe    // We can't get the signal catcher through getAllStackTraces. So ignore it.
236447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe    // expectedList.add(findThreadByName(threadsFromTraces, "Signal Catcher"));
237447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe    expectedList.add(findThreadByName(threadsFromTraces, "TestThread"));
238447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe    expectedList.add(findThreadByName(threadsFromTraces, "main"));
239447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe
240447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe    if (!threadList.containsAll(expectedList)) {
241447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe      throw new RuntimeException("Expected " + expectedList + " as subset, got " + threadList);
242447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe    }
243447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe    System.out.println(expectedList);
244447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe  }
245447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe
246447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe  private static Thread findThreadByName(Set<Thread> threads, String name) {
247447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe    for (Thread t : threads) {
248447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe        if (t.getName().equals(name)) {
249447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe            return t;
250447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe        }
251447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe    }
252447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe    throw new RuntimeException("Did not find thread " + name + ": " + threads);
2538580744607a963d408956c3eb712b0e070c139b0Andreas Gampe  }
2548580744607a963d408956c3eb712b0e070c139b0Andreas Gampe
2557b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe  private static void doTLSTests() throws Exception {
2567b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe    doTLSNonLiveTests();
2577b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe    doTLSLiveTests();
2587b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe  }
2597b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe
2607b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe  private static void doTLSNonLiveTests() throws Exception {
2617b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe    Thread t = new Thread();
2627b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe    try {
2637b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe      setTLS(t, 1);
2647b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe      System.out.println("Expected failure setting TLS for non-live thread");
2657b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe    } catch (Exception e) {
2667b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe      System.out.println(e.getMessage());
2677b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe    }
2687b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe    t.start();
2697b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe    t.join();
2707b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe    try {
2717b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe      setTLS(t, 1);
2727b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe      System.out.println("Expected failure setting TLS for non-live thread");
2737b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe    } catch (Exception e) {
2747b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe      System.out.println(e.getMessage());
2757b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe    }
2767b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe  }
2777b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe
2787b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe  private static void doTLSLiveTests() throws Exception {
2797b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe    setTLS(Thread.currentThread(), 1);
2807b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe
2817b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe    long l = getTLS(Thread.currentThread());
2827b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe    if (l != 1) {
2837b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe      throw new RuntimeException("Unexpected TLS value: " + l);
2847b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe    };
2857b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe
2867b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe    final CountDownLatch cdl1 = new CountDownLatch(1);
2877b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe    final CountDownLatch cdl2 = new CountDownLatch(1);
2887b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe
2897b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe    Runnable r = new Runnable() {
2907b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe      @Override
2917b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe      public void run() {
2927b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe        try {
2937b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe          cdl1.countDown();
2947b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe          cdl2.await();
2957b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe          setTLS(Thread.currentThread(), 2);
2967b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe          if (getTLS(Thread.currentThread()) != 2) {
2977b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe            throw new RuntimeException("Different thread issue");
2987b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe          }
2997b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe        } catch (Exception e) {
3007b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe          throw new RuntimeException(e);
3017b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe        }
3027b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe      }
3037b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe    };
3047b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe
3057b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe    Thread t = new Thread(r);
3067b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe    t.start();
3077b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe    cdl1.await();
3087b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe    setTLS(Thread.currentThread(), 1);
3097b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe    cdl2.countDown();
3107b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe
3117b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe    t.join();
3127b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe    if (getTLS(Thread.currentThread()) != 1) {
3137b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe      throw new RuntimeException("Got clobbered");
3147b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe    }
3157b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe  }
3167b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe
317eafaf57557939bcabeb7a7388fb4951e74661a53Andreas Gampe  private static void doTestEvents() throws Exception {
318eafaf57557939bcabeb7a7388fb4951e74661a53Andreas Gampe    enableThreadEvents(true);
319eafaf57557939bcabeb7a7388fb4951e74661a53Andreas Gampe
320447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe    final CountDownLatch cdl1 = new CountDownLatch(1);
321447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe    final CountDownLatch cdl2 = new CountDownLatch(1);
322447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe
323447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe    Runnable r = new Runnable() {
324447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe      @Override
325447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe      public void run() {
326447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe        try {
327447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe          cdl1.countDown();
328447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe          cdl2.await();
329447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe        } catch (Exception e) {
330447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe          throw new RuntimeException(e);
331447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe        }
332447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe      }
333447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe    };
334447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe    Thread t = new Thread(r, "EventTestThread");
335eafaf57557939bcabeb7a7388fb4951e74661a53Andreas Gampe
336eafaf57557939bcabeb7a7388fb4951e74661a53Andreas Gampe    System.out.println("Constructed thread");
337eafaf57557939bcabeb7a7388fb4951e74661a53Andreas Gampe    Thread.yield();
338447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe    Thread.sleep(100);
339447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe    System.out.println(Arrays.toString(getThreadEventMessages()));
340eafaf57557939bcabeb7a7388fb4951e74661a53Andreas Gampe
341eafaf57557939bcabeb7a7388fb4951e74661a53Andreas Gampe    t.start();
342447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe    cdl1.await();
343447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe
344447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe    System.out.println(Arrays.toString(getThreadEventMessages()));
345447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe
346447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe    cdl2.countDown();
347eafaf57557939bcabeb7a7388fb4951e74661a53Andreas Gampe    t.join();
348447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe    System.out.println(Arrays.toString(getThreadEventMessages()));
349eafaf57557939bcabeb7a7388fb4951e74661a53Andreas Gampe
350eafaf57557939bcabeb7a7388fb4951e74661a53Andreas Gampe    System.out.println("Thread joined");
351eafaf57557939bcabeb7a7388fb4951e74661a53Andreas Gampe
352eafaf57557939bcabeb7a7388fb4951e74661a53Andreas Gampe    enableThreadEvents(false);
353eafaf57557939bcabeb7a7388fb4951e74661a53Andreas Gampe  }
354eafaf57557939bcabeb7a7388fb4951e74661a53Andreas Gampe
3558580744607a963d408956c3eb712b0e070c139b0Andreas Gampe  private final static Comparator<Thread> THREAD_COMP = new Comparator<Thread>() {
3568580744607a963d408956c3eb712b0e070c139b0Andreas Gampe    public int compare(Thread o1, Thread o2) {
3578580744607a963d408956c3eb712b0e070c139b0Andreas Gampe      return o1.getName().compareTo(o2.getName());
3588580744607a963d408956c3eb712b0e070c139b0Andreas Gampe    }
3598580744607a963d408956c3eb712b0e070c139b0Andreas Gampe  };
3608580744607a963d408956c3eb712b0e070c139b0Andreas Gampe
36172c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe  private final static Map<Integer, String> STATE_NAMES = new HashMap<Integer, String>();
36272c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe  private final static List<Integer> STATE_KEYS = new ArrayList<Integer>();
36372c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe  static {
36472c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    STATE_NAMES.put(0x1, "ALIVE");
36572c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    STATE_NAMES.put(0x2, "TERMINATED");
36672c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    STATE_NAMES.put(0x4, "RUNNABLE");
36772c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    STATE_NAMES.put(0x400, "BLOCKED_ON_MONITOR_ENTER");
36872c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    STATE_NAMES.put(0x80, "WAITING");
36972c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    STATE_NAMES.put(0x10, "WAITING_INDEFINITELY");
37072c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    STATE_NAMES.put(0x20, "WAITING_WITH_TIMEOUT");
37172c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    STATE_NAMES.put(0x40, "SLEEPING");
37272c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    STATE_NAMES.put(0x100, "IN_OBJECT_WAIT");
37372c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    STATE_NAMES.put(0x200, "PARKED");
37472c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    STATE_NAMES.put(0x100000, "SUSPENDED");
37572c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    STATE_NAMES.put(0x200000, "INTERRUPTED");
37672c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    STATE_NAMES.put(0x400000, "IN_NATIVE");
37772c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    STATE_KEYS.addAll(STATE_NAMES.keySet());
37872c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    Collections.sort(STATE_KEYS);
37972c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe  }
380ed3a357e6b28dbc00a60b72af8bb846775348172Alex Light
381ed3a357e6b28dbc00a60b72af8bb846775348172Alex Light  // Call getThreadState 'votes' times waiting 'wait' millis between calls and print the most common
382ed3a357e6b28dbc00a60b72af8bb846775348172Alex Light  // result.
383ed3a357e6b28dbc00a60b72af8bb846775348172Alex Light  private static void printMajorityThreadState(Thread t, int votes, int wait) throws Exception {
384ed3a357e6b28dbc00a60b72af8bb846775348172Alex Light    Map<Integer, Integer> states = new HashMap<>();
385ed3a357e6b28dbc00a60b72af8bb846775348172Alex Light    for (int i = 0; i < votes; i++) {
386ed3a357e6b28dbc00a60b72af8bb846775348172Alex Light      int cur_state = getThreadState(t);
387ed3a357e6b28dbc00a60b72af8bb846775348172Alex Light      states.put(cur_state, states.getOrDefault(cur_state, 0) + 1);
388ed3a357e6b28dbc00a60b72af8bb846775348172Alex Light      Thread.sleep(wait);  // Wait a little bit.
389ed3a357e6b28dbc00a60b72af8bb846775348172Alex Light    }
390ed3a357e6b28dbc00a60b72af8bb846775348172Alex Light    int best_state = -1;
391ed3a357e6b28dbc00a60b72af8bb846775348172Alex Light    int highest_count = 0;
392ed3a357e6b28dbc00a60b72af8bb846775348172Alex Light    for (Map.Entry<Integer, Integer> e : states.entrySet()) {
393ed3a357e6b28dbc00a60b72af8bb846775348172Alex Light      if (e.getValue() > highest_count) {
394ed3a357e6b28dbc00a60b72af8bb846775348172Alex Light        highest_count = e.getValue();
395ed3a357e6b28dbc00a60b72af8bb846775348172Alex Light        best_state = e.getKey();
396ed3a357e6b28dbc00a60b72af8bb846775348172Alex Light      }
397ed3a357e6b28dbc00a60b72af8bb846775348172Alex Light    }
398ed3a357e6b28dbc00a60b72af8bb846775348172Alex Light    printThreadState(best_state);
399ed3a357e6b28dbc00a60b72af8bb846775348172Alex Light  }
400ed3a357e6b28dbc00a60b72af8bb846775348172Alex Light
40172c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe  private static void printThreadState(Thread t) {
402ed3a357e6b28dbc00a60b72af8bb846775348172Alex Light    printThreadState(getThreadState(t));
403ed3a357e6b28dbc00a60b72af8bb846775348172Alex Light  }
40472c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe
405ed3a357e6b28dbc00a60b72af8bb846775348172Alex Light  private static void printThreadState(int state) {
40672c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    StringBuilder sb = new StringBuilder();
40772c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe
40872c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    for (Integer i : STATE_KEYS) {
40972c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe      if ((state & i) != 0) {
41072c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe        if (sb.length()>0) {
41172c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe          sb.append('|');
41272c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe        }
41372c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe        sb.append(STATE_NAMES.get(i));
41472c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe      }
41572c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    }
41672c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe
41772c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    if (sb.length() == 0) {
41872c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe      sb.append("NEW");
41972c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    }
42072c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe
42172c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe    System.out.println(Integer.toHexString(state) + " = " + sb.toString());
422af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe  }
423af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe
424af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe  private static void printThreadInfo(Thread t) {
425af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe    Object[] threadInfo = getThreadInfo(t);
426af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe    if (threadInfo == null || threadInfo.length != 5) {
427af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe      System.out.println(Arrays.toString(threadInfo));
428af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe      throw new RuntimeException("threadInfo length wrong");
429af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe    }
430af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe
431af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe    System.out.println(threadInfo[0]);  // Name
432af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe    System.out.println(threadInfo[1]);  // Priority
433af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe    System.out.println(threadInfo[2]);  // Daemon
434af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe    System.out.println(threadInfo[3]);  // Threadgroup
435af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe    System.out.println(threadInfo[4] == null ? "null" : threadInfo[4].getClass());  // Context CL.
436af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe  }
437af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe
438597adad749499bc2da85851273e7623f6b249d1eAlex Light  public static final class NativeWaiter {
439597adad749499bc2da85851273e7623f6b249d1eAlex Light    public long struct;
440597adad749499bc2da85851273e7623f6b249d1eAlex Light    public NativeWaiter() {
441597adad749499bc2da85851273e7623f6b249d1eAlex Light      struct = nativeWaiterStructAlloc();
442597adad749499bc2da85851273e7623f6b249d1eAlex Light    }
443597adad749499bc2da85851273e7623f6b249d1eAlex Light    public void waitForNative() {
444597adad749499bc2da85851273e7623f6b249d1eAlex Light      if (struct == 0l) {
445597adad749499bc2da85851273e7623f6b249d1eAlex Light        throw new Error("Already resumed from native!");
446597adad749499bc2da85851273e7623f6b249d1eAlex Light      }
447597adad749499bc2da85851273e7623f6b249d1eAlex Light      nativeWaiterStructWaitForNative(struct);
448597adad749499bc2da85851273e7623f6b249d1eAlex Light    }
449597adad749499bc2da85851273e7623f6b249d1eAlex Light    public void finish() {
450597adad749499bc2da85851273e7623f6b249d1eAlex Light      if (struct == 0l) {
451597adad749499bc2da85851273e7623f6b249d1eAlex Light        throw new Error("Already resumed from native!");
452597adad749499bc2da85851273e7623f6b249d1eAlex Light      }
453597adad749499bc2da85851273e7623f6b249d1eAlex Light      nativeWaiterStructFinish(struct);
454597adad749499bc2da85851273e7623f6b249d1eAlex Light      struct = 0;
455597adad749499bc2da85851273e7623f6b249d1eAlex Light    }
456597adad749499bc2da85851273e7623f6b249d1eAlex Light  }
457597adad749499bc2da85851273e7623f6b249d1eAlex Light
458597adad749499bc2da85851273e7623f6b249d1eAlex Light  private static native long nativeWaiterStructAlloc();
459597adad749499bc2da85851273e7623f6b249d1eAlex Light  private static native void nativeWaiterStructWaitForNative(long struct);
460597adad749499bc2da85851273e7623f6b249d1eAlex Light  private static native void nativeWaiterStructFinish(long struct);
461597adad749499bc2da85851273e7623f6b249d1eAlex Light  private static native void nativeLoop(long w);
462597adad749499bc2da85851273e7623f6b249d1eAlex Light
463af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe  private static native Thread getCurrentThread();
464af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe  private static native Object[] getThreadInfo(Thread t);
46572c19834136c81eace33687e06f5daf92a5a7583Andreas Gampe  private static native int getThreadState(Thread t);
4668580744607a963d408956c3eb712b0e070c139b0Andreas Gampe  private static native Thread[] getAllThreads();
4677b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe  private static native void setTLS(Thread t, long l);
4687b3b326158676a89bc27639b829a3e1746f8c988Andreas Gampe  private static native long getTLS(Thread t);
469eafaf57557939bcabeb7a7388fb4951e74661a53Andreas Gampe  private static native void enableThreadEvents(boolean b);
470447c1af5187ea23b8bd045a84fd332dd6a284fe0Andreas Gampe  private static native String[] getThreadEventMessages();
471af13ab9586cebbfc40204179e2dd0986cc14dd84Andreas Gampe}
472