<!DOCTYPE html><html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<p>You beat me to it :-) reproduced on my machine as well.</p>
<p>The C string to be passed to open needs to be written using
MemorySegment::setString (which will copy the string bytes and
append the required terminator at the end).<br>
</p>
<p>Maurizio<br>
</p>
<div class="moz-cite-prefix">On 06/02/2025 12:50, Jorn Vernee wrote:<br>
</div>
<blockquote type="cite" cite="mid:ed6ed14d-61d5-4a39-b005-0b5eefa69188@oracle.com">
<p>Hey David,</p>
<p>It looks like you're not passing a null-terminated string to <font face="monospace">open</font>. <font face="monospace">path.getBytes</font>
will not return a null-terminated string. It probably works when
using the <font color="#000000"><font face="monospace">stableBuffer</font>
because the paths you're using are shorter then the buffer,
and you fill the buffer with zeros every iteration. So, the
string in there will always be null-terminated.</font></p>
<p><font color="#000000">Jorn<br>
</font></p>
<div class="moz-cite-prefix">On 6-2-2025 13:17, David wrote:<br>
</div>
<blockquote type="cite" cite="mid:CAG-0zZf5yf_bedftPhtOxgt9wfAwqKV+opBBr2tjrBcMK4NC1g@mail.gmail.com">
<div dir="ltr">Hi,<br>
<br>
I have a question about the behavior of critical functions
inside a for-loop. I marked open() as critical (I know this is
not an empty function like the java docs tells me i should use
critical for, but I really wanted to try it). Wanting to see
if it speeds things up. What I didn't expect was that it
doesn't work well with variables created inside the loop
itself, or at least that seems to be the case. Open() fails
returning -1. To work around this issue I created a
"stableBuffer" just outside the loop, which makes the code
work all of the time.
<div><br>
</div>
<div>I just have two questions. Is this expected behavior for
critical functions? Why does the stable buffer approach work
consistently while using variables inside the loop fail
after a few iterations?
<div><br>
</div>
<div>The loop that causes issues:<br>
<div>
<div style="">
<pre style="font-family:"JetBrains Mono",monospace;font-size:9.8pt"><font color="#000000"> @Test
void test() {
var paths = <span style="font-style:italic">filesTooRead</span>;
byte[] stableBuffer = new byte[4096];
for (var path : paths) {
byte[] pathBytes = path.getBytes();
Arrays.<span style="font-style:italic">fill</span>(stableBuffer, (byte) 0);
System.<span style="font-style:italic">arraycopy</span>(pathBytes, 0, stableBuffer, 0, pathBytes.length);
<span style="font-style:italic">// works all the time
</span><span style="font-style:italic"> </span>int fd = openFile(stableBuffer, 0, 0);
<span style="font-style:italic">// works for a couple of </span></font>iterations<font color="#000000"><span style="font-style:italic">
</span><span style="font-style:italic">// int fd = openFile(path.getBytes(), 0, 0);
</span><span style="font-style:italic">// int fd = openFile("/media/david/Data2/text_files/file_2299.bin".getBytes(), 0, 0);
</span><span style="font-style:italic">
</span><span style="font-style:italic"> </span>MemorySegment buffer = Arena.<span style="font-style:italic">ofAuto</span>().allocate(4);
read(fd, buffer, 4);
buffer.set(ValueLayout.<span style="font-style:italic">JAVA_BYTE</span>, 3, (byte) 0);
<span style="font-style:italic">// System.out.println(path + "content " + buffer.getString(0));
</span><span style="font-style:italic">
</span><span style="font-style:italic"> </span>if (fd < 0) {
System.<span style="font-style:italic">err</span>.println("Failed to open file:");
}
<span style="font-style:italic">closeFile</span>(fd);
}
}</font></pre>
<pre style="font-family:"JetBrains Mono",monospace;font-size:9.8pt">OS: Pop!_OS 22.04 LTS
<span style="font-family:Arial,Helvetica,sans-serif;font-size:small;white-space:normal">Java version: JDK 24 EA Build 35 (2025/2/4)</span></pre>
<pre style="font-family:"JetBrains Mono",monospace;font-size:9.8pt"><span style="font-family:Arial,Helvetica,sans-serif;font-size:small;white-space:normal">
</span></pre>
Thank you for your time and feedback.<br>
<br>
Kind regards,<br>
David Vlijmincx<br>
<br>
The entire class:
<pre style="font-family:"JetBrains Mono",monospace;font-size:9.8pt"><div style=""><pre style="font-family:"JetBrains Mono",monospace;font-size:9.8pt"><font color="#000000">package bench;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.lang.foreign.*;
import java.lang.invoke.MethodHandle;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.stream.Stream;
import static java.lang.foreign.ValueLayout.*;
public class CriticalLoopTest {
public static final String <span style="font-style:italic">BENCHMARK_FILE_EXTENSION </span>= ".bin";
public static final Path <span style="font-style:italic">BASE_BENCHMARK_FILES_DIR </span>= Path.<span style="font-style:italic">of</span>("/media/david/Data2/text_files");
public static final String[] <span style="font-style:italic">filesTooRead</span>;
private static final MethodHandle <span style="font-style:italic">open</span>;
private static final MethodHandle <span style="font-style:italic">close</span>;
private static final MethodHandle <span style="font-style:italic">read</span>;
static {
Linker linker = Linker.<span style="font-style:italic">nativeLinker</span>();
<span style="font-style:italic">open </span>= linker.downcallHandle(
linker.defaultLookup().find("open").orElseThrow(),
FunctionDescriptor.<span style="font-style:italic">of</span>(<span style="font-style:italic">JAVA_INT</span>, <span style="font-style:italic">ADDRESS</span>, <span style="font-style:italic">JAVA_INT</span>, <span style="font-style:italic">JAVA_INT</span>),
Linker.Option.<span style="font-style:italic">critical</span>(true)
);
<span style="font-style:italic">read </span>= linker.downcallHandle(
linker.defaultLookup().find("read").orElseThrow(),
FunctionDescriptor.<span style="font-style:italic">of</span>(<span style="font-style:italic">JAVA_INT</span>, <span style="font-style:italic">JAVA_INT</span>, <span style="font-style:italic">ADDRESS</span>, <span style="font-style:italic">JAVA_INT</span>)
);
<span style="font-style:italic">close </span>= linker.downcallHandle(
linker.defaultLookup().find("close").orElseThrow(),
FunctionDescriptor.<span style="font-style:italic">ofVoid</span>(<span style="font-style:italic">JAVA_INT</span>)
);
try (Stream<Path> files = Files.<span style="font-style:italic">walk</span>(<span style="font-style:italic">BASE_BENCHMARK_FILES_DIR</span>)){
<span style="font-style:italic">filesTooRead </span>= files
.filter(p -> p.getFileName().toString().endsWith(<span style="font-style:italic">BENCHMARK_FILE_EXTENSION</span>))
.map(Path::toString)
.toArray(String[]::new);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Test
void test() {
var paths = <span style="font-style:italic">filesTooRead</span>;
byte[] stableBuffer = new byte[4096];
for (var path : paths) {
byte[] pathBytes = path.getBytes();
Arrays.<span style="font-style:italic">fill</span>(stableBuffer, (byte) 0);
System.<span style="font-style:italic">arraycopy</span>(pathBytes, 0, stableBuffer, 0, pathBytes.length);
<span style="font-style:italic">// works all the time
</span><span style="font-style:italic"> </span>int fd = openFile(stableBuffer, 0, 0);
<span style="font-style:italic">// works sometimes
</span><span style="font-style:italic">// int fd = openFile(path.getBytes(), 0, 0);
</span><span style="font-style:italic">// int fd = openFile("/media/david/Data2/text_files/file_2299.bin".getBytes(), 0, 0);
</span><span style="font-style:italic">
</span><span style="font-style:italic"> </span>MemorySegment buffer = Arena.<span style="font-style:italic">ofAuto</span>().allocate(4);
read(fd, buffer, 4);
buffer.set(ValueLayout.<span style="font-style:italic">JAVA_BYTE</span>, 3, (byte) 0);
<span style="font-style:italic">// System.out.println(path + "content " + buffer.getString(0));
</span><span style="font-style:italic">
</span><span style="font-style:italic"> </span>if (fd < 0) {
System.<span style="font-style:italic">err</span>.println("Failed to open file:");
}
<span style="font-style:italic">closeFile</span>(fd);
}
}
public int read(int fd, MemorySegment mem, int len) {
try {
return (int) <span style="font-style:italic">read</span>.invokeExact(fd, mem, len);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
public int openFile(byte[] filePath, int flags, int mode) {
try {
int fd = (int) <span style="font-style:italic">open</span>.invokeExact(MemorySegment.<span style="font-style:italic">ofArray</span>(filePath), flags, mode);
if (fd < 0) {
throw new RuntimeException("Failed to open file fd=" + fd);
}
return fd;
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
public static void closeFile(int fd) {
try {
<span style="font-style:italic">close</span>.invokeExact(fd);
} catch (Throwable e) {
throw new RuntimeException("Could not close file with FD:" + fd, e);
}
}
}</font><font color="#080808">
</font></pre></div></pre>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</blockquote>
</body>
</html>