<!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>