Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,65 +20,82 @@ public class MemFDUnixWriterFFM extends MemFDUnixWriter {
private static final long ERRNO_OFFSET =
CAPTURE_STATE_LAYOUT.byteOffset(MemoryLayout.PathElement.groupElement("errno"));

// Function handles - initialized once
private final MethodHandle syscallMH;
private final MethodHandle writeMH;
private final MethodHandle fcntlMH;
private static class Lazy {
// Function handles - initialized once
static final MethodHandle syscallMH;
static final MethodHandle writeMH;
static final MethodHandle fcntlMH;

static {
MethodHandle syscall = null;
MethodHandle write = null;
MethodHandle fcntl = null;
try {
final Linker linker = Linker.nativeLinker();
final SymbolLookup LIBC = linker.defaultLookup();
// long syscall(long number, ...)
// Note: variadic functions require special handling, we'll use a fixed signature
syscall =
linker.downcallHandle(
LIBC.find("syscall").orElseThrow(),
FunctionDescriptor.of(
ValueLayout.JAVA_LONG, // return type: long
ValueLayout.JAVA_LONG, // syscall number
ValueLayout.ADDRESS, // const char* name
ValueLayout.JAVA_INT // int flags
),
Linker.Option.captureCallState("errno"));

// ssize_t write(int fd, const void *buf, size_t count)
write =
linker.downcallHandle(
LIBC.find("write").orElseThrow(),
FunctionDescriptor.of(
ValueLayout.JAVA_LONG, // return type: ssize_t
ValueLayout.JAVA_INT, // int fd
ValueLayout.ADDRESS, // const void* buf
ValueLayout.JAVA_LONG // size_t count
),
Linker.Option.captureCallState("errno"));

// int fcntl(int fd, int cmd, ... /* arg */)
fcntl =
linker.downcallHandle(
LIBC.find("fcntl").orElseThrow(),
FunctionDescriptor.of(
ValueLayout.JAVA_INT, // return type: int
ValueLayout.JAVA_INT, // int fd
ValueLayout.JAVA_INT, // int cmd
ValueLayout.JAVA_INT // int arg
),
Linker.Option.captureCallState("errno"));
} catch (final Throwable ex) {
log.error("Failed to initialize MemFDUnixWriterFFM", ex);
} finally {
syscallMH = syscall;
writeMH = write;
fcntlMH = fcntl;
}
}
}

private final MemorySegment captureState;

public MemFDUnixWriterFFM() {
final Linker linker = Linker.nativeLinker();
final SymbolLookup LIBC = linker.defaultLookup();

// Allocate memory for capturing errno (need to be alive until the class instance is collected)
this.captureState = Arena.ofAuto().allocate(CAPTURE_STATE_LAYOUT);

// long syscall(long number, ...)
// Note: variadic functions require special handling, we'll use a fixed signature
syscallMH =
linker.downcallHandle(
LIBC.find("syscall").orElseThrow(),
FunctionDescriptor.of(
ValueLayout.JAVA_LONG, // return type: long
ValueLayout.JAVA_LONG, // syscall number
ValueLayout.ADDRESS, // const char* name
ValueLayout.JAVA_INT // int flags
),
Linker.Option.captureCallState("errno"));

// ssize_t write(int fd, const void *buf, size_t count)
writeMH =
linker.downcallHandle(
LIBC.find("write").orElseThrow(),
FunctionDescriptor.of(
ValueLayout.JAVA_LONG, // return type: ssize_t
ValueLayout.JAVA_INT, // int fd
ValueLayout.ADDRESS, // const void* buf
ValueLayout.JAVA_LONG // size_t count
),
Linker.Option.captureCallState("errno"));

// int fcntl(int fd, int cmd, ... /* arg */)
fcntlMH =
linker.downcallHandle(
LIBC.find("fcntl").orElseThrow(),
FunctionDescriptor.of(
ValueLayout.JAVA_INT, // return type: int
ValueLayout.JAVA_INT, // int fd
ValueLayout.JAVA_INT, // int cmd
ValueLayout.JAVA_INT // int arg
),
Linker.Option.captureCallState("errno"));
}

@Override
protected long syscall(long number, String name, int flags) {
if (Lazy.syscallMH == null) {
return -1;
}
try (Arena arena = Arena.ofConfined()) {
// Allocate native string for file name
MemorySegment fileNameSegment = arena.allocateFrom(name);
// Call memfd_create via syscall, passing captureState as first arg
return (long) syscallMH.invoke(captureState, (long) number, fileNameSegment, flags);
return (long) Lazy.syscallMH.invoke(captureState, (long) number, fileNameSegment, flags);
} catch (Throwable t) {
log.error("Unable to make a syscall through FFM", t);
return -1;
Expand All @@ -87,13 +104,16 @@ protected long syscall(long number, String name, int flags) {

@Override
protected long write(int fd, byte[] payload) {
if (Lazy.writeMH == null) {
return -1;
}
try (Arena arena = Arena.ofConfined()) {
// Allocate native memory for payload
MemorySegment buffer = arena.allocate(payload.length);
MemorySegment.copy(payload, 0, buffer, ValueLayout.JAVA_BYTE, 0, payload.length);

// Write payload to memfd, passing captureState as first arg
return (long) writeMH.invoke(captureState, fd, buffer, (long) payload.length);
return (long) Lazy.writeMH.invoke(captureState, fd, buffer, (long) payload.length);
} catch (Throwable t) {
log.error("Unable to make a write call through FFM", t);
return -1;
Expand All @@ -102,8 +122,11 @@ protected long write(int fd, byte[] payload) {

@Override
protected int fcntl(int fd, int cmd, int arg) {
if (Lazy.fcntlMH == null) {
return -1;
}
try {
return (int) fcntlMH.invoke(captureState, fd, cmd, arg);
return (int) Lazy.fcntlMH.invoke(captureState, fd, cmd, arg);
} catch (Throwable t) {
log.error("Unable to make a fcntl call through FFM", t);
return -1;
Expand Down
Loading