Skip to content

Commit 6d6cd04

Browse files
Add a logging mechanism that can be used from uninterruptible code.
1 parent 83f240c commit 6d6cd04

File tree

24 files changed

+1794
-993
lines changed

24 files changed

+1794
-993
lines changed
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
* Copyright (c) 2025, 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
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
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
package com.oracle.svm.core.posix;
26+
27+
import static com.oracle.svm.core.Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE;
28+
29+
import java.util.EnumSet;
30+
31+
import org.graalvm.nativeimage.c.type.CCharPointer;
32+
import org.graalvm.word.Pointer;
33+
import org.graalvm.word.UnsignedWord;
34+
35+
import com.oracle.svm.core.Uninterruptible;
36+
import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton;
37+
import com.oracle.svm.core.headers.LibC;
38+
import com.oracle.svm.core.layeredimagesingleton.InitialLayerOnlyImageSingleton;
39+
import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonBuilderFlags;
40+
import com.oracle.svm.core.log.StdErrWriter;
41+
import com.oracle.svm.core.util.VMError;
42+
43+
@AutomaticallyRegisteredImageSingleton(value = StdErrWriter.class)
44+
class PosixStdErrWriter implements StdErrWriter, InitialLayerOnlyImageSingleton {
45+
private static final int STDERR_FD = 2;
46+
47+
@Override
48+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
49+
public void log(CCharPointer bytes, UnsignedWord length) {
50+
/* Save and restore errno around calls that would otherwise change errno. */
51+
int savedErrno = LibC.errno();
52+
try {
53+
if (!PosixUtils.writeUninterruptibly(STDERR_FD, (Pointer) bytes, length)) {
54+
throw VMError.shouldNotReachHere("Writing to stderr failed.");
55+
}
56+
} finally {
57+
LibC.setErrno(savedErrno);
58+
}
59+
}
60+
61+
@Override
62+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
63+
public void flush() {
64+
/* Save and restore errno around calls that would otherwise change errno. */
65+
int savedErrno = LibC.errno();
66+
try {
67+
/* Flush and ignore errors. */
68+
PosixUtils.flushUninterruptibly(STDERR_FD);
69+
} finally {
70+
LibC.setErrno(savedErrno);
71+
}
72+
}
73+
74+
@Override
75+
public EnumSet<LayeredImageSingletonBuilderFlags> getImageBuilderFlags() {
76+
return LayeredImageSingletonBuilderFlags.RUNTIME_ACCESS_ONLY;
77+
}
78+
79+
@Override
80+
public boolean accessibleInFutureLayers() {
81+
return true;
82+
}
83+
}

substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixUtils.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,11 @@ public static boolean flush(FileDescriptor descriptor) {
252252
return Unistd.fsync(fd) == 0;
253253
}
254254

255+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
256+
public static boolean flushUninterruptibly(int fd) {
257+
return Unistd.NoTransitions.fsync(fd) == 0;
258+
}
259+
255260
public static PointerBase dlopen(String file, int mode) {
256261
try (CCharPointerHolder pathPin = CTypeConversion.toCString(file)) {
257262
CCharPointer pathPtr = pathPin.get();

substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/headers/Unistd.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,5 +142,8 @@ public static class NoTransitions {
142142

143143
@CFunction(transition = Transition.NO_TRANSITION)
144144
public static native int geteuid();
145+
146+
@CFunction(transition = Transition.NO_TRANSITION)
147+
public static native int fsync(int fd);
145148
}
146149
}

substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsLogHandler.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,13 @@
3232
import com.oracle.svm.core.headers.LibC;
3333
import com.oracle.svm.core.thread.VMThreads;
3434
import com.oracle.svm.core.windows.headers.FileAPI;
35+
import com.oracle.svm.core.windows.headers.WinBase.HANDLE;
3536

3637
public class WindowsLogHandler implements LogHandler {
3738

3839
@Override
3940
public void log(CCharPointer bytes, UnsignedWord length) {
40-
if (!WindowsUtils.writeBytes(getOutputFile(), bytes, length)) {
41+
if (!WindowsUtils.write(getOutputFile(), bytes, length)) {
4142
/*
4243
* We are in a low-level log routine and output failed, so there is little we can do.
4344
*/
@@ -60,7 +61,7 @@ public void fatalError() {
6061
LibC.abort();
6162
}
6263

63-
private static int getOutputFile() {
64+
private static HANDLE getOutputFile() {
6465
// [TODO] Change to use FileDescriptor.err once FileDescriptor class is functional
6566
return FileAPI.GetStdHandle(FileAPI.STD_ERROR_HANDLE());
6667
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright (c) 2025, 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
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
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
package com.oracle.svm.core.windows;
26+
27+
import static com.oracle.svm.core.Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE;
28+
29+
import java.util.EnumSet;
30+
31+
import org.graalvm.nativeimage.c.type.CCharPointer;
32+
import org.graalvm.word.UnsignedWord;
33+
34+
import com.oracle.svm.core.Uninterruptible;
35+
import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton;
36+
import com.oracle.svm.core.layeredimagesingleton.InitialLayerOnlyImageSingleton;
37+
import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonBuilderFlags;
38+
import com.oracle.svm.core.log.StdErrWriter;
39+
import com.oracle.svm.core.util.VMError;
40+
import com.oracle.svm.core.windows.headers.FileAPI;
41+
import com.oracle.svm.core.windows.headers.WinBase.HANDLE;
42+
43+
@AutomaticallyRegisteredImageSingleton(value = StdErrWriter.class)
44+
class WindowsStdErrWriter implements StdErrWriter, InitialLayerOnlyImageSingleton {
45+
@Override
46+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
47+
public void log(CCharPointer bytes, UnsignedWord length) {
48+
if (!WindowsUtils.writeUninterruptibly(getStdErrHandle(), bytes, length)) {
49+
throw VMError.shouldNotReachHere("Writing to stderr failed.");
50+
}
51+
}
52+
53+
@Override
54+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
55+
public void flush() {
56+
/* Flush and ignore errors. */
57+
WindowsUtils.flushUninterruptibly(getStdErrHandle());
58+
}
59+
60+
@Override
61+
public EnumSet<LayeredImageSingletonBuilderFlags> getImageBuilderFlags() {
62+
return LayeredImageSingletonBuilderFlags.RUNTIME_ACCESS_ONLY;
63+
}
64+
65+
@Override
66+
public boolean accessibleInFutureLayers() {
67+
return true;
68+
}
69+
70+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
71+
private static HANDLE getStdErrHandle() {
72+
return FileAPI.NoTransition.GetStdHandle(FileAPI.STD_ERROR_HANDLE());
73+
}
74+
}

substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/WindowsUtils.java

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,12 @@
2424
*/
2525
package com.oracle.svm.core.windows;
2626

27+
import static com.oracle.svm.core.Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE;
2728
import static com.oracle.svm.core.annotate.RecomputeFieldValue.Kind.Custom;
29+
import static com.oracle.svm.core.windows.headers.WinBase.INVALID_HANDLE_VALUE;
2830

2931
import java.io.FileDescriptor;
3032

31-
import jdk.graal.compiler.word.Word;
3233
import org.graalvm.nativeimage.StackValue;
3334
import org.graalvm.nativeimage.c.function.CFunctionPointer;
3435
import org.graalvm.nativeimage.c.struct.CPointerTo;
@@ -50,8 +51,11 @@
5051
import com.oracle.svm.core.windows.headers.FileAPI;
5152
import com.oracle.svm.core.windows.headers.LibLoaderAPI;
5253
import com.oracle.svm.core.windows.headers.WinBase;
54+
import com.oracle.svm.core.windows.headers.WinBase.HANDLE;
5355
import com.oracle.svm.core.windows.headers.WinBase.HMODULE;
5456

57+
import jdk.graal.compiler.word.Word;
58+
5559
public class WindowsUtils {
5660

5761
@TargetClass(className = "java.lang.ProcessImpl")
@@ -78,8 +82,8 @@ public Object transform(Object receiver, Object originalValue) {
7882
long handle;
7983
}
8084

81-
static void setHandle(FileDescriptor descriptor, long handle) {
82-
SubstrateUtil.cast(descriptor, Target_java_io_FileDescriptor.class).handle = handle;
85+
static void setHandle(FileDescriptor descriptor, HANDLE handle) {
86+
SubstrateUtil.cast(descriptor, Target_java_io_FileDescriptor.class).handle = handle.rawValue();
8387
}
8488

8589
/** Return the error string for the last error, or a default message. */
@@ -92,18 +96,42 @@ public static String lastErrorString(String defaultMsg) {
9296
* Low-level output of bytes already in native memory. This method is allocation free, so that
9397
* it can be used, e.g., in low-level logging routines.
9498
*/
95-
public static boolean writeBytes(int handle, CCharPointer bytes, UnsignedWord length) {
99+
public static boolean write(HANDLE handle, CCharPointer bytes, UnsignedWord length) {
100+
if (handle == INVALID_HANDLE_VALUE()) {
101+
return false;
102+
}
103+
96104
CCharPointer curBuf = bytes;
97105
UnsignedWord curLen = length;
98106
while (curLen.notEqual(0)) {
99-
if (handle == -1) {
107+
CIntPointer bytesWritten = UnsafeStackValue.get(CIntPointer.class);
108+
int ret = FileAPI.WriteFile(handle, curBuf, curLen, bytesWritten, Word.nullPointer());
109+
if (ret == 0) {
100110
return false;
101111
}
102112

103-
CIntPointer bytesWritten = UnsafeStackValue.get(CIntPointer.class);
113+
int writtenCount = bytesWritten.read();
114+
if (curLen.notEqual(writtenCount)) {
115+
return false;
116+
}
104117

105-
int ret = FileAPI.WriteFile(handle, curBuf, curLen, bytesWritten, Word.nullPointer());
118+
curBuf = curBuf.addressOf(writtenCount);
119+
curLen = curLen.subtract(writtenCount);
120+
}
121+
return true;
122+
}
106123

124+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
125+
public static boolean writeUninterruptibly(HANDLE handle, CCharPointer bytes, UnsignedWord length) {
126+
if (handle == INVALID_HANDLE_VALUE()) {
127+
return false;
128+
}
129+
130+
CCharPointer curBuf = bytes;
131+
UnsignedWord curLen = length;
132+
while (curLen.notEqual(0)) {
133+
CIntPointer bytesWritten = UnsafeStackValue.get(CIntPointer.class);
134+
int ret = FileAPI.NoTransition.WriteFile(handle, curBuf, curLen, bytesWritten, Word.nullPointer());
107135
if (ret == 0) {
108136
return false;
109137
}
@@ -119,12 +147,19 @@ public static boolean writeBytes(int handle, CCharPointer bytes, UnsignedWord le
119147
return true;
120148
}
121149

122-
static boolean flush(int handle) {
123-
if (handle == -1) {
150+
static boolean flush(HANDLE handle) {
151+
if (handle == INVALID_HANDLE_VALUE()) {
152+
return false;
153+
}
154+
return FileAPI.FlushFileBuffers(handle) != 0;
155+
}
156+
157+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
158+
static boolean flushUninterruptibly(HANDLE handle) {
159+
if (handle == INVALID_HANDLE_VALUE()) {
124160
return false;
125161
}
126-
int result = FileAPI.FlushFileBuffers(handle);
127-
return (result != 0);
162+
return FileAPI.NoTransition.FlushFileBuffers(handle) != 0;
128163
}
129164

130165
private static long performanceFrequency = 0L;

substratevm/src/com.oracle.svm.core.windows/src/com/oracle/svm/core/windows/headers/FileAPI.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@
3434
import org.graalvm.word.PointerBase;
3535
import org.graalvm.word.UnsignedWord;
3636

37-
import com.oracle.svm.core.windows.headers.WindowsLibC.WCharPointer;
3837
import com.oracle.svm.core.windows.headers.WinBase.HANDLE;
38+
import com.oracle.svm.core.windows.headers.WindowsLibC.WCharPointer;
3939

4040
// Checkstyle: stop
4141

@@ -67,11 +67,11 @@ public static native HANDLE CreateFileW(WCharPointer lpFileName, int dwDesiredAc
6767
public static native int OPEN_EXISTING();
6868

6969
@CFunction
70-
public static native int WriteFile(int hFile, CCharPointer lpBuffer, UnsignedWord nNumberOfBytesToWrite,
70+
public static native int WriteFile(HANDLE hFile, CCharPointer lpBuffer, UnsignedWord nNumberOfBytesToWrite,
7171
CIntPointer lpNumberOfBytesWritten, PointerBase lpOverlapped);
7272

7373
@CFunction
74-
public static native int FlushFileBuffers(int hFile);
74+
public static native int FlushFileBuffers(HANDLE hFile);
7575

7676
@CConstant
7777
public static native int STD_INPUT_HANDLE();
@@ -83,8 +83,19 @@ public static native int WriteFile(int hFile, CCharPointer lpBuffer, UnsignedWor
8383
public static native int STD_ERROR_HANDLE();
8484

8585
@CFunction
86-
public static native int GetStdHandle(int stdHandle);
86+
public static native HANDLE GetStdHandle(int stdHandle);
8787

8888
@CFunction(transition = NO_TRANSITION)
8989
public static native int GetTempPathW(int nBufferLength, WCharPointer lpBuffer);
90+
91+
public static class NoTransition {
92+
@CFunction(transition = NO_TRANSITION)
93+
public static native int WriteFile(HANDLE hFile, CCharPointer lpBuffer, UnsignedWord nNumberOfBytesToWrite, CIntPointer lpNumberOfBytesWritten, PointerBase lpOverlapped);
94+
95+
@CFunction(transition = NO_TRANSITION)
96+
public static native int FlushFileBuffers(HANDLE hFile);
97+
98+
@CFunction(transition = NO_TRANSITION)
99+
public static native HANDLE GetStdHandle(int stdHandle);
100+
}
90101
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/InvalidMethodPointerHandler.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828

2929
import java.lang.reflect.Method;
3030

31-
import jdk.graal.compiler.word.Word;
3231
import org.graalvm.nativeimage.ImageSingletons;
3332
import org.graalvm.nativeimage.LogHandler;
3433
import org.graalvm.nativeimage.Platform;
@@ -44,6 +43,8 @@
4443
import com.oracle.svm.core.thread.VMThreads.SafepointBehavior;
4544
import com.oracle.svm.util.ReflectionUtil;
4645

46+
import jdk.graal.compiler.word.Word;
47+
4748
/**
4849
* Provides stub methods that can be used for uninitialized method pointers. Instead of a segfault,
4950
* the stubs provide full diagnostic output with a stack trace.

0 commit comments

Comments
 (0)