Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GR-56601] Initial support for jcmd. #9963

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* The Universal Permissive License (UPL), Version 1.0
Expand Down Expand Up @@ -40,8 +40,14 @@
*/
package org.graalvm.nativeimage.impl;

import java.io.IOException;

public interface HeapDumpSupport {

void dumpHeap(String outputFile, boolean live) throws java.io.IOException;
/** Overwrites the file if it already exists. */
default void dumpHeap(String outputFile, boolean live) throws IOException {
dumpHeap(outputFile, live, true);
}

void dumpHeap(String outputFile, boolean live, boolean overwrite) throws IOException;
}
1 change: 1 addition & 0 deletions substratevm/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ At runtime, premain runtime options are set along with main class' arguments in
The warning is planned to be replaced by an error in GraalVM for JDK 25.
* (GR-48384) Added a GDB Python script (`gdb-debughelpers.py`) to improve the Native Image debugging experience.
* (GR-49517) Add support for emitting Windows x64 unwind info. This enables stack walking in native tooling such as debuggers and profilers.
* (GR-56601) Together with Red Hat, we added experimental support for `jcmd` on Linux and macOS. Add `--enable-monitoring=jcmd` to your build arguments to try it out.
* (GR-57384) Preserve the origin of a resource included in a native image. The information is included in the report produced by -H:+GenerateEmbeddedResourcesFile.
* (GR-58000) Support for `GetStringUTFLengthAsLong` added in JNI_VERSION_24 ([JDK-8328877](https://bugs.openjdk.org/browse/JDK-8328877))
* (GR-58383) The length of the printed stack trace when using `-XX:MissingRegistrationReportingMode=Warn` can now be set with `-XX:MissingRegistrationWarnContextLines=` and its default length is now 8.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public void log(CCharPointer bytes, UnsignedWord length) {
/* Save and restore errno around calls that would otherwise change errno. */
final int savedErrno = LibC.errno();
try {
if (!PosixUtils.writeBytes(getOutputFile(), bytes, length)) {
if (!PosixUtils.write(getOutputFile(), bytes, length)) {
/*
* We are in a low-level log routine and output failed, so there is little we can
* do.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,9 @@
import com.oracle.svm.core.Uninterruptible;
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
import com.oracle.svm.core.feature.InternalFeature;
import com.oracle.svm.core.headers.LibC;
import com.oracle.svm.core.memory.UntrackedNullableNativeMemory;
import com.oracle.svm.core.os.AbstractRawFileOperationSupport;
import com.oracle.svm.core.os.AbstractRawFileOperationSupport.RawFileOperationSupportHolder;
import com.oracle.svm.core.posix.headers.Errno;
import com.oracle.svm.core.posix.headers.Fcntl;
import com.oracle.svm.core.posix.headers.Unistd;
import com.oracle.svm.core.util.VMError;
Expand Down Expand Up @@ -152,35 +150,14 @@ public boolean seek(RawFileDescriptor fd, long position) {
@Override
public boolean write(RawFileDescriptor fd, Pointer data, UnsignedWord size) {
int posixFd = getPosixFileDescriptor(fd);

Pointer position = data;
UnsignedWord remaining = size;
while (remaining.aboveThan(0)) {
SignedWord writtenBytes = Unistd.NoTransitions.write(posixFd, position, remaining);
if (writtenBytes.equal(-1)) {
if (LibC.errno() == Errno.EINTR()) {
// Retry the write if it was interrupted before any bytes were written.
continue;
}
return false;
}
position = position.add((UnsignedWord) writtenBytes);
remaining = remaining.subtract((UnsignedWord) writtenBytes);
}
return true;
return PosixUtils.writeUninterruptibly(posixFd, data, size);
}

@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
@Override
public long read(RawFileDescriptor fd, Pointer buffer, UnsignedWord bufferSize) {
int posixFd = getPosixFileDescriptor(fd);

SignedWord readBytes;
do {
readBytes = Unistd.NoTransitions.read(posixFd, buffer, bufferSize);
} while (readBytes.equal(-1) && LibC.errno() == Errno.EINTR());

return readBytes.rawValue();
return PosixUtils.readUninterruptibly(posixFd, buffer, bufferSize);
}

@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@

import com.oracle.svm.core.Uninterruptible;
import com.oracle.svm.core.graal.stackvalue.UnsafeStackValue;
import com.oracle.svm.core.headers.LibC;
import com.oracle.svm.core.posix.headers.Errno;
import com.oracle.svm.core.posix.headers.PosixDirectives;
import com.oracle.svm.core.posix.headers.darwin.DarwinStat;
import com.oracle.svm.core.posix.headers.linux.LinuxStat;
Expand Down Expand Up @@ -167,6 +169,26 @@ public interface stat extends PointerBase {
UnsignedWord st_nlink();
}

@Uninterruptible(reason = "LibC.errno() must not be overwritten accidentally.")
public static int restartableFstat(int fd, PosixStat.stat buf) {
int result;
do {
result = PosixStat.NoTransitions.fstat(fd, buf);
} while (result == -1 && LibC.errno() == Errno.EINTR());

return result;
}

@Uninterruptible(reason = "LibC.errno() must not be overwritten accidentally.")
public static int restartableLstat(CCharPointer path, PosixStat.stat buf) {
int result;
do {
result = PosixStat.NoTransitions.lstat(path, buf);
} while (result == -1 && LibC.errno() == Errno.EINTR());

return result;
}

@Platforms(Platform.HOSTED_ONLY.class)
private PosixStat() {
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,18 @@
*/
package com.oracle.svm.core.posix;

import static com.oracle.svm.core.Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE;
import static com.oracle.svm.core.posix.headers.Unistd._SC_GETPW_R_SIZE_MAX;

import java.io.FileDescriptor;
import java.io.IOException;

import org.graalvm.nativeimage.Platform;
import org.graalvm.nativeimage.StackValue;
import org.graalvm.nativeimage.c.type.CCharPointer;
import org.graalvm.nativeimage.c.type.CIntPointer;
import org.graalvm.nativeimage.c.type.CTypeConversion;
import org.graalvm.nativeimage.c.type.CTypeConversion.CCharPointerHolder;
import org.graalvm.word.Pointer;
import org.graalvm.word.PointerBase;
import org.graalvm.word.SignedWord;
import org.graalvm.word.UnsignedWord;
Expand All @@ -48,6 +49,8 @@
import com.oracle.svm.core.c.libc.LibCBase;
import com.oracle.svm.core.graal.stackvalue.UnsafeStackValue;
import com.oracle.svm.core.headers.LibC;
import com.oracle.svm.core.hub.DynamicHub;
import com.oracle.svm.core.hub.LayoutEncoding;
import com.oracle.svm.core.memory.NullableNativeMemory;
import com.oracle.svm.core.nmt.NmtCategory;
import com.oracle.svm.core.posix.headers.Dlfcn;
Expand All @@ -61,9 +64,12 @@
import com.oracle.svm.core.posix.headers.Wait;
import com.oracle.svm.core.posix.headers.darwin.DarwinTime;
import com.oracle.svm.core.posix.headers.linux.LinuxTime;
import com.oracle.svm.core.snippets.KnownIntrinsics;
import com.oracle.svm.core.util.BasedOnJDKFile;
import com.oracle.svm.core.util.VMError;

import jdk.graal.compiler.word.Word;

public class PosixUtils {
static String setLocale(String category, String locale) {
int intCategory = getCategory(category);
Expand Down Expand Up @@ -140,10 +146,6 @@ public static String lastErrorString(String defaultMsg) {
return errorString(errno, defaultMsg);
}

public static IOException newIOExceptionWithLastError(String defaultMsg) {
return new IOException(lastErrorString(defaultMsg));
}

/** Return the error string for the given error number, or a default message. */
public static String errorString(int errno, String defaultMsg) {
String result = "";
Expand Down Expand Up @@ -194,25 +196,52 @@ public static int waitForProcessExit(int ppid) {
* Low-level output of bytes already in native memory. This method is allocation free, so that
* it can be used, e.g., in low-level logging routines.
*/
public static boolean writeBytes(FileDescriptor descriptor, CCharPointer bytes, UnsignedWord length) {
CCharPointer curBuf = bytes;
UnsignedWord curLen = length;
while (curLen.notEqual(0)) {
public static boolean write(FileDescriptor descriptor, CCharPointer data, UnsignedWord size) {
CCharPointer position = data;
UnsignedWord remaining = size;
while (remaining.notEqual(0)) {
int fd = getFD(descriptor);
if (fd == -1) {
return false;
}

SignedWord n = Unistd.write(fd, curBuf, curLen);
if (n.equal(-1)) {
SignedWord writtenBytes = Unistd.write(fd, position, remaining);
if (writtenBytes.equal(-1)) {
if (LibC.errno() == Errno.EINTR()) {
// Retry the write if it was interrupted before any bytes were written.
continue;
}
return false;
}
curBuf = curBuf.addressOf(n);
curLen = curLen.subtract((UnsignedWord) n);
position = position.addressOf(writtenBytes);
remaining = remaining.subtract((UnsignedWord) writtenBytes);
}
return true;
}

@Uninterruptible(reason = "Array must not move.")
public static boolean writeUninterruptibly(int fd, byte[] data) {
DynamicHub hub = KnownIntrinsics.readHub(data);
UnsignedWord baseOffset = LayoutEncoding.getArrayBaseOffset(hub.getLayoutEncoding());
Pointer dataPtr = Word.objectToUntrackedPointer(data).add(baseOffset);
return writeUninterruptibly(fd, dataPtr, WordFactory.unsigned(data.length));
}

@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
public static boolean writeUninterruptibly(int fd, Pointer data, UnsignedWord size) {
Pointer position = data;
UnsignedWord remaining = size;
while (remaining.notEqual(0)) {
SignedWord writtenBytes = Unistd.NoTransitions.write(fd, position, remaining);
if (writtenBytes.equal(-1)) {
if (LibC.errno() == Errno.EINTR()) {
// Retry the write if it was interrupted before any bytes were written.
continue;
}
return false;
}
position = position.add((UnsignedWord) writtenBytes);
remaining = remaining.subtract((UnsignedWord) writtenBytes);
}
return true;
}
Expand Down Expand Up @@ -249,17 +278,35 @@ public static void checkStatusIs0(int status, String message) {
VMError.guarantee(status == 0, message);
}

@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public static int readBytes(int fd, CCharPointer buffer, int bufferLen, int readOffset) {
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
public static int readUninterruptibly(int fd, Pointer buffer, int bufferLen, int bufferOffset) {
int readBytes = -1;
if (readOffset < bufferLen) {
if (bufferOffset < bufferLen) {
do {
readBytes = (int) Unistd.NoTransitions.read(fd, buffer.addressOf(readOffset), WordFactory.unsigned(bufferLen - readOffset)).rawValue();
readBytes = (int) Unistd.NoTransitions.read(fd, buffer.add(bufferOffset), WordFactory.unsigned(bufferLen - bufferOffset)).rawValue();
} while (readBytes == -1 && LibC.errno() == Errno.EINTR());
}
return readBytes;
}

@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
public static int readUninterruptibly(int fd, Pointer buffer, int bufferSize) {
VMError.guarantee(bufferSize >= 0);
long readBytes = readUninterruptibly(fd, buffer, WordFactory.unsigned(bufferSize));
assert (int) readBytes == readBytes;
return (int) readBytes;
}

@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
public static long readUninterruptibly(int fd, Pointer buffer, UnsignedWord bufferSize) {
SignedWord readBytes;
do {
readBytes = Unistd.NoTransitions.read(fd, buffer, bufferSize);
} while (readBytes.equal(-1) && LibC.errno() == Errno.EINTR());

return readBytes.rawValue();
}

// Checkstyle: stop
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public static int clock_gettime(int clock_id, Time.timespec ts) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.svm.core.posix.attach;

import org.graalvm.nativeimage.c.function.CFunction;
import org.graalvm.nativeimage.c.function.CLibrary;
import org.graalvm.nativeimage.c.type.CCharPointer;

/** C methods that are used to support the attach API. */
@CLibrary(value = "libchelper", requireStatic = true)
public class AttachHelper {
@CFunction(value = "svm_attach_startup")
public static native void startup(CCharPointer path);

@CFunction(value = "svm_attach_listener_cleanup")
public static native void listenerCleanup(int listenerSocket, CCharPointer path);

/** Returns true if the socket file is valid. */
@CFunction(value = "svm_attach_check_socket_file")
public static native boolean checkSocketFile(CCharPointer path);

@CFunction(value = "svm_attach_is_init_trigger")
public static native boolean isInitTrigger(CCharPointer path);

@CFunction(value = "svm_attach_create_listener")
public static native int createListener(CCharPointer path);

@CFunction(value = "svm_attach_wait_for_request")
public static native int waitForRequest(int listenerSocket);

@CFunction(value = "svm_attach_shutdown_socket")
public static native void shutdownSocket(int socket);
}
Loading