1 /* |
1 /* |
2 * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. |
2 * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * |
4 * |
5 * This code is free software; you can redistribute it and/or modify it |
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 |
6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. |
7 * published by the Free Software Foundation. |
27 * @summary Exercise the java.lang.instrument.Instrumentation APIs on classes archived |
27 * @summary Exercise the java.lang.instrument.Instrumentation APIs on classes archived |
28 * using CDS/AppCDSv1/AppCDSv2. |
28 * using CDS/AppCDSv1/AppCDSv2. |
29 * @library /test/lib /test/hotspot/jtreg/runtime/appcds /test/hotspot/jtreg/runtime/appcds/test-classes |
29 * @library /test/lib /test/hotspot/jtreg/runtime/appcds /test/hotspot/jtreg/runtime/appcds/test-classes |
30 * @requires vm.cds |
30 * @requires vm.cds |
31 * @requires vm.flavor != "minimal" |
31 * @requires vm.flavor != "minimal" |
32 * @modules java.base/jdk.internal.misc |
|
33 * jdk.jartool/sun.tools.jar |
|
34 * java.management |
|
35 * @build sun.hotspot.WhiteBox |
32 * @build sun.hotspot.WhiteBox |
36 * InstrumentationApp |
33 * InstrumentationApp |
37 * InstrumentationClassFileTransformer |
34 * InstrumentationClassFileTransformer |
38 * InstrumentationRegisterClassFileTransformer |
35 * InstrumentationRegisterClassFileTransformer |
39 * @run main/othervm InstrumentationTest |
36 * @run main/othervm InstrumentationTest |
41 |
38 |
42 // Note: TestCommon is from /test/hotspot/jtreg/runtime/appcds/TestCommon.java |
39 // Note: TestCommon is from /test/hotspot/jtreg/runtime/appcds/TestCommon.java |
43 // Note: Util is from /test/hotspot/jtreg/runtime/appcds/test-classes/TestCommon.java |
40 // Note: Util is from /test/hotspot/jtreg/runtime/appcds/test-classes/TestCommon.java |
44 |
41 |
45 import com.sun.tools.attach.VirtualMachine; |
42 import com.sun.tools.attach.VirtualMachine; |
46 import com.sun.tools.attach.VirtualMachineDescriptor; |
|
47 import java.io.File; |
43 import java.io.File; |
48 import java.io.FileOutputStream; |
44 import java.io.FileInputStream; |
49 import java.util.List; |
45 import java.util.Scanner; |
50 import jdk.test.lib.Asserts; |
46 import jdk.test.lib.Asserts; |
51 import jdk.test.lib.cds.CDSOptions; |
47 import jdk.test.lib.cds.CDSOptions; |
52 import jdk.test.lib.process.OutputAnalyzer; |
48 import jdk.test.lib.process.OutputAnalyzer; |
53 import jdk.test.lib.process.ProcessTools; |
49 import jdk.test.lib.process.ProcessTools; |
54 |
50 |
177 static AgentAttachThread doAttach(boolean attachAgent, String flagFile, String agentJar) throws Throwable { |
173 static AgentAttachThread doAttach(boolean attachAgent, String flagFile, String agentJar) throws Throwable { |
178 if (!attachAgent) { |
174 if (!attachAgent) { |
179 return null; |
175 return null; |
180 } |
176 } |
181 |
177 |
182 // We use the flagFile to prevent the child process to make progress, until we have |
178 // Hand-shake protocol with the child process |
183 // attached to it. |
179 // [1] Parent process (this process) launches child process (InstrumentationApp) |
|
180 // and then waits until child process writes its pid into the flagFile. |
|
181 // [2] Child process process starts up, writes its pid into the flagFile, |
|
182 // and waits for the flagFile to be deleted. |
|
183 // [3] When parent process gets the pid, it attaches to the child process |
|
184 // (if we attempt to attach to a process too early, the SIGQUIT |
|
185 // may cause the child to die) and deletes the flagFile. |
|
186 // [4] Child process resumes execution. |
|
187 |
184 File f = new File(flagFile); |
188 File f = new File(flagFile); |
185 try (FileOutputStream o = new FileOutputStream(f)) { |
189 f.delete(); |
186 o.write(1); |
190 if (f.exists()) { |
187 } |
191 throw new RuntimeException("Flag file should not exist: " + f); |
188 if (!f.exists()) { |
|
189 throw new RuntimeException("Failed to create " + f); |
|
190 } |
192 } |
191 |
193 |
192 // At this point, the child process is not yet launched. Note that |
194 // At this point, the child process is not yet launched. Note that |
193 // TestCommon.exec() and OutputAnalyzer.OutputAnalyzer() both block |
195 // TestCommon.exec() and OutputAnalyzer.OutputAnalyzer() both block |
194 // until the child process has finished. |
196 // until the child process has finished. |
195 // |
197 // |
196 // So, we will launch a AgentAttachThread which will poll the system |
198 // So, we will launch a AgentAttachThread which will poll the flagFile |
197 // until the child process is launched, and then do the attachment. |
199 // until the child process is launched. |
198 // The child process is uniquely identified by having flagFile in its |
|
199 // command-line -- see AgentAttachThread.getPid(). |
|
200 AgentAttachThread t = new AgentAttachThread(flagFile, agentJar); |
200 AgentAttachThread t = new AgentAttachThread(flagFile, agentJar); |
201 t.start(); |
201 t.start(); |
202 return t; |
202 return t; |
203 } |
203 } |
204 |
204 |
223 while (true) { |
223 while (true) { |
224 // Keep polling until the child process has been launched. If for some |
224 // Keep polling until the child process has been launched. If for some |
225 // reason the child process fails to launch, this test will be terminated |
225 // reason the child process fails to launch, this test will be terminated |
226 // by JTREG's time-out mechanism. |
226 // by JTREG's time-out mechanism. |
227 Thread.sleep(100); |
227 Thread.sleep(100); |
228 List<VirtualMachineDescriptor> vmds = VirtualMachine.list(); |
228 File f = new File(flagFile); |
229 for (VirtualMachineDescriptor vmd : vmds) { |
229 if (f.exists() && f.length() > 100) { |
230 if (vmd.displayName().contains(flagFile) && vmd.displayName().contains("InstrumentationApp")) { |
230 try (FileInputStream in = new FileInputStream(f)) { |
231 // We use flagFile (which has the PID of this process) as a unique identifier |
231 Scanner scanner = new Scanner(in); |
232 // to ident the child process, which we want to attach to. |
232 return Long.toString(scanner.nextLong()); |
233 System.out.println("Process found: " + vmd.id() + " " + vmd.displayName()); |
233 } catch (Throwable t) { |
234 return vmd.id(); |
234 // This may happen on Windows if the child process has not |
|
235 // fully closed the output stream to the flagFile |
|
236 System.out.println("Ignored: " + t); |
|
237 t.printStackTrace(System.out); |
|
238 continue; |
235 } |
239 } |
236 } |
240 } |
237 } |
241 } |
238 } |
242 } |
239 |
243 |
240 public void run() { |
244 public void run() { |
241 try { |
245 try { |
242 String pid = getPid(flagFile); |
246 String pid = getPid(flagFile); |
|
247 System.out.println("child pid = " + pid); |
243 VirtualMachine vm = VirtualMachine.attach(pid); |
248 VirtualMachine vm = VirtualMachine.attach(pid); |
244 System.out.println(agentJar); |
249 System.out.println(agentJar); |
245 vm.loadAgent(agentJar); |
250 vm.loadAgent(agentJar); |
246 } catch (Throwable t) { |
251 } catch (Throwable t) { |
247 t.printStackTrace(); |
252 t.printStackTrace(); |