1 /* 2 * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /** 25 * @test 26 * @bug 8022595 27 * @summary JSR292: deadlock during class loading of MethodHandles, MethodHandleImpl & MethodHandleNatives 28 * @library /testlibrary 29 * @modules java.base/sun.misc 30 * java.management 31 * @run main/othervm ConcurrentClassLoadingTest 32 */ 33 import jdk.test.lib.Utils; 34 import java.util.ArrayList; 35 import java.util.Arrays; 36 import java.util.List; 37 import java.util.Random; 38 import java.util.concurrent.BrokenBarrierException; 39 import java.util.concurrent.CyclicBarrier; 40 41 public class ConcurrentClassLoadingTest { 42 int numThreads = 0; 43 CyclicBarrier l; 44 private static final Random rand = Utils.getRandomInstance(); 45 46 public static void main(String[] args) throws Throwable { 47 ConcurrentClassLoadingTest test = new ConcurrentClassLoadingTest(); 48 test.parseArgs(args); 49 test.run(); 50 } 51 52 void parseArgs(String[] args) { 53 int i = 0; 54 while (i < args.length) { 55 String flag = args[i]; 56 switch(flag) { 57 case "-numThreads": 58 numThreads = Integer.parseInt(args[++i]); 59 break; 60 default: 61 throw new Error("Unknown flag: " + flag); 62 } 63 ++i; 64 } 65 } 66 67 void init() { 68 if (numThreads == 0) { 69 numThreads = Runtime.getRuntime().availableProcessors(); 70 } 71 72 l = new CyclicBarrier(numThreads + 1); 73 74 System.out.printf("Threads: %d\n", numThreads); 75 } 76 77 final List<Loader> loaders = new ArrayList<>(); 78 79 void prepare() { 80 List<String> c = new ArrayList<>(Arrays.asList(classNames)); 81 82 // Split classes between loading threads 83 int count = (classNames.length / numThreads) + 1; 84 for (int t = 0; t < numThreads; t++) { 85 List<String> sel = new ArrayList<>(); 86 87 System.out.printf("Thread #%d:\n", t); 88 for (int i = 0; i < count; i++) { 89 if (c.isEmpty()) { 90 break; 91 } 92 93 int k = rand.nextInt(c.size()); 94 String elem = c.remove(k); 95 sel.add(elem); 96 System.out.printf("\t%s\n", elem); 97 } 98 loaders.add(new Loader(sel)); 99 } 100 101 // Print diagnostic info when the test hangs 102 Runtime.getRuntime().addShutdownHook(new Thread() { 103 public void run() { 104 boolean alive = false; 105 for (Loader l : loaders) { 106 if (!l.isAlive()) continue; 107 108 if (!alive) { 109 System.out.println("Some threads are still alive:"); 110 alive = true; 111 } 112 113 System.out.println(l.getName()); 114 for (StackTraceElement elem : l.getStackTrace()) { 115 System.out.println("\t"+elem.toString()); 116 } 117 } 118 } 119 }); 120 } 121 122 public void run() throws Throwable { 123 init(); 124 prepare(); 125 126 for (Loader loader : loaders) { 127 loader.start(); 128 } 129 130 l.await(); 131 132 for (Loader loader : loaders) { 133 loader.join(); 134 } 135 } 136 137 class Loader extends Thread { 138 List<String> classes; 139 140 public Loader(List<String> classes) { 141 this.classes = classes; 142 setDaemon(true); 143 } 144 145 @Override 146 public void run() { 147 try { 148 l.await(); 149 150 for (String name : classes) { 151 Class.forName(name).getName(); 152 } 153 } catch (ClassNotFoundException | BrokenBarrierException | InterruptedException e) { 154 throw new Error(e); 155 } 156 } 157 } 158 159 final static String[] classNames = { 160 "java.lang.invoke.CallSite", 161 "java.lang.invoke.ConstantCallSite", 162 "java.lang.invoke.LambdaConversionException", 163 "java.lang.invoke.LambdaMetafactory", 164 "java.lang.invoke.MethodHandle", 165 "java.lang.invoke.MethodHandleInfo", 166 "java.lang.invoke.MethodHandleProxies", 167 "java.lang.invoke.MethodHandles", 168 "java.lang.invoke.MethodType", 169 "java.lang.invoke.MutableCallSite", 170 "java.lang.invoke.SerializedLambda", 171 "java.lang.invoke.SwitchPoint", 172 "java.lang.invoke.VolatileCallSite", 173 "java.lang.invoke.WrongMethodTypeException" 174 }; 175 }