diff --git a/java-does-usb/jextract/linux/epoll.h b/java-does-usb/jextract/linux/epoll.h new file mode 100644 index 0000000..c7c68b4 --- /dev/null +++ b/java-does-usb/jextract/linux/epoll.h @@ -0,0 +1,3 @@ +typedef unsigned int uint32_t; +typedef unsigned long int uint64_t; +#include diff --git a/java-does-usb/jextract/linux/gen_linux.sh b/java-does-usb/jextract/linux/gen_linux.sh index 31b8654..429ccc2 100755 --- a/java-does-usb/jextract/linux/gen_linux.sh +++ b/java-does-usb/jextract/linux/gen_linux.sh @@ -10,6 +10,8 @@ $JEXTRACT --source --output ../../src/main/java \ --include-constant EAGAIN \ --include-constant EINVAL \ --include-constant ENODEV \ + --include-constant EINTR \ + --include-constant ENOENT \ /usr/include/errno.h # string.h @@ -45,16 +47,6 @@ $JEXTRACT --source --output ../../src/main/java \ --include-struct usbdevfs_urb \ --include-struct usbdevfs_disconnect_claim \ --include-struct usbdevfs_ioctl \ - --include-constant USBDEVFS_CONTROL \ - --include-constant USBDEVFS_BULK \ - --include-constant USBDEVFS_CLAIMINTERFACE \ - --include-constant USBDEVFS_RELEASEINTERFACE \ - --include-constant USBDEVFS_SETINTERFACE \ - --include-constant USBDEVFS_CLEAR_HALT \ - --include-constant USBDEVFS_SUBMITURB \ - --include-constant USBDEVFS_DISCARDURB \ - --include-constant USBDEVFS_REAPURB \ - --include-constant USBDEVFS_DISCONNECT_CLAIM \ --include-constant USBDEVFS_URB_TYPE_INTERRUPT \ --include-constant USBDEVFS_URB_TYPE_CONTROL \ --include-constant USBDEVFS_URB_TYPE_BULK \ @@ -89,14 +81,14 @@ $JEXTRACT --source --output ../../src/main/java \ --include-function udev_monitor_get_fd \ /usr/include/libudev.h -# poll.h +# epoll.h $JEXTRACT --source --output ../../src/main/java \ - --header-class-name poll \ - --target-package net.codecrete.usb.linux.gen.poll \ - --include-function poll \ - --include-struct pollfd \ - --include-constant POLLIN \ - --include-constant POLLOUT \ - --include-constant POLLERR \ - /usr/include/poll.h + --header-class-name epoll \ + --target-package net.codecrete.usb.linux.gen.epoll \ + --include-struct epoll_event \ + --include-constant EPOLL_CTL_ADD \ + --include-constant EPOLL_CTL_DEL \ + --include-constant EPOLLIN \ + --include-constant EPOLLOUT \ + epoll.h diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java new file mode 100644 index 0000000..8376467 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/EPoll.java @@ -0,0 +1,98 @@ +// +// Java Does USB +// Copyright (c) 2022 Manuel Bleichenbacher +// Licensed under MIT License +// https://opensource.org/licenses/MIT +// + +package net.codecrete.usb.linux; + +import net.codecrete.usb.linux.gen.epoll.epoll_event; +import net.codecrete.usb.linux.gen.errno.errno; + +import java.lang.foreign.*; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.ADDRESS; +import static java.lang.foreign.ValueLayout.JAVA_INT; +import static net.codecrete.usb.linux.Linux.allocateErrorState; +import static net.codecrete.usb.linux.LinuxUsbException.throwLastError; +import static net.codecrete.usb.linux.gen.epoll.epoll.*; + +@SuppressWarnings({"OptionalGetWithoutIsPresent", "SameParameterValue", "java:S100"}) +public class EPoll { + private EPoll() {} + + private static final Linker linker = Linker.nativeLinker(); + + private static final FunctionDescriptor epoll_create$FUNC = FunctionDescriptor.of(JAVA_INT, JAVA_INT); + private static final MethodHandle epoll_create$MH = linker.downcallHandle(linker.defaultLookup().find( + "epoll_create").get(), epoll_create$FUNC, Linux.ERRNO_STATE); + + private static final FunctionDescriptor epoll_ctl$FUNC = FunctionDescriptor.of(JAVA_INT, JAVA_INT, JAVA_INT, JAVA_INT, ADDRESS); + private static final MethodHandle epoll_ctl$MH = linker.downcallHandle(linker.defaultLookup().find( + "epoll_ctl").get(), epoll_ctl$FUNC, Linux.ERRNO_STATE); + + private static final FunctionDescriptor epoll_wait$FUNC = FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS, JAVA_INT, JAVA_INT); + private static final MethodHandle epoll_wait$MH = linker.downcallHandle(linker.defaultLookup().find( + "epoll_wait").get(), epoll_wait$FUNC, Linux.ERRNO_STATE); + + private static final VarHandle epoll_event_data_fd$VH = epoll_event.$LAYOUT().varHandle( + MemoryLayout.PathElement.groupElement("data"), + MemoryLayout.PathElement.groupElement("fd") + ); + + static int epoll_create(int size, MemorySegment errno) { + try { + return (int) epoll_create$MH.invokeExact(errno, size); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + private static int epoll_ctl(int epfd, int op, int fd, MemorySegment event, MemorySegment errno) { + try { + return (int) epoll_ctl$MH.invokeExact(errno, epfd, op, fd, event); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static int epoll_wait(int epfd, MemorySegment events, int maxevent, int timeout, MemorySegment errno) { + try { + return (int) epoll_wait$MH.invokeExact(errno, epfd, events, maxevent, timeout); + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + + static void addFileDescriptor(int epfd, int op, int fd) { + try (var arena = Arena.ofConfined()) { + var errorState = allocateErrorState(arena); + + var event = arena.allocate(epoll_event.$LAYOUT()); + epoll_event.events$set(event, op); + epoll_event_data_fd$VH.set(event, fd); + var ret = epoll_ctl(epfd, EPOLL_CTL_ADD(), fd, event, errorState); + if (ret < 0) + throwLastError(errorState, "internal error (epoll_ctl_add)"); + } + } + + static void removeFileDescriptor(int epfd, int fd) { + try (var arena = Arena.ofConfined()) { + var errorState = allocateErrorState(arena); + + var event = arena.allocate(epoll_event.$LAYOUT()); + epoll_event.events$set(event, 0); + epoll_event_data_fd$VH.set(event, fd); + var ret = epoll_ctl(epfd, EPOLL_CTL_DEL(), fd, event, errorState); + if (ret < 0) { + var err = Linux.getErrno(errorState); + if (err != errno.ENOENT()) + throwLastError(errorState, "internal error (epoll_ctl_del)"); + } + } + } +} diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java index 88b6d36..bfdc938 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/IO.java @@ -27,15 +27,6 @@ private IO() { private static final FunctionDescriptor open$FUNC = FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_INT); private static final MethodHandle open$MH = linker.downcallHandle(linker.defaultLookup().find("open").get(), open$FUNC, Linux.ERRNO_STATE); - private static final FunctionDescriptor eventfd$FUNC = FunctionDescriptor.of(JAVA_INT, JAVA_INT, JAVA_INT); - private static final MethodHandle eventfd$MH = linker.downcallHandle(linker.defaultLookup().find("eventfd").get() - , eventfd$FUNC, Linux.ERRNO_STATE); - private static final FunctionDescriptor eventfd_read$FUNC = FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS); - private static final MethodHandle eventfd_read$MH = linker.downcallHandle(linker.defaultLookup().find( - "eventfd_read").get(), eventfd_read$FUNC, Linux.ERRNO_STATE); - private static final FunctionDescriptor eventfd_write$FUNC = FunctionDescriptor.of(JAVA_INT, JAVA_INT, JAVA_LONG); - private static final MethodHandle eventfd_write$MH = linker.downcallHandle(linker.defaultLookup().find( - "eventfd_write").get(), eventfd_write$FUNC, Linux.ERRNO_STATE); static int ioctl(int fd, long request, MemorySegment segment, MemorySegment errno) { try { @@ -52,29 +43,4 @@ static int open(MemorySegment file, int oflag, MemorySegment errno) { throw new AssertionError(ex); } } - - static int eventfd(int count, int flags, MemorySegment errno) { - try { - return (int) eventfd$MH.invokeExact(errno, count, flags); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static int eventfd_read(int fd, MemorySegment value, MemorySegment errno) { - try { - return (int) eventfd_read$MH.invokeExact(errno, fd, value); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - - static int eventfd_write(int fd, long value, MemorySegment errno) { - try { - return (int) eventfd_write$MH.invokeExact(errno, fd, value); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - } - } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java index 524fe81..fb515ee 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxAsyncTask.java @@ -8,25 +8,29 @@ package net.codecrete.usb.linux; import net.codecrete.usb.UsbTransferType; +import net.codecrete.usb.linux.gen.epoll.epoll_event; import net.codecrete.usb.linux.gen.errno.errno; -import net.codecrete.usb.linux.gen.poll.poll; -import net.codecrete.usb.linux.gen.poll.pollfd; import net.codecrete.usb.linux.gen.usbdevice_fs.usbdevfs_urb; import java.lang.foreign.Arena; +import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; +import java.lang.invoke.VarHandle; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import static java.lang.foreign.ValueLayout.ADDRESS; -import static java.lang.foreign.ValueLayout.JAVA_LONG; +import static java.lang.foreign.ValueLayout.*; import static net.codecrete.usb.common.ForeignMemory.dereference; +import static net.codecrete.usb.linux.EPoll.epoll_create; +import static net.codecrete.usb.linux.EPoll.epoll_wait; import static net.codecrete.usb.linux.Linux.allocateErrorState; import static net.codecrete.usb.linux.LinuxUsbException.throwException; import static net.codecrete.usb.linux.LinuxUsbException.throwLastError; import static net.codecrete.usb.linux.UsbDevFS.*; +import static net.codecrete.usb.linux.gen.epoll.epoll.*; +import static net.codecrete.usb.linux.gen.errno.errno.EINTR; import static net.codecrete.usb.linux.gen.usbdevice_fs.usbdevice_fs.*; /** @@ -51,15 +55,20 @@ class LinuxAsyncTask { */ static final LinuxAsyncTask INSTANCE = new LinuxAsyncTask(); + private static final int NUM_EVENTS = 5; + + private static final VarHandle epoll_event_data_fd$VH = epoll_event.$LAYOUT().varHandle( + MemoryLayout.PathElement.groupElement("data"), + MemoryLayout.PathElement.groupElement("fd") + ); + private final Arena urbArena = Arena.ofAuto(); /// available URBs private final List availableURBs = new ArrayList<>(); /// map of URB addresses to transfer (for outstanding transfers) private final Map transfersByURB = new LinkedHashMap<>(); - /// array of file descriptors using asynchronous completion - private int[] asyncFds; - /// file descriptor to notify async IO background thread about an update - private int asyncIOWakeUpEventFd; + /// file descriptor of epoll + private int epollFd = -1; /** * Background task for handling asynchronous IO completions. @@ -67,85 +76,33 @@ class LinuxAsyncTask { * It polls on all registered file descriptors. If a file descriptor is * ready, the URB is "reaped". *

- *

- * Using an additional {@code eventfd} file descriptor, this background task - * can be woken up to refresh the list of polled file descriptors. - *

*/ @SuppressWarnings({"java:S2189", "java:S135", "java:S3776"}) private void asyncCompletionTask() { try (var arena = Arena.ofConfined()) { var errorState = allocateErrorState(arena); - var pollfdArray = pollfd.allocateArray(100, arena); var urbPointerHolder = arena.allocate(ADDRESS); - var eventfdValueHolder = arena.allocate(JAVA_LONG); + var events = arena.allocateArray(epoll_event.$LAYOUT(), NUM_EVENTS); while (true) { - // get current file descriptor array - int[] fds; - synchronized (this) { - fds = asyncFds; + var res = epoll_wait(epollFd, events, NUM_EVENTS, -1, errorState); + if (res < 0) { + var err = Linux.getErrno(errorState); + if (err == EINTR()) + continue; + throwException(err, "internal error (epoll_wait)"); } - // poll for event - fillPollfdArray(pollfdArray, fds); - var n = fds.length; - var res = poll.poll(pollfdArray, n + 1L, -1); - if (res < 0) - throwException("internal error (poll)"); - - // acquire lock - synchronized (this) { - - // check for wakeup event - if ((pollfd.revents$get(pollfdArray, n) & poll.POLLIN()) != 0) { - // wakeup to refresh list of file descriptors - res = IO.eventfd_read(asyncIOWakeUpEventFd, eventfdValueHolder, errorState); - if (res < 0) - throwLastError(errorState, "internal error (eventfd_read)"); - continue; - } - - // check for USB device events - for (var i = 0; i < n + 1; i++) { - var revent = pollfd.revents$get(pollfdArray, i); - if (revent == 0) - continue; - - if ((revent & poll.POLLERR()) != 0) { - // most likely the device has been disconnected, - // remove from polled FD list to prevent further problems - var fd = pollfd.fd$get(pollfdArray, i); - removeFdFromAsyncIOCompletion(fd); - continue; - } - - // reap URB - var fd = pollfd.fd$get(pollfdArray, i); - reapURBs(fd, urbPointerHolder, errorState); - } + for (int i = 0; i < res; i++) { + var fd = (int) epoll_event_data_fd$VH.get(events.asSlice(epoll_event.sizeof() * i, epoll_event.sizeof())); + reapURBs(fd, urbPointerHolder, errorState); } } } } - void fillPollfdArray(MemorySegment asyncPolls, int[] fds) { - // device file descriptors - var n = fds.length; - for (var i = 0; i < n; i++) { - pollfd.fd$set(asyncPolls, i, fds[i]); - pollfd.events$set(asyncPolls, i, (short) poll.POLLOUT()); - pollfd.revents$set(asyncPolls, i, (short) 0); - } - - // entry n is the wake-up event file descriptor - pollfd.fd$set(asyncPolls, n, asyncIOWakeUpEventFd); - pollfd.events$set(asyncPolls, n, (short) poll.POLLIN()); - pollfd.revents$set(asyncPolls, n, (short) 0); - } - /** * Reap all pending URBs and handle the completed transfers. * @@ -160,8 +117,11 @@ private void reapURBs(int fd, MemorySegment urbPointerHolder, MemorySegment erro var err = Linux.getErrno(errorState); if (err == errno.EAGAIN()) return; // no more pending URBs - if (err == errno.ENODEV()) - return; // ignore, device might have been closed + if (err == errno.ENODEV()) { + // device might have been unplugged + removeFdFromAsyncIOCompletion(fd); + return; + } throwException(err, "internal error (reap URB)"); } @@ -172,38 +132,17 @@ private void reapURBs(int fd, MemorySegment urbPointerHolder, MemorySegment erro } } - /** - * Notifies background process about changed FD list - */ - private void notifyAsyncIOTask() { - // start background process if needed - if (asyncIOWakeUpEventFd == 0) { - startAsyncIOTask(); - return; - } - - try (var arena = Arena.ofConfined()) { - var errorState = allocateErrorState(arena); - if (IO.eventfd_write(asyncIOWakeUpEventFd, 1, errorState) < 0) - throwLastError(errorState, "internal error (eventfd_write)"); - } - } - /** * Register a device for asynchronous IO completion handling * * @param device USB device */ synchronized void addForAsyncIOCompletion(LinuxUsbDevice device) { - var n = asyncFds != null ? asyncFds.length : 0; - var fds = new int[n + 1]; - if (n > 0) - System.arraycopy(asyncFds, 0, fds, 0, n); - fds[n] = device.fileDescriptor(); - - // activate new array - asyncFds = fds; - notifyAsyncIOTask(); + // start background process if needed + if (epollFd < 0) + startAsyncIOTask(); + + EPoll.addFileDescriptor(epollFd, EPOLLOUT(), device.fileDescriptor()); } /** @@ -212,29 +151,11 @@ synchronized void addForAsyncIOCompletion(LinuxUsbDevice device) { * @param device USB device */ synchronized void removeFromAsyncIOCompletion(LinuxUsbDevice device) { - removeFdFromAsyncIOCompletion(device.fileDescriptor()); - notifyAsyncIOTask(); + EPoll.removeFileDescriptor(epollFd, device.fileDescriptor()); } private synchronized void removeFdFromAsyncIOCompletion(int fd) { - // copy file descriptor (except the device's) into new array - var n = asyncFds.length; - if (n == 0) - return; - - var fds = new int[n - 1]; - var tgt = 0; - for (var asyncFd : asyncFds) { - if (asyncFd != fd) { - if (tgt == n) - return; - fds[tgt] = asyncFd; - tgt += 1; - } - } - - // make new array to active one - asyncFds = fds; + EPoll.removeFileDescriptor(epollFd, fd); } synchronized void submitTransfer(LinuxUsbDevice device, int endpointAddress, UsbTransferType transferType, LinuxTransfer transfer) { @@ -319,11 +240,9 @@ synchronized void abortTransfers(LinuxUsbDevice device, byte endpointAddress) { private void startAsyncIOTask() { try (var arena = Arena.ofConfined()) { var errorState = allocateErrorState(arena); - asyncIOWakeUpEventFd = IO.eventfd(0, 0, errorState); - if (asyncIOWakeUpEventFd == -1) { - asyncIOWakeUpEventFd = 0; - throwLastError(errorState, "internal error (eventfd)"); - } + epollFd = epoll_create(NUM_EVENTS, errorState); + if (epollFd < 0) + throwLastError(errorState, "internal error (epoll_create)"); } // start background thread for handling IO completion diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDeviceRegistry.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDeviceRegistry.java index 01051c9..48480ce 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDeviceRegistry.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUsbDeviceRegistry.java @@ -10,8 +10,7 @@ import net.codecrete.usb.UsbDevice; import net.codecrete.usb.common.ScopeCleanup; import net.codecrete.usb.common.UsbDeviceRegistry; -import net.codecrete.usb.linux.gen.poll.poll; -import net.codecrete.usb.linux.gen.poll.pollfd; +import net.codecrete.usb.linux.gen.epoll.epoll_event; import net.codecrete.usb.linux.gen.udev.udev; import java.lang.foreign.Arena; @@ -20,7 +19,12 @@ import java.util.List; import static java.lang.System.Logger.Level.INFO; +import static net.codecrete.usb.linux.EPoll.epoll_create; +import static net.codecrete.usb.linux.EPoll.epoll_wait; +import static net.codecrete.usb.linux.Linux.allocateErrorState; import static net.codecrete.usb.linux.LinuxUsbException.throwException; +import static net.codecrete.usb.linux.LinuxUsbException.throwLastError; +import static net.codecrete.usb.linux.gen.epoll.epoll.*; /** * Linux implementation of USB device registry. @@ -90,28 +94,40 @@ protected void monitorDevices() { return; } - // monitor device changes - //noinspection InfiniteLoopStatement - while (true) { - try (var arena = Arena.ofConfined(); var cleanup = new ScopeCleanup()) { + try (var arena = Arena.ofConfined()) { + // create epoll + var errorState = allocateErrorState(arena); + var epfd = epoll_create(1, errorState); + if (epfd < 0) + throwLastError(errorState, "internal error (epoll_create)"); + EPoll.addFileDescriptor(epfd, EPOLLIN(), fd); - // wait for next change - waitForFileDescriptor(fd, arena); + // allocate event (as output for epoll_wait) + var event = arena.allocate(epoll_event.$LAYOUT()); - // retrieve change - var udevDevice = udev.udev_monitor_receive_device(monitor); - if (udevDevice == null) - continue; // shouldn't happen + // monitor device changes + //noinspection InfiniteLoopStatement + while (true) { + try (var cleanup = new ScopeCleanup()) { + + // wait for next change + epoll_wait(epfd, event, 1, -1, errorState); + + // retrieve change + var udevDevice = udev.udev_monitor_receive_device(monitor); + if (udevDevice == null) + continue; // shouldn't happen - cleanup.add(() -> udev.udev_device_unref(udevDevice)); + cleanup.add(() -> udev.udev_device_unref(udevDevice)); - // get details - var action = getDeviceAction(udevDevice); + // get details + var action = getDeviceAction(udevDevice); - if ("add".equals(action)) { - onDeviceConnected(udevDevice); - } else if ("remove".equals(action)) { - onDeviceDisconnected(udevDevice); + if ("add".equals(action)) { + onDeviceConnected(udevDevice); + } else if ("remove".equals(action)) { + onDeviceDisconnected(udevDevice); + } } } } @@ -243,20 +259,4 @@ private static String getDeviceName(MemorySegment udevDevice) { private static String getDeviceAction(MemorySegment udevDevice) { return udev.udev_device_get_action(udevDevice).getUtf8String(0); } - - /** - * Waits until the specified file descriptor becomes ready for reading. - * - * @param fd the file descriptor - * @param arena an arena for allocating memory - */ - private static void waitForFileDescriptor(int fd, Arena arena) { - var fds = pollfd.allocate(arena); - pollfd.fd$set(fds, fd); - pollfd.events$set(fds, (short) poll.POLLIN()); - int res = poll.poll(fds, 1, -1); - if (res < 0) - throwException("internal error (poll)"); - } - } diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/RuntimeHelper.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/RuntimeHelper.java similarity index 99% rename from java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/RuntimeHelper.java rename to java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/RuntimeHelper.java index 5fdcd81..6259819 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/RuntimeHelper.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/RuntimeHelper.java @@ -1,4 +1,4 @@ -package net.codecrete.usb.linux.gen.poll; +package net.codecrete.usb.linux.gen.epoll; // Generated by jextract import java.lang.foreign.*; diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/constants$0.java new file mode 100644 index 0000000..f5fe605 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/constants$0.java @@ -0,0 +1,27 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.epoll; + +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.StructLayout; +import java.lang.invoke.VarHandle; + +import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.JAVA_LONG; +final class constants$0 { + + // Suppresses default constructor, ensuring non-instantiability. + private constants$0() {} + static final StructLayout const$0 = MemoryLayout.structLayout( + JAVA_INT.withByteAlignment(1).withName("events"), + MemoryLayout.unionLayout( + RuntimeHelper.POINTER.withByteAlignment(1).withName("ptr"), + JAVA_INT.withByteAlignment(1).withName("fd"), + JAVA_INT.withByteAlignment(1).withName("u32"), + JAVA_LONG.withByteAlignment(1).withName("u64") + ).withName("data") + ).withName("epoll_event"); + static final VarHandle const$1 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("events")); +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll.java new file mode 100644 index 0000000..a208a74 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll.java @@ -0,0 +1,52 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.epoll; + +import java.lang.foreign.AddressLayout; + +import static java.lang.foreign.ValueLayout.*; +public class epoll { + + public static final OfByte C_CHAR = JAVA_BYTE; + public static final OfShort C_SHORT = JAVA_SHORT; + public static final OfInt C_INT = JAVA_INT; + public static final OfLong C_LONG = JAVA_LONG; + public static final OfLong C_LONG_LONG = JAVA_LONG; + public static final OfFloat C_FLOAT = JAVA_FLOAT; + public static final OfDouble C_DOUBLE = JAVA_DOUBLE; + public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; + /** + * {@snippet : + * #define EPOLL_CTL_ADD 1 + * } + */ + public static int EPOLL_CTL_ADD() { + return (int)1L; + } + /** + * {@snippet : + * #define EPOLL_CTL_DEL 2 + * } + */ + public static int EPOLL_CTL_DEL() { + return (int)2L; + } + /** + * {@snippet : + * enum EPOLL_EVENTS.EPOLLIN = 1; + * } + */ + public static int EPOLLIN() { + return (int)1L; + } + /** + * {@snippet : + * enum EPOLL_EVENTS.EPOLLOUT = 4; + * } + */ + public static int EPOLLOUT() { + return (int)4L; + } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_event.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_event.java new file mode 100644 index 0000000..e59d353 --- /dev/null +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/epoll/epoll_event.java @@ -0,0 +1,61 @@ +// Generated by jextract + +package net.codecrete.usb.linux.gen.epoll; + +import java.lang.foreign.Arena; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; +import java.lang.invoke.VarHandle; +/** + * {@snippet : + * struct epoll_event { + * uint32_t events; + * epoll_data_t data; + * }; + * } + */ +public class epoll_event { + + public static MemoryLayout $LAYOUT() { + return constants$0.const$0; + } + public static VarHandle events$VH() { + return constants$0.const$1; + } + /** + * Getter for field: + * {@snippet : + * uint32_t events; + * } + */ + public static int events$get(MemorySegment seg) { + return (int)constants$0.const$1.get(seg); + } + /** + * Setter for field: + * {@snippet : + * uint32_t events; + * } + */ + public static void events$set(MemorySegment seg, int x) { + constants$0.const$1.set(seg, x); + } + public static int events$get(MemorySegment seg, long index) { + return (int)constants$0.const$1.get(seg.asSlice(index*sizeof())); + } + public static void events$set(MemorySegment seg, long index, int x) { + constants$0.const$1.set(seg.asSlice(index*sizeof()), x); + } + public static MemorySegment data$slice(MemorySegment seg) { + return seg.asSlice(4, 8); + } + public static long sizeof() { return $LAYOUT().byteSize(); } + public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } + public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); + } + public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } +} + + diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java index 5db1b04..b9a9566 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/errno/errno.java @@ -15,6 +15,22 @@ public class errno { public static final OfFloat C_FLOAT = JAVA_FLOAT; public static final OfDouble C_DOUBLE = JAVA_DOUBLE; public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; + /** + * {@snippet : + * #define ENOENT 2 + * } + */ + public static int ENOENT() { + return (int)2L; + } + /** + * {@snippet : + * #define EINTR 4 + * } + */ + public static int EINTR() { + return (int)4L; + } /** * {@snippet : * #define EAGAIN 11 diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/constants$0.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/constants$0.java deleted file mode 100644 index 112fe8b..0000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/constants$0.java +++ /dev/null @@ -1,35 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.poll; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.StructLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; - -import static java.lang.foreign.ValueLayout.*; -final class constants$0 { - - // Suppresses default constructor, ensuring non-instantiability. - private constants$0() {} - static final StructLayout const$0 = MemoryLayout.structLayout( - JAVA_INT.withName("fd"), - JAVA_SHORT.withName("events"), - JAVA_SHORT.withName("revents") - ).withName("pollfd"); - static final VarHandle const$1 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("fd")); - static final VarHandle const$2 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("events")); - static final VarHandle const$3 = constants$0.const$0.varHandle(MemoryLayout.PathElement.groupElement("revents")); - static final FunctionDescriptor const$4 = FunctionDescriptor.of(JAVA_INT, - RuntimeHelper.POINTER, - JAVA_LONG, - JAVA_INT - ); - static final MethodHandle const$5 = RuntimeHelper.downcallHandle( - "poll", - constants$0.const$4 - ); -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/poll.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/poll.java deleted file mode 100644 index c3002ab..0000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/poll.java +++ /dev/null @@ -1,62 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.poll; - -import java.lang.foreign.AddressLayout; -import java.lang.foreign.MemorySegment; -import java.lang.invoke.MethodHandle; - -import static java.lang.foreign.ValueLayout.*; -public class poll { - - public static final OfByte C_CHAR = JAVA_BYTE; - public static final OfShort C_SHORT = JAVA_SHORT; - public static final OfInt C_INT = JAVA_INT; - public static final OfLong C_LONG = JAVA_LONG; - public static final OfLong C_LONG_LONG = JAVA_LONG; - public static final OfFloat C_FLOAT = JAVA_FLOAT; - public static final OfDouble C_DOUBLE = JAVA_DOUBLE; - public static final AddressLayout C_POINTER = RuntimeHelper.POINTER; - /** - * {@snippet : - * #define POLLIN 1 - * } - */ - public static int POLLIN() { - return (int)1L; - } - /** - * {@snippet : - * #define POLLOUT 4 - * } - */ - public static int POLLOUT() { - return (int)4L; - } - /** - * {@snippet : - * #define POLLERR 8 - * } - */ - public static int POLLERR() { - return (int)8L; - } - public static MethodHandle poll$MH() { - return RuntimeHelper.requireNonNull(constants$0.const$5,"poll"); - } - /** - * {@snippet : - * int poll(struct pollfd* __fds, nfds_t __nfds, int __timeout); - * } - */ - public static int poll(MemorySegment __fds, long __nfds, int __timeout) { - var mh$ = poll$MH(); - try { - return (int)mh$.invokeExact(__fds, __nfds, __timeout); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } -} - - diff --git a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/pollfd.java b/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/pollfd.java deleted file mode 100644 index 6d632aa..0000000 --- a/java-does-usb/src/main/java/net/codecrete/usb/linux/gen/poll/pollfd.java +++ /dev/null @@ -1,113 +0,0 @@ -// Generated by jextract - -package net.codecrete.usb.linux.gen.poll; - -import java.lang.foreign.Arena; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.lang.invoke.VarHandle; -/** - * {@snippet : - * struct pollfd { - * int fd; - * short events; - * short revents; - * }; - * } - */ -public class pollfd { - - public static MemoryLayout $LAYOUT() { - return constants$0.const$0; - } - public static VarHandle fd$VH() { - return constants$0.const$1; - } - /** - * Getter for field: - * {@snippet : - * int fd; - * } - */ - public static int fd$get(MemorySegment seg) { - return (int)constants$0.const$1.get(seg); - } - /** - * Setter for field: - * {@snippet : - * int fd; - * } - */ - public static void fd$set(MemorySegment seg, int x) { - constants$0.const$1.set(seg, x); - } - public static int fd$get(MemorySegment seg, long index) { - return (int)constants$0.const$1.get(seg.asSlice(index*sizeof())); - } - public static void fd$set(MemorySegment seg, long index, int x) { - constants$0.const$1.set(seg.asSlice(index*sizeof()), x); - } - public static VarHandle events$VH() { - return constants$0.const$2; - } - /** - * Getter for field: - * {@snippet : - * short events; - * } - */ - public static short events$get(MemorySegment seg) { - return (short)constants$0.const$2.get(seg); - } - /** - * Setter for field: - * {@snippet : - * short events; - * } - */ - public static void events$set(MemorySegment seg, short x) { - constants$0.const$2.set(seg, x); - } - public static short events$get(MemorySegment seg, long index) { - return (short)constants$0.const$2.get(seg.asSlice(index*sizeof())); - } - public static void events$set(MemorySegment seg, long index, short x) { - constants$0.const$2.set(seg.asSlice(index*sizeof()), x); - } - public static VarHandle revents$VH() { - return constants$0.const$3; - } - /** - * Getter for field: - * {@snippet : - * short revents; - * } - */ - public static short revents$get(MemorySegment seg) { - return (short)constants$0.const$3.get(seg); - } - /** - * Setter for field: - * {@snippet : - * short revents; - * } - */ - public static void revents$set(MemorySegment seg, short x) { - constants$0.const$3.set(seg, x); - } - public static short revents$get(MemorySegment seg, long index) { - return (short)constants$0.const$3.get(seg.asSlice(index*sizeof())); - } - public static void revents$set(MemorySegment seg, long index, short x) { - constants$0.const$3.set(seg.asSlice(index*sizeof()), x); - } - public static long sizeof() { return $LAYOUT().byteSize(); } - public static MemorySegment allocate(SegmentAllocator allocator) { return allocator.allocate($LAYOUT()); } - public static MemorySegment allocateArray(long len, SegmentAllocator allocator) { - return allocator.allocate(MemoryLayout.sequenceLayout(len, $LAYOUT())); - } - public static MemorySegment ofAddress(MemorySegment addr, Arena scope) { return RuntimeHelper.asArray(addr, $LAYOUT(), 1, scope); } -} - -