<!DOCTYPE html><html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<p>Hi David,<br>
it seems like you are hitting an issue with reachability. E.g.
when you do:</p>
<pre style="font-family:"JetBrains Mono",monospace;font-size:9.8pt"><font color="#000000"><span style="font-style:italic">int fd = openFile(path.getBytes(), 0, 0);</span></font></pre>
<p>The Linker should keep the array reachable _for the duration of
the call_. But if that doesn't happen, the GC will recycle the
memory for your buffer _while you are in the middle of the open
call_, which will then misbehave.</p>
<p>Can you try to tweak your program, so that the array is saved in
a local variable, and then use a try/finally with a reachability
fence? Something like this:<br>
</p>
<p>```<br>
byte[] buffer = path.getBytes();<br>
try {<br>
int fd = openFile(buffer, 0, 0);<br>
...<br>
closeFile(fd);<br>
} finally {<br>
Reference.reachabiltyFence(buffer);<br>
}<br>
```</p>
<p>This ensures that the array used from native code is kept
reachable. If this works reliably, there might be an issue with
critical downcalls and reachability.</p>
<p>Maurizio<br>
</p>
<div class="moz-cite-prefix">On 06/02/2025 12: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>
</body>
</html>