1 /* 2 * Copyright (c) 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 8072466 27 * @summary Deadlock when initializing MulticastSocket and DatagramSocket 28 * @library /lib/testlibrary 29 * @library /test/lib 30 * @build jdk.testlibrary.* 31 * @run main/othervm MultiDead 32 */ 33 34 import java.net.DatagramSocket; 35 import java.net.MulticastSocket; 36 import java.util.concurrent.atomic.AtomicBoolean; 37 import java.util.concurrent.atomic.AtomicReference; 38 import java.util.concurrent.CountDownLatch; 39 import static java.util.concurrent.TimeUnit.MILLISECONDS; 40 import jdk.test.lib.JDKToolLauncher; 41 import jdk.testlibrary.Utils; 42 43 public class MultiDead { 44 private static final int THREAD_PAIR_COUNT = 4; 45 private static final int CHILDREN_COUNT = 20; 46 // at least 2.5 seconds for a child to complete 47 private static final long CHILD_TIMEOUT = 2500; 48 private static final long TIMEOUT = 49 Utils.adjustTimeout(CHILDREN_COUNT * CHILD_TIMEOUT * 2); 50 51 public static void main(String[] args) throws Throwable { 52 if (args.length == 0 || args[0].equals("parent")) { 53 parentProcess(); 54 } 55 56 if (args.length > 0 && args[0].equals("child")) { 57 childProcess(); 58 } 59 } 60 61 private static void parentProcess() throws Throwable { 62 JDKToolLauncher launcher = JDKToolLauncher 63 .createUsingTestJDK("java") 64 .addToolArg("MultiDead") 65 .addToolArg("child"); 66 ProcessBuilder pb = new ProcessBuilder(launcher.getCommand()); 67 68 AtomicReference<Process> child = new AtomicReference<>(); 69 AtomicBoolean stopFlag = new AtomicBoolean(false); 70 71 Thread th = new Thread(() -> { 72 for (int i = 0; i < CHILDREN_COUNT; ++i) { 73 System.out.println("child #" + (i + 1) + " of " + 74 CHILDREN_COUNT); 75 long start = System.nanoTime(); 76 try { 77 child.set(pb.start()); 78 child.get().waitFor(); 79 if (stopFlag.get()) { 80 break; 81 } 82 } catch (Exception e) { 83 throw new RuntimeException(e); 84 } 85 if (System.nanoTime() - start > 86 MILLISECONDS.toNanos(CHILD_TIMEOUT)) { 87 System.err.println("Machine is too slow, " + 88 "skipping the test..."); 89 break; 90 } 91 } 92 }); 93 94 th.start(); 95 th.join(TIMEOUT); 96 97 stopFlag.set(true); 98 if (th.isAlive()) { 99 if (child.get() != null) { 100 child.get().destroyForcibly(); 101 } 102 throw new RuntimeException("Failed to complete on time."); 103 } 104 } 105 106 private static void childProcess() { 107 CountDownLatch latch = new CountDownLatch(1); 108 for (int i = 0; i < THREAD_PAIR_COUNT; ++i) { 109 new Thread(() -> { 110 try { 111 latch.await(); 112 try (MulticastSocket a = new MulticastSocket(6000)) { 113 } 114 } catch (Exception ignore) { 115 } 116 }).start(); 117 118 new Thread(() -> { 119 try { 120 latch.await(); 121 try (DatagramSocket b = new DatagramSocket(6000)) { 122 } 123 } catch (Exception ignore) { 124 } 125 }).start(); 126 } 127 latch.countDown(); 128 } 129 }