Skip to content

Commit 12edcff

Browse files
committed
8344671: Few JFR streaming tests fail with application not alive error on MacOS 15
Reviewed-by: mdoerr, phh Backport-of: d979bd859215a16e6398ae627acfd40e8d71102c
1 parent dfa0f73 commit 12edcff

File tree

2 files changed

+57
-13
lines changed

2 files changed

+57
-13
lines changed

src/jdk.attach/macosx/classes/sun/tools/attach/VirtualMachineImpl.java

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -70,32 +70,35 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine {
7070
if (!socket_file.exists()) {
7171
File f = createAttachFile(pid);
7272
try {
73-
sendQuitTo(pid);
73+
checkCatchesAndSendQuitTo(pid, false);
7474

7575
// give the target VM time to start the attach mechanism
7676
final int delay_step = 100;
7777
final long timeout = attachTimeout();
78-
long time_spend = 0;
78+
long time_spent = 0;
7979
long delay = 0;
80+
81+
boolean timedout = false;
8082
do {
8183
// Increase timeout on each attempt to reduce polling
8284
delay += delay_step;
8385
try {
8486
Thread.sleep(delay);
8587
} catch (InterruptedException x) { }
8688

87-
time_spend += delay;
88-
if (time_spend > timeout/2 && !socket_file.exists()) {
89+
timedout = (time_spent += delay) > timeout;
90+
91+
if (time_spent > timeout/2 && !socket_file.exists()) {
8992
// Send QUIT again to give target VM the last chance to react
90-
sendQuitTo(pid);
93+
checkCatchesAndSendQuitTo(pid, !timedout);
9194
}
92-
} while (time_spend <= timeout && !socket_file.exists());
95+
} while (!timedout && !socket_file.exists());
9396
if (!socket_file.exists()) {
9497
throw new AttachNotSupportedException(
9598
String.format("Unable to open socket file %s: " +
9699
"target process %d doesn't respond within %dms " +
97100
"or HotSpot VM not loaded", socket_path,
98-
pid, time_spend));
101+
pid, time_spent));
99102
}
100103
} finally {
101104
f.delete();
@@ -227,7 +230,7 @@ private File createAttachFile(int pid) throws IOException {
227230

228231
//-- native methods
229232

230-
static native void sendQuitTo(int pid) throws IOException;
233+
static native boolean checkCatchesAndSendQuitTo(int pid, boolean throwIfNotReady) throws IOException, AttachNotSupportedException;
231234

232235
static native void checkPermissions(String path) throws IOException;
233236

src/jdk.attach/macosx/native/libattach/VirtualMachineImpl.c

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,13 @@
2828
#include <sys/socket.h>
2929
#include <sys/stat.h>
3030
#include <sys/syslimits.h>
31+
#include <sys/sysctl.h>
3132
#include <sys/types.h>
3233
#include <sys/un.h>
3334
#include <errno.h>
3435
#include <fcntl.h>
3536
#include <signal.h>
37+
#include <stdbool.h>
3638
#include <stdio.h>
3739
#include <stdlib.h>
3840
#include <string.h>
@@ -116,15 +118,54 @@ JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_connect
116118

117119
/*
118120
* Class: sun_tools_attach_VirtualMachineImpl
119-
* Method: sendQuitTo
121+
* Method: checkCatchesAndSendQuitTo
120122
* Signature: (I)V
121123
*/
122-
JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_sendQuitTo
123-
(JNIEnv *env, jclass cls, jint pid)
124+
JNIEXPORT jboolean JNICALL Java_sun_tools_attach_VirtualMachineImpl_checkCatchesAndSendQuitTo
125+
(JNIEnv *env, jclass cls, jint pid, jboolean throwIfNotReady)
124126
{
125-
if (kill((pid_t)pid, SIGQUIT)) {
126-
JNU_ThrowIOExceptionWithLastError(env, "kill");
127+
int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, (int)pid };
128+
129+
struct kinfo_proc kiproc;
130+
size_t kipsz = sizeof(struct kinfo_proc);
131+
132+
/*
133+
* Early in the lifetime of a JVM it has not yet initialized its signal handlers, in particular the QUIT
134+
* handler, note that the default behavior of QUIT is to terminate the receiving process, if unhandled.
135+
*
136+
* Since we use QUIT to initiate an attach operation, if we signal a JVM during this period early in its
137+
* lifetime before it has initialized its QUIT handler, such a signal delivery will terminate the JVM we
138+
* are attempting to attach to!
139+
*
140+
* The following code guards the QUIT delivery by testing the current signal masks. It is okay to send QUIT
141+
* if the signal is caught but not ignored, as that implies a handler has been installed.
142+
*/
143+
144+
if (sysctl(mib, sizeof(mib) / sizeof(int), &kiproc, &kipsz, NULL, 0) == 0) {
145+
const bool ignored = (kiproc.kp_proc.p_sigignore & sigmask(SIGQUIT)) != 0;
146+
const bool caught = (kiproc.kp_proc.p_sigcatch & sigmask(SIGQUIT)) != 0;
147+
148+
// note: obviously the masks could change between testing and signalling however this is not the
149+
// observed behavior of the current JVM implementation.
150+
151+
if (caught && !ignored) {
152+
if (kill((pid_t)pid, SIGQUIT) != 0) {
153+
JNU_ThrowIOExceptionWithLastError(env, "kill");
154+
} else {
155+
return JNI_TRUE;
156+
}
157+
} else if (throwIfNotReady) {
158+
char msg[100];
159+
160+
snprintf(msg, sizeof(msg), "pid: %d, state is not ready to participate in attach handshake!", (int)pid);
161+
162+
JNU_ThrowByName(env, "com/sun/tools/attach/AttachNotSupportedException", msg);
163+
}
164+
} else {
165+
JNU_ThrowIOExceptionWithLastError(env, "sysctl");
127166
}
167+
168+
return JNI_FALSE;
128169
}
129170

130171
/*

0 commit comments

Comments
 (0)