import java.io.*;
import java.nio.channels.*;
import java.nio.file.*;
import java.lang.foreign.*;
import java.lang.invoke.*;
import java.util.concurrent.CountDownLatch;

public class Main {

    static final Linker LINKER = Linker.nativeLinker();
    static final ValueLayout.OfInt C_INT = (ValueLayout.OfInt) LINKER.canonicalLayouts().get("int");

    static final int PAGE_SIZE = pageSize();

    static volatile boolean stop = false;

    public static void main(String[] args) throws Throwable {
        CountDownLatch latch = new CountDownLatch(1);
        Thread.ofPlatform().start(() -> {
            latch.countDown();
            while (!stop) {
                Arena.ofShared().close(); // hammer
            }
        });

        latch.await();

        String fileName = "tmp.txt";
        Path path = Path.of(fileName);

        StringBuilder s = new StringBuilder();
        for (int i = 1; i < PAGE_SIZE + 1000; i++) {
            s.append("1");
        }
        Files.write(path, s.toString().getBytes());
        FileChannel fileChannel = new RandomAccessFile(fileName, "rw").getChannel();
        MemorySegment segment =
            fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, fileChannel.size(), Arena.ofAuto());

        // truncate
        Files.write(path, "2".getBytes());

        for (int i = 0; i < 50_000; i++) {
            try {
                segment.get(ValueLayout.JAVA_INT, PAGE_SIZE);
            } catch (InternalError e) {
                //System.out.println("Fault occurred");
            }
        }
        stop = true;
    }

    private static int pageSize() {
        class Holder {
            static final MethodHandle MH_getpagesize = LINKER.downcallHandle(
                LINKER.defaultLookup().findOrThrow("getpagesize"),
                FunctionDescriptor.of(C_INT));
        }
        try {
            return (int) Holder.MH_getpagesize.invokeExact();
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
    }
}