Skip to content

Commit

Permalink
Initial jcmd support.
Browse files Browse the repository at this point in the history
  • Loading branch information
christianhaeubl committed Oct 30, 2024
1 parent dfa18cb commit 10528ff
Show file tree
Hide file tree
Showing 73 changed files with 2,882 additions and 2,238 deletions.
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.
* (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

0 comments on commit 10528ff

Please sign in to comment.