1 /* 2 * Copyright (c) 2013, 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 * 29 * @run main/othervm ConcurrentClassLoadingTest 30 */ 31 import java.util.*; 32 import java.util.concurrent.BrokenBarrierException; 33 import java.util.concurrent.CyclicBarrier; 34 35 public class ConcurrentClassLoadingTest { 36 int numThreads = 0; 37 long seed = 0; 38 CyclicBarrier l; 39 Random rand; 40 41 public static void main(String[] args) throws Throwable { 42 ConcurrentClassLoadingTest test = new ConcurrentClassLoadingTest(); 43 test.parseArgs(args); 44 test.run(); 45 } 46 47 void parseArgs(String[] args) { 48 int i = 0; 49 while (i < args.length) { 50 String flag = args[i]; 51 switch(flag) { 52 case "-seed": 53 seed = Long.parseLong(args[++i]); 54 break; 55 case "-numThreads": 56 numThreads = Integer.parseInt(args[++i]); 57 break; 58 default: 59 throw new Error("Unknown flag: " + flag); 60 } 61 ++i; 62 } 63 } 64 65 void init() { 66 if (numThreads == 0) { 67 numThreads = Runtime.getRuntime().availableProcessors(); 68 } 69 70 if (seed == 0) { 71 seed = (new Random()).nextLong(); 72 } 73 rand = new Random(seed); 74 75 l = new CyclicBarrier(numThreads + 1); 76 77 System.out.printf("Threads: %d\n", numThreads); 78 System.out.printf("Seed: %d\n", seed); 79 } 80 81 final List<Loader> loaders = new ArrayList<>(); 82 83 void prepare() { 84 List<String> c = new ArrayList<>(Arrays.asList(classNames)); 85 86 // Split classes between loading threads 87 int count = (classNames.length / numThreads) + 1; 88 for (int t = 0; t < numThreads; t++) { 89 List<String> sel = new ArrayList<>(); 90 91 System.out.printf("Thread #%d:\n", t); 92 for (int i = 0; i < count; i++) { 93 if (c.size() == 0) break; 94 95 int k = rand.nextInt(c.size()); 96 String elem = c.remove(k); 97 sel.add(elem); 98 System.out.printf("\t%s\n", elem); 99 } 100 loaders.add(new Loader(sel)); 101 } 102 103 // Print diagnostic info when the test hangs 104 Runtime.getRuntime().addShutdownHook(new Thread() { 105 public void run() { 106 boolean alive = false; 107 for (Loader l : loaders) { 108 if (!l.isAlive()) continue; 109 110 if (!alive) { 111 System.out.println("Some threads are still alive:"); 112 alive = true; 113 } 114 115 System.out.println(l.getName()); 116 for (StackTraceElement elem : l.getStackTrace()) { 117 System.out.println("\t"+elem.toString()); 118 } 119 } 120 } 121 }); 122 } 123 124 public void run() throws Throwable { 125 init(); 126 prepare(); 127 128 for (Loader loader : loaders) { 129 loader.start(); 130 } 131 132 l.await(); 133 134 for (Loader loader : loaders) { 135 loader.join(); 136 } 137 } 138 139 class Loader extends Thread { 140 List<String> classes; 141 142 public Loader(List<String> classes) { 143 this.classes = classes; 144 setDaemon(true); 145 } 146 147 @Override 148 public void run() { 149 try { 150 l.await(); 151 152 for (String name : classes) { 153 Class.forName(name).getName(); 154 } 155 } catch (ClassNotFoundException | BrokenBarrierException | InterruptedException e) { 156 throw new Error(e); 157 } 158 } 159 } 160 161 final static String[] classNames = { 162 "java.lang.invoke.CallSite", 163 "java.lang.invoke.ConstantCallSite", 164 "java.lang.invoke.LambdaConversionException", 165 "java.lang.invoke.LambdaMetafactory", 166 "java.lang.invoke.MethodHandle", 167 "java.lang.invoke.MethodHandleInfo", 168 "java.lang.invoke.MethodHandleProxies", 169 "java.lang.invoke.MethodHandles", 170 "java.lang.invoke.MethodType", 171 "java.lang.invoke.MutableCallSite", 172 "java.lang.invoke.SerializedLambda", 173 "java.lang.invoke.SwitchPoint", 174 "java.lang.invoke.VolatileCallSite", 175 "java.lang.invoke.WrongMethodTypeException" 176 }; 177 }