1 /* 2 * Copyright (c) 2019, 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 8225690 27 * @requires os.family != "windows" 28 * @library /test/lib 29 * @modules jdk.attach/com.sun.tools.attach 30 * @run main ConcAttachTest 31 */ 32 33 import java.io.IOException; 34 import java.util.concurrent.CountDownLatch; 35 import java.util.concurrent.Executors; 36 import java.util.concurrent.ExecutorService; 37 import java.util.concurrent.TimeUnit; 38 39 import com.sun.tools.attach.VirtualMachine; 40 import com.sun.tools.attach.AttachNotSupportedException; 41 42 import jdk.test.lib.apps.LingeredApp; 43 import jdk.test.lib.Asserts; 44 import jdk.test.lib.JDKToolLauncher; 45 import jdk.test.lib.process.OutputAnalyzer; 46 47 public class ConcAttachTest implements Runnable { 48 49 private static final int NUM_CONC_REQUESTS = 100; 50 51 private static final int THREAD_POOL_TIMEOUT_IN_SEC = 30; 52 53 private static CountDownLatch latch; 54 55 private static String strPID; 56 57 // Attach to LingeredApp concurrently. 58 public void run() { 59 VirtualMachine vm = null; 60 61 try { 62 latch.countDown(); 63 latch.await(); 64 } catch (InterruptedException e) { 65 throw new RuntimeException(e); 66 } 67 68 try { 69 vm = VirtualMachine.attach(strPID); 70 } catch (AttachNotSupportedException | IOException e) { 71 throw new RuntimeException(e); 72 } finally { 73 try { 74 vm.detach(); 75 } catch (IOException e) { 76 throw new RuntimeException(e); 77 } 78 } 79 } 80 81 private static void checkAttachListenerThread() throws InterruptedException, IOException { 82 JDKToolLauncher jcmd = JDKToolLauncher.createUsingTestJDK("jcmd"); 83 jcmd.addToolArg(strPID); 84 jcmd.addToolArg("Thread.print"); 85 86 ProcessBuilder pb = new ProcessBuilder(jcmd.getCommand()); 87 Process jcmdProc = pb.start(); 88 89 OutputAnalyzer out = new OutputAnalyzer(jcmdProc); 90 91 jcmdProc.waitFor(); 92 93 System.out.println(out.getStdout()); 94 System.err.println(out.getStderr()); 95 96 long numOfAttachListener = out.asLines() 97 .stream() 98 .filter(l -> l.contains("Attach Listener")) 99 .count(); 100 101 Asserts.assertEquals(1L, numOfAttachListener, "AttachListener should exist only 1 thread."); 102 } 103 104 public static void main(String... args) throws Exception { 105 LingeredApp app = null; 106 latch = new CountDownLatch(NUM_CONC_REQUESTS); 107 ExecutorService pool = Executors.newFixedThreadPool(NUM_CONC_REQUESTS); 108 109 try { 110 app = LingeredApp.startApp(); 111 strPID = Long.toString(app.getPid()); 112 113 for (int i = 0; i < NUM_CONC_REQUESTS; i++) { 114 pool.submit(new ConcAttachTest()); 115 } 116 117 pool.shutdown(); 118 pool.awaitTermination(THREAD_POOL_TIMEOUT_IN_SEC, TimeUnit.SECONDS); 119 120 checkAttachListenerThread(); 121 } finally { 122 LingeredApp.stopApp(app); 123 } 124 } 125 126 }