Home | History | Annotate | Download | only in art
      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.util.ArrayList;
     20 import java.util.Arrays;
     21 import java.util.Comparator;
     22 import java.util.Collections;
     23 import java.util.Iterator;
     24 import java.util.List;
     25 
     26 public class Test925 {
     27   public static void run() throws Exception {
     28     doTest();
     29   }
     30 
     31   private static void doTest() throws Exception {
     32     Thread t1 = Thread.currentThread();
     33     ThreadGroup curGroup = t1.getThreadGroup();
     34 
     35     ThreadGroup rootGroup = curGroup;
     36     while (rootGroup.getParent() != null) {
     37       rootGroup = rootGroup.getParent();
     38     }
     39 
     40     ThreadGroup topGroups[] = getTopThreadGroups();
     41     if (topGroups == null || topGroups.length != 1 || topGroups[0] != rootGroup) {
     42       System.out.println(Arrays.toString(topGroups));
     43       throw new RuntimeException("Unexpected topGroups");
     44     }
     45 
     46     printThreadGroupInfo(curGroup);
     47     printThreadGroupInfo(rootGroup);
     48 
     49     waitGroupChildren(rootGroup, 5 /* # daemons */, 30 /* timeout in seconds */);
     50 
     51     checkChildren(curGroup);
     52   }
     53 
     54   private static void printThreadGroupInfo(ThreadGroup tg) {
     55     Object[] threadGroupInfo = getThreadGroupInfo(tg);
     56     if (threadGroupInfo == null || threadGroupInfo.length != 4) {
     57       System.out.println(Arrays.toString(threadGroupInfo));
     58       throw new RuntimeException("threadGroupInfo length wrong");
     59     }
     60 
     61     System.out.println(tg);
     62     System.out.println("  " + threadGroupInfo[0]);  // Parent
     63     System.out.println("  " + threadGroupInfo[1]);  // Name
     64     System.out.println("  " + threadGroupInfo[2]);  // Priority
     65     System.out.println("  " + threadGroupInfo[3]);  // Daemon
     66   }
     67 
     68   private static void checkChildren(ThreadGroup tg) {
     69     Object[] data = getThreadGroupChildren(tg);
     70     Thread[] threads = (Thread[])data[0];
     71     ThreadGroup[] groups = (ThreadGroup[])data[1];
     72 
     73     List<Thread> threadList = new ArrayList<>(Arrays.asList(threads));
     74 
     75     // Filter out JIT thread. It may or may not be there depending on configuration.
     76     Iterator<Thread> it = threadList.iterator();
     77     while (it.hasNext()) {
     78       Thread t = it.next();
     79       if (t.getName().startsWith("Jit thread pool worker")) {
     80         it.remove();
     81         break;
     82       }
     83     }
     84 
     85     Collections.sort(threadList, THREAD_COMP);
     86 
     87     Arrays.sort(groups, THREADGROUP_COMP);
     88     System.out.println(tg.getName() + ":");
     89     System.out.println("  " + threadList);
     90     System.out.println("  " + Arrays.toString(groups));
     91 
     92     if (tg.getParent() != null) {
     93       checkChildren(tg.getParent());
     94     }
     95   }
     96 
     97   private static void waitGroupChildren(ThreadGroup tg, int expectedChildCount, int timeoutS)
     98       throws Exception {
     99     for (int i = 0; i <  timeoutS; i++) {
    100       Object[] data = getThreadGroupChildren(tg);
    101       Thread[] threads = (Thread[])data[0];
    102       if (threads.length == expectedChildCount) {
    103         return;
    104       }
    105       Thread.sleep(1000);
    106     }
    107 
    108     Object[] data = getThreadGroupChildren(tg);
    109     Thread[] threads = (Thread[])data[0];
    110     System.out.println(Arrays.toString(threads));
    111     throw new RuntimeException("Waited unsuccessfully for " + expectedChildCount + " children.");
    112   }
    113 
    114   private final static Comparator<Thread> THREAD_COMP = new Comparator<Thread>() {
    115     public int compare(Thread o1, Thread o2) {
    116       return o1.getName().compareTo(o2.getName());
    117     }
    118   };
    119 
    120   private final static Comparator<ThreadGroup> THREADGROUP_COMP = new Comparator<ThreadGroup>() {
    121     public int compare(ThreadGroup o1, ThreadGroup o2) {
    122       return o1.getName().compareTo(o2.getName());
    123     }
    124   };
    125 
    126   private static native ThreadGroup[] getTopThreadGroups();
    127   private static native Object[] getThreadGroupInfo(ThreadGroup tg);
    128   // Returns an array where element 0 is an array of threads and element 1 is an array of groups.
    129   private static native Object[] getThreadGroupChildren(ThreadGroup tg);
    130 }
    131