diff --git a/src/java.base/macosx/classes/jdk/internal/ffi/generated/ErrnoUtils.java b/src/java.base/macosx/classes/jdk/internal/ffi/generated/ErrnoUtils.java new file mode 100644 index 0000000000000..7050900a3db3f --- /dev/null +++ b/src/java.base/macosx/classes/jdk/internal/ffi/generated/ErrnoUtils.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.ffi.generated; + +import jdk.internal.ffi.generated.errno.errno_h; + +import java.io.IOException; +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.nio.charset.StandardCharsets; + +// Errno utility for macosx platform +public final class ErrnoUtils { + private ErrnoUtils() { + } + + private static final long ERRNO_STRING_HOLDER_ARRAY_SIZE = 256L; + + public static IOException IOExceptionWithErrnoString(int errno, String message) { + try (Arena arena = Arena.ofConfined()) { + MemorySegment buf = arena.allocate(ERRNO_STRING_HOLDER_ARRAY_SIZE); + if (errno_h.strerror_r(errno, buf, ERRNO_STRING_HOLDER_ARRAY_SIZE) == 0) { + String errnoMsg = buf.getString(0, StandardCharsets.UTF_8); + return new IOException(message + " " + errnoMsg); + } else { + // failed to convert errno to string - output errno value + return new IOException(message + " Errno: " + errno); + } + } + } +} diff --git a/src/java.base/macosx/classes/jdk/internal/ffi/generated/errno/errno_h.java b/src/java.base/macosx/classes/jdk/internal/ffi/generated/errno/errno_h.java new file mode 100644 index 0000000000000..17f1a51a96ecc --- /dev/null +++ b/src/java.base/macosx/classes/jdk/internal/ffi/generated/errno/errno_h.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +// Generated by jextract + +package jdk.internal.ffi.generated.errno; + +import jdk.internal.ffi.util.FFMUtils; + +import java.lang.invoke.*; +import java.lang.foreign.*; + +@SuppressWarnings("restricted") +public class errno_h { + + errno_h() { + // Should not be called directly + } + + private static final int EINTR = (int)4L; + /** + * {@snippet lang=c : + * #define EINTR 4 + * } + */ + public static int EINTR() { + return EINTR; + } + + private static class strerror_r { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + FFMUtils.C_INT, + FFMUtils.C_INT, + FFMUtils.C_POINTER, + FFMUtils.C_LONG + ); + + public static final MemorySegment ADDR = FFMUtils.findOrThrow("strerror_r"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * int strerror_r(int __errnum, char *__strerrbuf, size_t __buflen) + * } + */ + public static FunctionDescriptor strerror_r$descriptor() { + return strerror_r.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * int strerror_r(int __errnum, char *__strerrbuf, size_t __buflen) + * } + */ + public static MethodHandle strerror_r$handle() { + return strerror_r.HANDLE; + } + + /** + * Address for: + * {@snippet lang=c : + * int strerror_r(int __errnum, char *__strerrbuf, size_t __buflen) + * } + */ + public static MemorySegment strerror_r$address() { + return strerror_r.ADDR; + } + + /** + * {@snippet lang=c : + * int strerror_r(int __errnum, char *__strerrbuf, size_t __buflen) + * } + */ + public static int strerror_r(int __errnum, MemorySegment __strerrbuf, long __buflen) { + var mh$ = strerror_r.HANDLE; + try { + if (FFMUtils.TRACE_DOWNCALLS) { + FFMUtils.traceDowncall("strerror_r", __errnum, __strerrbuf, __buflen); + } + return (int)mh$.invokeExact(__errnum, __strerrbuf, __buflen); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } +} diff --git a/src/java.base/macosx/classes/jdk/internal/ffi/generated/errno/package-info.java b/src/java.base/macosx/classes/jdk/internal/ffi/generated/errno/package-info.java new file mode 100644 index 0000000000000..bd7afb997697b --- /dev/null +++ b/src/java.base/macosx/classes/jdk/internal/ffi/generated/errno/package-info.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * Defines native structures for errno APIs. + * Generated with the following jextract command: + * {@snippet lang = "Shell Script": + * + * HEADER_NAME=errno.h + * echo "#include " > $HEADER_NAME + * echo "#include " >> $HEADER_NAME + * + * jextract --target-package jdk.internal.ffi.generated.errno \ + * --include-constant EINTR \ + * --include-function strerror_r \ + * $HEADER_NAME + * } + * + * After generation of native bindings, the layouts for the C builtin layouts and other + * variables/methods not specific to a component area are moved to the {@code BindingUtils} class + * for future reusability. + * + */ + +package jdk.internal.ffi.generated.errno; diff --git a/src/java.base/macosx/classes/jdk/internal/ffi/generated/kqueue/kevent.java b/src/java.base/macosx/classes/jdk/internal/ffi/generated/kqueue/kevent.java new file mode 100644 index 0000000000000..09cd3660964cb --- /dev/null +++ b/src/java.base/macosx/classes/jdk/internal/ffi/generated/kqueue/kevent.java @@ -0,0 +1,387 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +// Generated by jextract + +package jdk.internal.ffi.generated.kqueue; + +import jdk.internal.ffi.util.FFMUtils; + +import java.lang.foreign.GroupLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.AddressLayout; +import java.lang.foreign.SegmentAllocator; +import java.lang.foreign.Arena; +import java.util.function.Consumer; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.ValueLayout.OfLong; +import static java.lang.foreign.ValueLayout.OfShort; +import static java.lang.foreign.ValueLayout.OfInt; + +/** + * {@snippet lang=c : + * struct kevent { + * uintptr_t ident; + * int16_t filter; + * uint16_t flags; + * uint32_t fflags; + * intptr_t data; + * void *udata; + * } + * } + */ +@SuppressWarnings("restricted") +public class kevent { + + kevent() { + // Should not be called directly + } + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + FFMUtils.align(FFMUtils.C_LONG, 4).withName("ident"), + FFMUtils.C_SHORT.withName("filter"), + FFMUtils.C_SHORT.withName("flags"), + FFMUtils.C_INT.withName("fflags"), + FFMUtils.align(FFMUtils.C_LONG, 4).withName("data"), + FFMUtils.align(FFMUtils.C_POINTER, 4).withName("udata") + ).withName("kevent"); + + /** + * The layout of this struct + */ + public static final GroupLayout layout() { + return $LAYOUT; + } + + private static final OfLong ident$LAYOUT = (OfLong)$LAYOUT.select(groupElement("ident")); + + /** + * Layout for field: + * {@snippet lang=c : + * uintptr_t ident + * } + */ + public static final OfLong ident$layout() { + return ident$LAYOUT; + } + + private static final long ident$OFFSET = 0; + + /** + * Offset for field: + * {@snippet lang=c : + * uintptr_t ident + * } + */ + public static final long ident$offset() { + return ident$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * uintptr_t ident + * } + */ + public static long ident(MemorySegment struct) { + return struct.get(ident$LAYOUT, ident$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * uintptr_t ident + * } + */ + public static void ident(MemorySegment struct, long fieldValue) { + struct.set(ident$LAYOUT, ident$OFFSET, fieldValue); + } + + private static final OfShort filter$LAYOUT = (OfShort)$LAYOUT.select(groupElement("filter")); + + /** + * Layout for field: + * {@snippet lang=c : + * int16_t filter + * } + */ + public static final OfShort filter$layout() { + return filter$LAYOUT; + } + + private static final long filter$OFFSET = 8; + + /** + * Offset for field: + * {@snippet lang=c : + * int16_t filter + * } + */ + public static final long filter$offset() { + return filter$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * int16_t filter + * } + */ + public static short filter(MemorySegment struct) { + return struct.get(filter$LAYOUT, filter$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * int16_t filter + * } + */ + public static void filter(MemorySegment struct, short fieldValue) { + struct.set(filter$LAYOUT, filter$OFFSET, fieldValue); + } + + private static final OfShort flags$LAYOUT = (OfShort)$LAYOUT.select(groupElement("flags")); + + /** + * Layout for field: + * {@snippet lang=c : + * uint16_t flags + * } + */ + public static final OfShort flags$layout() { + return flags$LAYOUT; + } + + private static final long flags$OFFSET = 10; + + /** + * Offset for field: + * {@snippet lang=c : + * uint16_t flags + * } + */ + public static final long flags$offset() { + return flags$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * uint16_t flags + * } + */ + public static short flags(MemorySegment struct) { + return struct.get(flags$LAYOUT, flags$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * uint16_t flags + * } + */ + public static void flags(MemorySegment struct, short fieldValue) { + struct.set(flags$LAYOUT, flags$OFFSET, fieldValue); + } + + private static final OfInt fflags$LAYOUT = (OfInt)$LAYOUT.select(groupElement("fflags")); + + /** + * Layout for field: + * {@snippet lang=c : + * uint32_t fflags + * } + */ + public static final OfInt fflags$layout() { + return fflags$LAYOUT; + } + + private static final long fflags$OFFSET = 12; + + /** + * Offset for field: + * {@snippet lang=c : + * uint32_t fflags + * } + */ + public static final long fflags$offset() { + return fflags$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * uint32_t fflags + * } + */ + public static int fflags(MemorySegment struct) { + return struct.get(fflags$LAYOUT, fflags$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * uint32_t fflags + * } + */ + public static void fflags(MemorySegment struct, int fieldValue) { + struct.set(fflags$LAYOUT, fflags$OFFSET, fieldValue); + } + + private static final OfLong data$LAYOUT = (OfLong)$LAYOUT.select(groupElement("data")); + + /** + * Layout for field: + * {@snippet lang=c : + * intptr_t data + * } + */ + public static final OfLong data$layout() { + return data$LAYOUT; + } + + private static final long data$OFFSET = 16; + + /** + * Offset for field: + * {@snippet lang=c : + * intptr_t data + * } + */ + public static final long data$offset() { + return data$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * intptr_t data + * } + */ + public static long data(MemorySegment struct) { + return struct.get(data$LAYOUT, data$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * intptr_t data + * } + */ + public static void data(MemorySegment struct, long fieldValue) { + struct.set(data$LAYOUT, data$OFFSET, fieldValue); + } + + private static final AddressLayout udata$LAYOUT = (AddressLayout)$LAYOUT.select(groupElement("udata")); + + /** + * Layout for field: + * {@snippet lang=c : + * void *udata + * } + */ + public static final AddressLayout udata$layout() { + return udata$LAYOUT; + } + + private static final long udata$OFFSET = 24; + + /** + * Offset for field: + * {@snippet lang=c : + * void *udata + * } + */ + public static final long udata$offset() { + return udata$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * void *udata + * } + */ + public static MemorySegment udata(MemorySegment struct) { + return struct.get(udata$LAYOUT, udata$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * void *udata + * } + */ + public static void udata(MemorySegment struct, MemorySegment fieldValue) { + struct.set(udata$LAYOUT, udata$OFFSET, fieldValue); + } + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); + } + + /** + * The size (in bytes) of this struct + */ + public static long sizeof() { return layout().byteSize(); } + + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); + } + + /** + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. + */ + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any). + * The returned segment has size {@code layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); + } +} diff --git a/src/java.base/macosx/classes/jdk/internal/ffi/generated/kqueue/kqueue_h.java b/src/java.base/macosx/classes/jdk/internal/ffi/generated/kqueue/kqueue_h.java new file mode 100644 index 0000000000000..cd98398f181be --- /dev/null +++ b/src/java.base/macosx/classes/jdk/internal/ffi/generated/kqueue/kqueue_h.java @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +// Generated by jextract + +package jdk.internal.ffi.generated.kqueue; + +import jdk.internal.ffi.util.FFMUtils; +import jdk.internal.foreign.*; + +import java.lang.foreign.*; +import java.lang.invoke.MethodHandle; + +@SuppressWarnings("restricted") +public class kqueue_h { + + private static final String ERRNO_NAME = "errno"; + + kqueue_h() { + // Should not be called directly + } + + static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.loaderLookup() + .or(Linker.nativeLinker().defaultLookup()); + + private static final int EV_ADD = (int)1L; + /** + * {@snippet lang=c : + * #define EV_ADD 1 + * } + */ + public static int EV_ADD() { + return EV_ADD; + } + private static final int EV_DELETE = (int)2L; + /** + * {@snippet lang=c : + * #define EV_DELETE 2 + * } + */ + public static int EV_DELETE() { + return EV_DELETE; + } + private static final int EV_ONESHOT = (int)16L; + /** + * {@snippet lang=c : + * #define EV_ONESHOT 16 + * } + */ + public static int EV_ONESHOT() { + return EV_ONESHOT; + } + + private static final int EV_CLEAR = (int)32L; + /** + * {@snippet lang=c : + * #define EV_CLEAR 32 + * } + */ + public static int EV_CLEAR() { + return EV_CLEAR; + } + + private static class kqueue { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + FFMUtils.C_INT ); + + public static final MemorySegment ADDR = FFMUtils.findOrThrow("kqueue"); + + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC, + Linker.Option.captureCallState(ERRNO_NAME)); + + public static final MethodHandle ADAPTED = CaptureStateUtil.adaptSystemCall(HANDLE, ERRNO_NAME); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * int kqueue() + * } + */ + public static FunctionDescriptor kqueue$descriptor() { + return kqueue.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * int kqueue() + * } + */ + public static MethodHandle kqueue$handle() { + return kqueue.HANDLE; + } + + /** + * Address for: + * {@snippet lang=c : + * int kqueue() + * } + */ + public static MemorySegment kqueue$address() { + return kqueue.ADDR; + } + + /** + * {@snippet lang=c : + * int kqueue() + * } + */ + public static int kqueue() { + try { + return (int) kqueue.ADAPTED.invokeExact(); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + + private static class kevent { + public static final FunctionDescriptor DESC = FunctionDescriptor.of( + FFMUtils.C_INT, + FFMUtils.C_INT, + FFMUtils.C_POINTER, + FFMUtils.C_INT, + FFMUtils.C_POINTER, + FFMUtils.C_INT, + FFMUtils.C_POINTER + ); + + public static final MemorySegment ADDR = FFMUtils.findOrThrow("kevent"); + public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC, + Linker.Option.captureCallState(ERRNO_NAME)); + public static final MethodHandle ADAPTED = CaptureStateUtil.adaptSystemCall(HANDLE, ERRNO_NAME); + } + + /** + * Function descriptor for: + * {@snippet lang=c : + * int kevent(int kq, const struct kevent *changelist, int nchanges, struct kevent *eventlist, int nevents, const struct timespec *timeout) + * } + */ + public static FunctionDescriptor kevent$descriptor() { + return kevent.DESC; + } + + /** + * Downcall method handle for: + * {@snippet lang=c : + * int kevent(int kq, const struct kevent *changelist, int nchanges, struct kevent *eventlist, int nevents, const struct timespec *timeout) + * } + */ + public static MethodHandle kevent$handle() { + return kevent.HANDLE; + } + + /** + * Address for: + * {@snippet lang=c : + * int kevent(int kq, const struct kevent *changelist, int nchanges, struct kevent *eventlist, int nevents, const struct timespec *timeout) + * } + */ + public static MemorySegment kevent$address() { + return kevent.ADDR; + } + + /** + * {@snippet lang=c : + * int kevent(int kq, const struct kevent *changelist, int nchanges, struct kevent *eventlist, int nevents, const struct timespec *timeout) + * } + */ + public static int kevent(int kq, MemorySegment changelist, int nchanges, MemorySegment eventlist, int nevents, MemorySegment timeout) { + try { + if (FFMUtils.TRACE_DOWNCALLS) { + FFMUtils.traceDowncall("kevent", kq, changelist, nchanges, eventlist, nevents, timeout); + } + return (int) kevent.ADAPTED.invokeExact(kq, changelist, nchanges, eventlist, nevents, timeout); + } catch (Throwable ex$) { + throw new AssertionError("should not reach here", ex$); + } + } + + private static final int EVFILT_READ = (int)-1L; + /** + * {@snippet lang=c : + * #define EVFILT_READ -1 + * } + */ + public static int EVFILT_READ() { + return EVFILT_READ; + } + private static final int EVFILT_WRITE = (int)-2L; + /** + * {@snippet lang=c : + * #define EVFILT_WRITE -2 + * } + */ + public static int EVFILT_WRITE() { + return EVFILT_WRITE; + } +} diff --git a/src/java.base/macosx/classes/jdk/internal/ffi/generated/kqueue/package-info.java b/src/java.base/macosx/classes/jdk/internal/ffi/generated/kqueue/package-info.java new file mode 100644 index 0000000000000..6f9b0ad7f838d --- /dev/null +++ b/src/java.base/macosx/classes/jdk/internal/ffi/generated/kqueue/package-info.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * Defines native structures for Kqueue socket APIs. + * Generated with the following jextract command: + * {@snippet lang = "Shell Script": + * + * HEADER_NAME=kqueue.h + * echo "#include " > $HEADER_NAME + * echo "#include " >> $HEADER_NAME + * + * + * $JEXTRACT --target-package jdk.internal.natives.net.kqueue \ + * --include-constant EV_CLEAR \ + * --include-constant EV_ONESHOT \ + * --include-constant EV_DELETE \ + * --include-constant EV_ADD \ + * --include-constant EVFILT_WRITE \ + * --include-constant EVFILT_READ \ + * --include-function kevent \ + * --include-function kqueue \ + * --include-struct kevent \ + * --include-struct klist \ + * $HEADER_NAME + * } + * + * After generation of native bindings, the layouts for the C builtin layouts and other + * variables/methods not specific to a component area are moved to the {@code BindingUtils} class + * for future reusability. + * + */ + +package jdk.internal.ffi.generated.kqueue; diff --git a/src/java.base/macosx/classes/jdk/internal/ffi/generated/timespec/package-info.java b/src/java.base/macosx/classes/jdk/internal/ffi/generated/timespec/package-info.java new file mode 100644 index 0000000000000..dc32d8c7721a1 --- /dev/null +++ b/src/java.base/macosx/classes/jdk/internal/ffi/generated/timespec/package-info.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * Defines native structures for timespec APIs. + * Generated with the following jextract command: + * {@snippet lang = "Shell Script": + * + * HEADER_NAME=timespec.h + * echo "#include " > $HEADER_NAME + * + * jextract --target-package jdk.internal.ffi.generated.timespec \ + * --include-struct timespec \ + * $HEADER_NAME + * } + * + * After generation of native bindings, the layouts for the C builtin layouts and other + * variables/methods not specific to a component area are moved to the {@code BindingUtils} class + * for future reusability. + * + */ + +package jdk.internal.ffi.generated.timespec; diff --git a/src/java.base/macosx/classes/jdk/internal/ffi/generated/timespec/timespec.java b/src/java.base/macosx/classes/jdk/internal/ffi/generated/timespec/timespec.java new file mode 100644 index 0000000000000..e135228b92326 --- /dev/null +++ b/src/java.base/macosx/classes/jdk/internal/ffi/generated/timespec/timespec.java @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +// Generated by jextract + +package jdk.internal.ffi.generated.timespec; + +import jdk.internal.ffi.util.*; + +import java.lang.foreign.*; +import java.util.function.Consumer; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.lang.foreign.ValueLayout.OfLong; + +/** + * {@snippet lang=c : + * struct timespec { + * __darwin_time_t tv_sec; + * long tv_nsec; + * } + * } + */ +@SuppressWarnings("restricted") +public class timespec { + + timespec() { + // Should not be called directly + } + + private static final GroupLayout $LAYOUT = MemoryLayout.structLayout( + FFMUtils.C_LONG.withName("tv_sec"), + FFMUtils.C_LONG.withName("tv_nsec") + ).withName("timespec"); + + /** + * The layout of this struct + */ + public static final GroupLayout layout() { + return $LAYOUT; + } + + private static final OfLong tv_sec$LAYOUT = (OfLong)$LAYOUT.select(groupElement("tv_sec")); + + /** + * Layout for field: + * {@snippet lang=c : + * __darwin_time_t tv_sec + * } + */ + public static final OfLong tv_sec$layout() { + return tv_sec$LAYOUT; + } + + private static final long tv_sec$OFFSET = 0; + + /** + * Offset for field: + * {@snippet lang=c : + * __darwin_time_t tv_sec + * } + */ + public static final long tv_sec$offset() { + return tv_sec$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * __darwin_time_t tv_sec + * } + */ + public static long tv_sec(MemorySegment struct) { + return struct.get(tv_sec$LAYOUT, tv_sec$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * __darwin_time_t tv_sec + * } + */ + public static void tv_sec(MemorySegment struct, long fieldValue) { + struct.set(tv_sec$LAYOUT, tv_sec$OFFSET, fieldValue); + } + + private static final OfLong tv_nsec$LAYOUT = (OfLong)$LAYOUT.select(groupElement("tv_nsec")); + + /** + * Layout for field: + * {@snippet lang=c : + * long tv_nsec + * } + */ + public static final OfLong tv_nsec$layout() { + return tv_nsec$LAYOUT; + } + + private static final long tv_nsec$OFFSET = 8; + + /** + * Offset for field: + * {@snippet lang=c : + * long tv_nsec + * } + */ + public static final long tv_nsec$offset() { + return tv_nsec$OFFSET; + } + + /** + * Getter for field: + * {@snippet lang=c : + * long tv_nsec + * } + */ + public static long tv_nsec(MemorySegment struct) { + return struct.get(tv_nsec$LAYOUT, tv_nsec$OFFSET); + } + + /** + * Setter for field: + * {@snippet lang=c : + * long tv_nsec + * } + */ + public static void tv_nsec(MemorySegment struct, long fieldValue) { + struct.set(tv_nsec$LAYOUT, tv_nsec$OFFSET, fieldValue); + } + + /** + * Obtains a slice of {@code arrayParam} which selects the array element at {@code index}. + * The returned segment has address {@code arrayParam.address() + index * layout().byteSize()} + */ + public static MemorySegment asSlice(MemorySegment array, long index) { + return array.asSlice(layout().byteSize() * index); + } + + /** + * The size (in bytes) of this struct + */ + public static long sizeof() { return layout().byteSize(); } + + /** + * Allocate a segment of size {@code layout().byteSize()} using {@code allocator} + */ + public static MemorySegment allocate(SegmentAllocator allocator) { + return allocator.allocate(layout()); + } + + /** + * Allocate an array of size {@code elementCount} using {@code allocator}. + * The returned segment has size {@code elementCount * layout().byteSize()}. + */ + public static MemorySegment allocateArray(long elementCount, SegmentAllocator allocator) { + return allocator.allocate(MemoryLayout.sequenceLayout(elementCount, layout())); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any). + * The returned segment has size {@code layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, Arena arena, Consumer cleanup) { + return reinterpret(addr, 1, arena, cleanup); + } + + /** + * Reinterprets {@code addr} using target {@code arena} and {@code cleanupAction} (if any). + * The returned segment has size {@code elementCount * layout().byteSize()} + */ + public static MemorySegment reinterpret(MemorySegment addr, long elementCount, Arena arena, Consumer cleanup) { + return addr.reinterpret(layout().byteSize() * elementCount, arena, cleanup); + } +} diff --git a/src/java.base/macosx/classes/jdk/internal/ffi/util/FFMUtils.java b/src/java.base/macosx/classes/jdk/internal/ffi/util/FFMUtils.java new file mode 100644 index 0000000000000..33a2a27cea8b8 --- /dev/null +++ b/src/java.base/macosx/classes/jdk/internal/ffi/util/FFMUtils.java @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.ffi.util; + +import java.lang.foreign.*; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.util.Arrays; +import java.util.stream.Collectors; + +import jdk.internal.misc.Unsafe; + +@SuppressWarnings("restricted") +public final class FFMUtils { + + public static final ValueLayout.OfBoolean C_BOOL = + (ValueLayout.OfBoolean) Linker.nativeLinker().canonicalLayouts().get("bool"); + + public static final ValueLayout.OfByte C_CHAR = + (ValueLayout.OfByte)Linker.nativeLinker().canonicalLayouts().get("char"); + + public static final ValueLayout.OfShort C_SHORT = + (ValueLayout.OfShort) Linker.nativeLinker().canonicalLayouts().get("short"); + + public static final ValueLayout.OfInt C_INT = + (ValueLayout.OfInt) Linker.nativeLinker().canonicalLayouts().get("int"); + + public static final ValueLayout.OfLong C_LONG_LONG = + (ValueLayout.OfLong) Linker.nativeLinker().canonicalLayouts().get("long long"); + + public static final ValueLayout.OfFloat C_FLOAT = + (ValueLayout.OfFloat) Linker.nativeLinker().canonicalLayouts().get("float"); + + public static final ValueLayout.OfDouble C_DOUBLE = + (ValueLayout.OfDouble) Linker.nativeLinker().canonicalLayouts().get("double"); + + public static final AddressLayout C_POINTER = + ((AddressLayout) Linker.nativeLinker().canonicalLayouts().get("void*")) + .withTargetLayout(MemoryLayout.sequenceLayout(Long.MAX_VALUE, C_CHAR)); + + public static final ValueLayout.OfLong C_LONG = + (ValueLayout.OfLong) Linker.nativeLinker().canonicalLayouts().get("long"); + + private FFMUtils() { + } + + /** + * Returns a {@code MemorySegment} set to the size of byteSize + * + * @param byteSize the size in bytes to be allocated + * @param byteAlignment the size in bytes for the memory alignment + * + * @throws IllegalArgumentException if the maxByteAlignment of the created + * MemorySegment is less than the provided byteAlignment + * + * @return the newly created {@code MemorySegment} + */ + public static MemorySegment malloc(long byteSize, long byteAlignment) { + long allocatedMemory = UNSAFE.allocateMemory(byteSize); + MemorySegment result = MemorySegment.ofAddress(allocatedMemory).reinterpret(byteSize); + if (result.maxByteAlignment() < byteAlignment) { + throw new IllegalArgumentException(); + } + return result; + } + + /** + * Takes a {@code MemorySegment} and deallocates the memory at that address + * @param memorySegment the {@code MemorySegment} that will be deallocated + */ + public static void free(MemorySegment memorySegment) { + UNSAFE.freeMemory(memorySegment.address()); + } + + // SegmentAllocator that delegates to Unsafe for memory allocation + public static final SegmentAllocator SEGMENT_ALLOCATOR = new SegmentAllocator() { + @Override + public MemorySegment allocate(long byteSize, long byteAlignment) { + return malloc(byteSize, byteAlignment); + } + }; + + private static final Unsafe UNSAFE = Unsafe.getUnsafe(); + + // Variables and methods below are extracted from jextract generated + // code and used by native bindings on all platforms + public static final boolean TRACE_DOWNCALLS = false; + static final SymbolLookup SYMBOL_LOOKUP = SymbolLookup.loaderLookup() + .or(Linker.nativeLinker().defaultLookup()); + + public static void traceDowncall(String name, Object... args) { + String traceArgs = Arrays.stream(args) + .map(Object::toString) + .collect(Collectors.joining(", ")); + System.out.printf("%s(%s)\n", name, traceArgs); + } + + public static MemorySegment findOrThrow(String symbol) { + return SYMBOL_LOOKUP.findOrThrow(symbol); + } + + public static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { + try { + return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); + } catch (ReflectiveOperationException ex) { + throw new AssertionError(ex); + } + } + + public static MemoryLayout align(MemoryLayout layout, long align) { + return switch (layout) { + case PaddingLayout p -> p; + case ValueLayout v -> v.withByteAlignment(align); + case GroupLayout g -> { + MemoryLayout[] alignedMembers = g.memberLayouts().stream() + .map(m -> align(m, align)).toArray(MemoryLayout[]::new); + yield g instanceof StructLayout ? + MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); + } + case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); + }; + } +} diff --git a/src/java.base/macosx/classes/sun/nio/ch/KQueue.java b/src/java.base/macosx/classes/sun/nio/ch/KQueue.java index 30ad9ca92fe1d..8092e1bca4028 100644 --- a/src/java.base/macosx/classes/sun/nio/ch/KQueue.java +++ b/src/java.base/macosx/classes/sun/nio/ch/KQueue.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,17 +25,29 @@ package sun.nio.ch; +import jdk.internal.ffi.generated.kqueue.kevent; +import jdk.internal.ffi.generated.kqueue.kqueue_h; +import jdk.internal.ffi.generated.timespec.timespec; +import jdk.internal.ffi.generated.ErrnoUtils; +import jdk.internal.ffi.util.FFMUtils; +import jdk.internal.foreign.BufferStack; + import java.io.IOException; -import jdk.internal.misc.Unsafe; +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; + +import static java.lang.foreign.MemorySegment.NULL; +import static jdk.internal.ffi.generated.errno.errno_h.EINTR; /** * Provides access to the BSD kqueue facility. */ -class KQueue { - private KQueue() { } +final class KQueue { - private static final Unsafe unsafe = Unsafe.getUnsafe(); + private static final BufferStack POOL = BufferStack.of(timespec.layout()); + + private KQueue() { } /** * struct kevent { @@ -47,74 +59,112 @@ private KQueue() { } * void *udata; // opaque user data identifier * }; */ - static { - IOUtil.load(); - } - private static final int SIZEOF_KQUEUEEVENT = keventSize(); - private static final int OFFSET_IDENT = identOffset(); - private static final int OFFSET_FILTER = filterOffset(); - private static final int OFFSET_FLAGS = flagsOffset(); // filters - static final int EVFILT_READ = -1; - static final int EVFILT_WRITE = -2; + static final int EVFILT_READ = kqueue_h.EVFILT_READ(); + static final int EVFILT_WRITE = kqueue_h.EVFILT_WRITE(); // flags - static final int EV_ADD = 0x0001; - static final int EV_DELETE = 0x0002; - static final int EV_ONESHOT = 0x0010; - static final int EV_CLEAR = 0x0020; + static final int EV_ADD = kqueue_h.EV_ADD(); + static final int EV_DELETE = kqueue_h.EV_DELETE(); + static final int EV_ONESHOT = kqueue_h.EV_ONESHOT(); + static final int EV_CLEAR = kqueue_h.EV_CLEAR(); /** * Allocates a poll array to handle up to {@code count} events. */ - static long allocatePollArray(int count) { - return unsafe.allocateMemory(count * SIZEOF_KQUEUEEVENT); + static MemorySegment allocatePollArray(int count) { + return kevent.allocateArray(count, FFMUtils.SEGMENT_ALLOCATOR); } /** * Free a poll array */ - static void freePollArray(long address) { - unsafe.freeMemory(address); + static void freePollArray(MemorySegment memorySegment){ + FFMUtils.free(memorySegment); } /** * Returns kevent[i]. */ - static long getEvent(long address, int i) { - return address + (SIZEOF_KQUEUEEVENT*i); + static MemorySegment getEvent(MemorySegment memoryHandle, int i) { + return kevent.asSlice(memoryHandle, i); } /** * Returns the file descriptor from a kevent (assuming it is in the ident field) */ - static int getDescriptor(long address) { - return unsafe.getInt(address + OFFSET_IDENT); + static long getDescriptor(MemorySegment memoryHandle) { + return kevent.ident(memoryHandle); } - static short getFilter(long address) { - return unsafe.getShort(address + OFFSET_FILTER); + static short getFilter(MemorySegment memoryHandle) { + return kevent.filter(memoryHandle); } - static short getFlags(long address) { - return unsafe.getShort(address + OFFSET_FLAGS); + static short getFlags(MemorySegment memoryHandle) { + return kevent.flags(memoryHandle); } // -- Native methods -- - private static native int keventSize(); - - private static native int identOffset(); - - private static native int filterOffset(); - - private static native int flagsOffset(); - - static native int create() throws IOException; + static public int register(int kqfd, int fd, int filter, int flags) { + int result; + try (Arena arena = Arena.ofConfined()) { + MemorySegment keventMS = arena.allocate(kevent.layout()); + kevent.ident(keventMS, fd); + kevent.filter(keventMS, (short) filter); + kevent.flags(keventMS, (short) flags); + // rest default to zero + + // this do-while replaces restartable + do { + result = kqueue_h.kevent( + kqfd, keventMS, 1, NULL, + 0, NULL); + } while (result == -EINTR()); + } catch (Throwable e) { + throw new RuntimeException(e); + } + return result; + } - static native int register(int kqfd, int fd, int filter, int flags); + static public int poll(int kqfd, MemorySegment pollAddress, int nevents, long timeout) { + int result; + try (Arena arena = POOL.pushFrame(timespec.layout())) { + MemorySegment tsMS = arena.allocate(timespec.layout()); + MemorySegment tsp; + + if (timeout >= 0) { + timespec.tv_sec(tsMS, timeout / 1000); + timespec.tv_nsec(tsMS, (timeout % 1000) * 1000000); + tsp = tsMS; + } else { + tsp = NULL; + } + + result = kqueue_h.kevent( + kqfd, NULL, 0, pollAddress, + nevents, tsp); + if (result < 0) { + if (result == -EINTR()) { + return IOStatus.INTERRUPTED; + } else { + throw ErrnoUtils.IOExceptionWithErrnoString(-result, + "kqueue failed."); + } + } + } catch (Throwable e) { + throw new RuntimeException(e); + } + return result; + } - static native int poll(int kqfd, long pollAddress, int nevents, long timeout) - throws IOException; + static int create() throws IOException { + int res = kqueue_h.kqueue(); + if (res < 0) { + throw ErrnoUtils.IOExceptionWithErrnoString(-res, "kqueue failed"); + } + return res; + } } diff --git a/src/java.base/macosx/classes/sun/nio/ch/KQueuePoller.java b/src/java.base/macosx/classes/sun/nio/ch/KQueuePoller.java index 6a1c771820e1c..e849b61d3a90f 100644 --- a/src/java.base/macosx/classes/sun/nio/ch/KQueuePoller.java +++ b/src/java.base/macosx/classes/sun/nio/ch/KQueuePoller.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,12 @@ */ package sun.nio.ch; +import jdk.internal.ffi.generated.*; +import jdk.internal.ffi.generated.kqueue.kqueue_h; + import java.io.IOException; +import java.lang.foreign.MemorySegment; + import static sun.nio.ch.KQueue.*; /** @@ -34,13 +39,13 @@ class KQueuePoller extends Poller { private final int kqfd; private final int filter; private final int maxEvents; - private final long address; + private final MemorySegment pollArray; KQueuePoller(boolean subPoller, boolean read) throws IOException { this.kqfd = KQueue.create(); this.filter = (read) ? EVFILT_READ : EVFILT_WRITE; this.maxEvents = (subPoller) ? 64 : 512; - this.address = KQueue.allocatePollArray(maxEvents); + this.pollArray = KQueue.allocatePollArray(maxEvents); } @Override @@ -65,11 +70,11 @@ void implDeregister(int fdVal, boolean polled) { @Override int poll(int timeout) throws IOException { - int n = KQueue.poll(kqfd, address, maxEvents, timeout); + int n = KQueue.poll(kqfd, pollArray, maxEvents, timeout); int i = 0; while (i < n) { - long keventAddress = KQueue.getEvent(address, i); - int fdVal = KQueue.getDescriptor(keventAddress); + MemorySegment eventMS = KQueue.getEvent(pollArray, i); + int fdVal = (int) KQueue.getDescriptor(eventMS); polled(fdVal); i++; } diff --git a/src/java.base/macosx/classes/sun/nio/ch/KQueuePort.java b/src/java.base/macosx/classes/sun/nio/ch/KQueuePort.java index e6c0e09ad3465..1bbaca157d8ba 100644 --- a/src/java.base/macosx/classes/sun/nio/ch/KQueuePort.java +++ b/src/java.base/macosx/classes/sun/nio/ch/KQueuePort.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,8 +25,12 @@ package sun.nio.ch; -import java.nio.channels.spi.AsynchronousChannelProvider; +import jdk.internal.ffi.generated.*; +import jdk.internal.ffi.generated.kqueue.kqueue_h; + import java.io.IOException; +import java.lang.foreign.MemorySegment; +import java.nio.channels.spi.AsynchronousChannelProvider; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.atomic.AtomicInteger; @@ -50,7 +54,7 @@ final class KQueuePort private final int kqfd; // address of the poll array passed to kqueue_wait - private final long address; + private final MemorySegment pollArrayRegions; // true if kqueue closed private boolean closed; @@ -85,16 +89,15 @@ static class Event { throws IOException { super(provider, pool); - this.kqfd = KQueue.create(); - this.address = KQueue.allocatePollArray(MAX_KEVENTS_TO_POLL); + this.pollArrayRegions = KQueue.allocatePollArray(MAX_KEVENTS_TO_POLL); // create socket pair for wakeup mechanism try { long fds = IOUtil.makePipe(true); this.sp = new int[]{(int) (fds >>> 32), (int) fds}; } catch (IOException ioe) { - KQueue.freePollArray(address); + KQueue.freePollArray(pollArrayRegions); FileDispatcherImpl.closeIntFD(kqfd); throw ioe; } @@ -126,7 +129,7 @@ private void implClose() { try { FileDispatcherImpl.closeIntFD(kqfd); } catch (IOException ioe) { } try { FileDispatcherImpl.closeIntFD(sp[0]); } catch (IOException ioe) { } try { FileDispatcherImpl.closeIntFD(sp[1]); } catch (IOException ioe) { } - KQueue.freePollArray(address); + KQueue.freePollArray(pollArrayRegions); } private void wakeup() { @@ -197,7 +200,7 @@ private Event poll() throws IOException { for (;;) { int n; do { - n = KQueue.poll(kqfd, address, MAX_KEVENTS_TO_POLL, -1L); + n = KQueue.poll(kqfd, pollArrayRegions, MAX_KEVENTS_TO_POLL, -1L); } while (n == IOStatus.INTERRUPTED); /** @@ -209,8 +212,8 @@ private Event poll() throws IOException { fdToChannelLock.readLock().lock(); try { while (n-- > 0) { - long keventAddress = KQueue.getEvent(address, n); - int fd = KQueue.getDescriptor(keventAddress); + MemorySegment eventMS = KQueue.getEvent(pollArrayRegions, n); + int fd = (int) KQueue.getDescriptor(eventMS); // wakeup if (fd == sp[0]) { @@ -235,7 +238,7 @@ private Event poll() throws IOException { PollableChannel channel = fdToChannel.get(fd); if (channel != null) { - int filter = KQueue.getFilter(keventAddress); + int filter = KQueue.getFilter(eventMS); int events = 0; if (filter == EVFILT_READ) events = Net.POLLIN; diff --git a/src/java.base/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java b/src/java.base/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java index b1a781d71446b..bb4aa76494370 100644 --- a/src/java.base/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java +++ b/src/java.base/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,11 @@ package sun.nio.ch; +import jdk.internal.ffi.generated.*; +import jdk.internal.ffi.generated.kqueue.kqueue_h; + import java.io.IOException; +import java.lang.foreign.MemorySegment; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.spi.SelectorProvider; @@ -54,7 +58,7 @@ class KQueueSelectorImpl extends SelectorImpl { private final int kqfd; // address of poll array (event list) when polling for pending events - private final long pollArrayAddress; + private final MemorySegment pollArrayAddress; // file descriptors used for interrupt private final int fd0; @@ -77,7 +81,6 @@ class KQueueSelectorImpl extends SelectorImpl { KQueueSelectorImpl(SelectorProvider sp) throws IOException { super(sp); - this.kqfd = KQueue.create(); this.pollArrayAddress = KQueue.allocatePollArray(MAX_KEVENTS); @@ -97,7 +100,7 @@ class KQueueSelectorImpl extends SelectorImpl { @Override protected int doSelect(Consumer action, long timeout) - throws IOException + throws IOException { assert Thread.holdsLock(this); @@ -229,7 +232,7 @@ private void processUpdateQueue() { * If the interrupt fd has been selected, drain it and clear the interrupt. */ private int processEvents(int numEntries, Consumer action) - throws IOException + throws IOException { assert Thread.holdsLock(this); @@ -245,15 +248,15 @@ private int processEvents(int numEntries, Consumer action) pollCount++; for (int i = 0; i < numEntries; i++) { - long kevent = KQueue.getEvent(pollArrayAddress, i); - int fd = KQueue.getDescriptor(kevent); + MemorySegment eventMS = KQueue.getEvent(pollArrayAddress, i); + int fd = (int) KQueue.getDescriptor(eventMS); if (fd == fd0) { interrupted = true; } else { SelectionKeyImpl ski = fdToKey.get(fd); if (ski != null) { int rOps = 0; - short filter = KQueue.getFilter(kevent); + short filter = KQueue.getFilter(eventMS); if (filter == EVFILT_READ) { rOps |= Net.POLLIN; } else if (filter == EVFILT_WRITE) { diff --git a/src/java.base/macosx/native/libnio/ch/KQueue.c b/src/java.base/macosx/native/libnio/ch/KQueue.c deleted file mode 100644 index 04d500c484760..0000000000000 --- a/src/java.base/macosx/native/libnio/ch/KQueue.c +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include -#include -#include -#include - -#include "jni.h" -#include "jni_util.h" -#include "jlong.h" -#include "nio.h" -#include "nio_util.h" - -#include "sun_nio_ch_KQueue.h" - -JNIEXPORT jint JNICALL -Java_sun_nio_ch_KQueue_keventSize(JNIEnv* env, jclass clazz) -{ - return sizeof(struct kevent); -} - -JNIEXPORT jint JNICALL -Java_sun_nio_ch_KQueue_identOffset(JNIEnv* env, jclass clazz) -{ - return offsetof(struct kevent, ident); -} - -JNIEXPORT jint JNICALL -Java_sun_nio_ch_KQueue_filterOffset(JNIEnv* env, jclass clazz) -{ - return offsetof(struct kevent, filter); -} - -JNIEXPORT jint JNICALL -Java_sun_nio_ch_KQueue_flagsOffset(JNIEnv* env, jclass clazz) -{ - return offsetof(struct kevent, flags); -} - -JNIEXPORT jint JNICALL -Java_sun_nio_ch_KQueue_create(JNIEnv *env, jclass clazz) { - int kqfd = kqueue(); - if (kqfd < 0) { - JNU_ThrowIOExceptionWithLastError(env, "kqueue failed"); - return IOS_THROWN; - } - return kqfd; -} - -JNIEXPORT jint JNICALL -Java_sun_nio_ch_KQueue_register(JNIEnv *env, jclass clazz, jint kqfd, - jint fd, jint filter, jint flags) - -{ - struct kevent changes[1]; - int res; - - EV_SET(&changes[0], fd, filter, flags, 0, 0, 0); - RESTARTABLE(kevent(kqfd, &changes[0], 1, NULL, 0, NULL), res); - return (res == -1) ? errno : 0; -} - -JNIEXPORT jint JNICALL -Java_sun_nio_ch_KQueue_poll(JNIEnv *env, jclass clazz, jint kqfd, jlong address, - jint nevents, jlong timeout) -{ - struct kevent *events = jlong_to_ptr(address); - int res; - struct timespec ts; - struct timespec *tsp; - - if (timeout >= 0) { - ts.tv_sec = timeout / 1000; - ts.tv_nsec = (timeout % 1000) * 1000000; - tsp = &ts; - } else { - tsp = NULL; - } - - res = kevent(kqfd, NULL, 0, events, nevents, tsp); - if (res < 0) { - if (errno == EINTR) { - return IOS_INTERRUPTED; - } else { - JNU_ThrowIOExceptionWithLastError(env, "kqueue failed"); - return IOS_THROWN; - } - } - return res; -}