Skip to content

Commit 34f76e3

Browse files
committed
8344671: Few JFR streaming tests fail with application not alive error on MacOS 15
Backport-of: 12edcff1fcf19955de67d8d34e03f080ed905db6
1 parent e213403 commit 34f76e3

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
@@ -74,32 +74,35 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine {
7474
if (!socket_file.exists()) {
7575
File f = createAttachFile(pid);
7676
try {
77-
sendQuitTo(pid);
77+
checkCatchesAndSendQuitTo(pid, false);
7878

7979
// give the target VM time to start the attach mechanism
8080
final int delay_step = 100;
8181
final long timeout = attachTimeout();
82-
long time_spend = 0;
82+
long time_spent = 0;
8383
long delay = 0;
84+
85+
boolean timedout = false;
8486
do {
8587
// Increase timeout on each attempt to reduce polling
8688
delay += delay_step;
8789
try {
8890
Thread.sleep(delay);
8991
} catch (InterruptedException x) { }
9092

91-
time_spend += delay;
92-
if (time_spend > timeout/2 && !socket_file.exists()) {
93+
timedout = (time_spent += delay) > timeout;
94+
95+
if (time_spent > timeout/2 && !socket_file.exists()) {
9396
// Send QUIT again to give target VM the last chance to react
94-
sendQuitTo(pid);
97+
checkCatchesAndSendQuitTo(pid, !timedout);
9598
}
96-
} while (time_spend <= timeout && !socket_file.exists());
99+
} while (!timedout && !socket_file.exists());
97100
if (!socket_file.exists()) {
98101
throw new AttachNotSupportedException(
99102
String.format("Unable to open socket file %s: " +
100103
"target process %d doesn't respond within %dms " +
101104
"or HotSpot VM not loaded", socket_path,
102-
pid, time_spend));
105+
pid, time_spent));
103106
}
104107
} finally {
105108
f.delete();
@@ -296,7 +299,7 @@ private File createAttachFile(int pid) throws IOException {
296299

297300
//-- native methods
298301

299-
static native void sendQuitTo(int pid) throws IOException;
302+
static native boolean checkCatchesAndSendQuitTo(int pid, boolean throwIfNotReady) throws IOException, AttachNotSupportedException;
300303

301304
static native void checkPermissions(String path) throws IOException;
302305

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)