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