--- /dev/null Sun May 15 10:42:57 2022 +++ a/src/java.base/solaris/classes/sun/nio/ch/DefaultPollerProvider.java Sun May 15 10:17:39 2022 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2022, 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 sun.nio.ch; + +import java.io.IOException; + +/** + * Default PollerProvider for illumos/Solaris. + */ +class DefaultPollerProvider extends PollerProvider { + DefaultPollerProvider() { } + + @Override + Poller readPoller(boolean subPoller) throws IOException { + return new SolarisEventPortPoller(subPoller, true); + } + + @Override + Poller writePoller(boolean subPoller) throws IOException { + return new SolarisEventPortPoller(subPoller, false); + } +} diff --new-file -ur jdk-jdk-22-22/src/java.base/solaris/classes/sun/nio/ch/EPoll.java jdk-jdk-22-23/src/java.base/solaris/classes/sun/nio/ch/EPoll.java --- jdk-jdk-22-22/src/java.base/solaris/classes/sun/nio/ch/EPoll.java 1970-01-01 01:00:00.000000000 +0100 +++ jdk-jdk-22-23/src/java.base/solaris/classes/sun/nio/ch/EPoll.java 2023-11-09 09:45:49.844024203 +0000 @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2008, 2022, 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 sun.nio.ch; + +import java.io.IOException; +import jdk.internal.misc.Unsafe; + +/** + * Provides access to the Linux epoll facility. + */ + +class EPoll { + private EPoll() { } + + private static final Unsafe unsafe = Unsafe.getUnsafe(); + + /** + * typedef union epoll_data { + * void *ptr; + * int fd; + * __uint32_t u32; + * __uint64_t u64; + * } epoll_data_t; + * + * struct epoll_event { + * __uint32_t events; + * epoll_data_t data; + * } + */ + static { + IOUtil.load(); + } + private static final int SIZEOF_EPOLLEVENT = eventSize(); + private static final int OFFSETOF_EVENTS = eventsOffset(); + private static final int OFFSETOF_FD = dataOffset(); + + // opcodes + static final int EPOLL_CTL_ADD = 1; + static final int EPOLL_CTL_DEL = 2; + static final int EPOLL_CTL_MOD = 3; + + // events + static final int EPOLLIN = 0x1; + static final int EPOLLOUT = 0x4; + + // flags + static final int EPOLLONESHOT = (1 << 30); + + /** + * Allocates a poll array to handle up to {@code count} events. + */ + static long allocatePollArray(int count) { + return unsafe.allocateMemory(count * SIZEOF_EPOLLEVENT); + } + + /** + * Free a poll array + */ + static void freePollArray(long address) { + unsafe.freeMemory(address); + } + + /** + * Returns event[i]; + */ + static long getEvent(long address, int i) { + return address + (SIZEOF_EPOLLEVENT*i); + } + + /** + * Returns event->data.fd + */ + static int getDescriptor(long eventAddress) { + return unsafe.getInt(eventAddress + OFFSETOF_FD); + } + + /** + * Returns event->events + */ + static int getEvents(long eventAddress) { + return unsafe.getInt(eventAddress + OFFSETOF_EVENTS); + } + + // -- Native methods -- + + private static native int eventSize(); + + private static native int eventsOffset(); + + private static native int dataOffset(); + + static native int create() throws IOException; + + static native int ctl(int epfd, int opcode, int fd, int events); + + static native int wait(int epfd, long pollAddress, int numfds, int timeout) + throws IOException; +} diff --new-file -ur jdk-jdk-22-22/src/java.base/solaris/classes/sun/nio/ch/EPollPoller.java jdk-jdk-22-23/src/java.base/solaris/classes/sun/nio/ch/EPollPoller.java --- jdk-jdk-22-22/src/java.base/solaris/classes/sun/nio/ch/EPollPoller.java 1970-01-01 01:00:00.000000000 +0100 +++ jdk-jdk-22-23/src/java.base/solaris/classes/sun/nio/ch/EPollPoller.java 2023-11-09 09:45:51.976254333 +0000 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2017, 2023, 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 sun.nio.ch; + +import java.io.IOException; +import static sun.nio.ch.EPoll.*; + +/** + * Poller implementation based on the epoll facility. + */ + +class EPollPoller extends Poller { + private static final int ENOENT = 2; + + private final int epfd; + private final int event; + private final int maxEvents; + private final long address; + + EPollPoller(boolean subPoller, boolean read) throws IOException { + this.epfd = EPoll.create(); + this.event = (read) ? EPOLLIN : EPOLLOUT; + this.maxEvents = (subPoller) ? 64 : 512; + this.address = EPoll.allocatePollArray(maxEvents); + } + + @Override + int fdVal() { + return epfd; + } + + @Override + void implRegister(int fdVal) throws IOException { + // re-arm + int err = EPoll.ctl(epfd, EPOLL_CTL_MOD, fdVal, (event | EPOLLONESHOT)); + if (err == ENOENT) + err = EPoll.ctl(epfd, EPOLL_CTL_ADD, fdVal, (event | EPOLLONESHOT)); + if (err != 0) + throw new IOException("epoll_ctl failed: " + err); + } + + @Override + void implDeregister(int fdVal, boolean polled) { + // event is disabled if already polled + if (!polled) { + EPoll.ctl(epfd, EPOLL_CTL_DEL, fdVal, 0); + } + } + + @Override + int poll(int timeout) throws IOException { + int n = EPoll.wait(epfd, address, maxEvents, timeout); + int i = 0; + while (i < n) { + long eventAddress = EPoll.getEvent(address, i); + int fdVal = EPoll.getDescriptor(eventAddress); + polled(fdVal); + i++; + } + return n; + } +} + diff --new-file -ur jdk-jdk-22-22/src/java.base/solaris/classes/sun/nio/ch/EPollPort.java jdk-jdk-22-23/src/java.base/solaris/classes/sun/nio/ch/EPollPort.java --- jdk-jdk-22-22/src/java.base/solaris/classes/sun/nio/ch/EPollPort.java 1970-01-01 01:00:00.000000000 +0100 +++ jdk-jdk-22-23/src/java.base/solaris/classes/sun/nio/ch/EPollPort.java 2023-11-09 09:45:51.976499486 +0000 @@ -0,0 +1,320 @@ +/* + * Copyright (c) 2008, 2022, 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 sun.nio.ch; + +import java.nio.channels.spi.AsynchronousChannelProvider; +import java.io.IOException; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.atomic.AtomicInteger; + +import static sun.nio.ch.EPoll.EPOLLIN; +import static sun.nio.ch.EPoll.EPOLLONESHOT; +import static sun.nio.ch.EPoll.EPOLL_CTL_ADD; +import static sun.nio.ch.EPoll.EPOLL_CTL_MOD; + + +/** + * AsynchronousChannelGroup implementation based on the Linux epoll facility. + */ + +final class EPollPort + extends Port +{ + // maximum number of events to poll at a time + private static final int MAX_EPOLL_EVENTS = 512; + + // errors + private static final int ENOENT = 2; + + // epoll file descriptor + private final int epfd; + + // address of the poll array passed to epoll_wait + private final long address; + + // true if epoll closed + private boolean closed; + + // socket pair used for wakeup + private final int sp[]; + + // number of wakeups pending + private final AtomicInteger wakeupCount = new AtomicInteger(); + + // encapsulates an event for a channel + static class Event { + final PollableChannel channel; + final int events; + + Event(PollableChannel channel, int events) { + this.channel = channel; + this.events = events; + } + + PollableChannel channel() { return channel; } + int events() { return events; } + } + + // queue of events for cases that a polling thread dequeues more than one + // event + private final ArrayBlockingQueue queue; + private final Event NEED_TO_POLL = new Event(null, 0); + private final Event EXECUTE_TASK_OR_SHUTDOWN = new Event(null, 0); + + EPollPort(AsynchronousChannelProvider provider, ThreadPool pool) + throws IOException + { + super(provider, pool); + + this.epfd = EPoll.create(); + this.address = EPoll.allocatePollArray(MAX_EPOLL_EVENTS); + + // create socket pair for wakeup mechanism + try { + long fds = IOUtil.makePipe(true); + this.sp = new int[]{(int) (fds >>> 32), (int) fds}; + } catch (IOException ioe) { + EPoll.freePollArray(address); + FileDispatcherImpl.closeIntFD(epfd); + throw ioe; + } + + // register one end with epoll + EPoll.ctl(epfd, EPOLL_CTL_ADD, sp[0], EPOLLIN); + + // create the queue and offer the special event to ensure that the first + // threads polls + this.queue = new ArrayBlockingQueue<>(MAX_EPOLL_EVENTS); + this.queue.offer(NEED_TO_POLL); + } + + EPollPort start() { + startThreads(new EventHandlerTask()); + return this; + } + + /** + * Release all resources + */ + private void implClose() { + synchronized (this) { + if (closed) + return; + closed = true; + } + try { FileDispatcherImpl.closeIntFD(epfd); } catch (IOException ioe) { } + try { FileDispatcherImpl.closeIntFD(sp[0]); } catch (IOException ioe) { } + try { FileDispatcherImpl.closeIntFD(sp[1]); } catch (IOException ioe) { } + EPoll.freePollArray(address); + } + + private void wakeup() { + if (wakeupCount.incrementAndGet() == 1) { + // write byte to socketpair to force wakeup + try { + IOUtil.write1(sp[1], (byte)0); + } catch (IOException x) { + throw new AssertionError(x); + } + } + } + + @Override + void executeOnHandlerTask(Runnable task) { + synchronized (this) { + if (closed) + throw new RejectedExecutionException(); + offerTask(task); + wakeup(); + } + } + + @Override + void shutdownHandlerTasks() { + /* + * If no tasks are running then just release resources; otherwise + * write to the one end of the socketpair to wakeup any polling threads. + */ + int nThreads = threadCount(); + if (nThreads == 0) { + implClose(); + } else { + // send wakeup to each thread + while (nThreads-- > 0) { + wakeup(); + } + } + } + + // invoke by clients to register a file descriptor + @Override + void startPoll(int fd, int events) { + // update events (or add to epoll on first usage) + int err = EPoll.ctl(epfd, EPOLL_CTL_MOD, fd, (events | EPOLLONESHOT)); + if (err == ENOENT) + err = EPoll.ctl(epfd, EPOLL_CTL_ADD, fd, (events | EPOLLONESHOT)); + if (err != 0) + throw new AssertionError(); // should not happen + } + + /** + * Task to process events from epoll and dispatch to the channel's + * onEvent handler. + * + * Events are retrieved from epoll in batch and offered to a BlockingQueue + * where they are consumed by handler threads. A special "NEED_TO_POLL" + * event is used to signal one consumer to re-poll when all events have + * been consumed. + */ + private class EventHandlerTask implements Runnable { + private Event poll() throws IOException { + try { + for (;;) { + int n; + do { + n = EPoll.wait(epfd, address, MAX_EPOLL_EVENTS, -1); + } while (n == IOStatus.INTERRUPTED); + + /** + * 'n' events have been read. Here we map them to their + * corresponding channel in batch and queue n-1 so that + * they can be handled by other handler threads. The last + * event is handled by this thread (and so is not queued). + */ + fdToChannelLock.readLock().lock(); + try { + while (n-- > 0) { + long eventAddress = EPoll.getEvent(address, n); + int fd = EPoll.getDescriptor(eventAddress); + + // wakeup + if (fd == sp[0]) { + if (wakeupCount.decrementAndGet() == 0) { + // consume one wakeup byte, never more as this + // would interfere with shutdown when there is + // a wakeup byte queued to wake each thread + int nread; + do { + nread = IOUtil.drain1(sp[0]); + } while (nread == IOStatus.INTERRUPTED); + } + + // queue special event if there are more events + // to handle. + if (n > 0) { + queue.offer(EXECUTE_TASK_OR_SHUTDOWN); + continue; + } + return EXECUTE_TASK_OR_SHUTDOWN; + } + + PollableChannel channel = fdToChannel.get(fd); + if (channel != null) { + int events = EPoll.getEvents(eventAddress); + Event ev = new Event(channel, events); + + // n-1 events are queued; This thread handles + // the last one except for the wakeup + if (n > 0) { + queue.offer(ev); + } else { + return ev; + } + } + } + } finally { + fdToChannelLock.readLock().unlock(); + } + } + } finally { + // to ensure that some thread will poll when all events have + // been consumed + queue.offer(NEED_TO_POLL); + } + } + + public void run() { + Invoker.GroupAndInvokeCount myGroupAndInvokeCount = + Invoker.getGroupAndInvokeCount(); + final boolean isPooledThread = (myGroupAndInvokeCount != null); + boolean replaceMe = false; + Event ev; + try { + for (;;) { + // reset invoke count + if (isPooledThread) + myGroupAndInvokeCount.resetInvokeCount(); + + try { + replaceMe = false; + ev = queue.take(); + + // no events and this thread has been "selected" to + // poll for more. + if (ev == NEED_TO_POLL) { + try { + ev = poll(); + } catch (IOException x) { + x.printStackTrace(); + return; + } + } + } catch (InterruptedException x) { + continue; + } + + // handle wakeup to execute task or shutdown + if (ev == EXECUTE_TASK_OR_SHUTDOWN) { + Runnable task = pollTask(); + if (task == null) { + // shutdown request + return; + } + // run task (may throw error/exception) + replaceMe = true; + task.run(); + continue; + } + + // process event + try { + ev.channel().onEvent(ev.events(), isPooledThread); + } catch (Error | RuntimeException x) { + replaceMe = true; + throw x; + } + } + } finally { + // last handler to exit when shutdown releases resources + int remaining = threadExit(this, replaceMe); + if (remaining == 0 && isShutdown()) { + implClose(); + } + } + } + } +} diff --new-file -ur jdk-jdk-22-22/src/java.base/solaris/classes/sun/nio/ch/EPollSelectorImpl.java jdk-jdk-22-23/src/java.base/solaris/classes/sun/nio/ch/EPollSelectorImpl.java --- jdk-jdk-22-22/src/java.base/solaris/classes/sun/nio/ch/EPollSelectorImpl.java 1970-01-01 01:00:00.000000000 +0100 +++ jdk-jdk-22-23/src/java.base/solaris/classes/sun/nio/ch/EPollSelectorImpl.java 2023-11-09 09:45:51.976701355 +0000 @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2005, 2022, 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 sun.nio.ch; + +import java.io.IOException; +import java.nio.channels.ClosedSelectorException; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.spi.SelectorProvider; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; +import jdk.internal.misc.Blocker; + +import static sun.nio.ch.EPoll.EPOLLIN; +import static sun.nio.ch.EPoll.EPOLL_CTL_ADD; +import static sun.nio.ch.EPoll.EPOLL_CTL_DEL; +import static sun.nio.ch.EPoll.EPOLL_CTL_MOD; + + +/** + * Linux epoll based Selector implementation + */ + +class EPollSelectorImpl extends SelectorImpl { + + // maximum number of events to poll in one call to epoll_wait + private static final int NUM_EPOLLEVENTS = Math.min(IOUtil.fdLimit(), 1024); + + // epoll file descriptor + private final int epfd; + + // address of poll array when polling with epoll_wait + private final long pollArrayAddress; + + // eventfd object used for interrupt + private final EventFD eventfd; + + // maps file descriptor to selection key, synchronize on selector + private final Map fdToKey = new HashMap<>(); + + // pending new registrations/updates, queued by setEventOps + private final Object updateLock = new Object(); + private final Deque updateKeys = new ArrayDeque<>(); + + // interrupt triggering and clearing + private final Object interruptLock = new Object(); + private boolean interruptTriggered; + + EPollSelectorImpl(SelectorProvider sp) throws IOException { + super(sp); + + this.epfd = EPoll.create(); + this.pollArrayAddress = EPoll.allocatePollArray(NUM_EPOLLEVENTS); + + try { + this.eventfd = new EventFD(); + IOUtil.configureBlocking(IOUtil.newFD(eventfd.efd()), false); + } catch (IOException ioe) { + EPoll.freePollArray(pollArrayAddress); + FileDispatcherImpl.closeIntFD(epfd); + throw ioe; + } + + // register the eventfd object for wakeups + EPoll.ctl(epfd, EPOLL_CTL_ADD, eventfd.efd(), EPOLLIN); + } + + private void ensureOpen() { + if (!isOpen()) + throw new ClosedSelectorException(); + } + + @Override + protected int doSelect(Consumer action, long timeout) + throws IOException + { + assert Thread.holdsLock(this); + + // epoll_wait timeout is int + int to = (int) Math.min(timeout, Integer.MAX_VALUE); + boolean blocking = (to != 0); + boolean timedPoll = (to > 0); + + int numEntries; + processUpdateQueue(); + processDeregisterQueue(); + try { + begin(blocking); + + do { + long startTime = timedPoll ? System.nanoTime() : 0; + boolean attempted = Blocker.begin(blocking); + try { + numEntries = EPoll.wait(epfd, pollArrayAddress, NUM_EPOLLEVENTS, to); + } finally { + Blocker.end(attempted); + } + if (numEntries == IOStatus.INTERRUPTED && timedPoll) { + // timed poll interrupted so need to adjust timeout + long adjust = System.nanoTime() - startTime; + to -= (int) TimeUnit.NANOSECONDS.toMillis(adjust); + if (to <= 0) { + // timeout expired so no retry + numEntries = 0; + } + } + } while (numEntries == IOStatus.INTERRUPTED); + assert IOStatus.check(numEntries); + + } finally { + end(blocking); + } + processDeregisterQueue(); + return processEvents(numEntries, action); + } + + /** + * Process changes to the interest ops. + */ + private void processUpdateQueue() { + assert Thread.holdsLock(this); + + synchronized (updateLock) { + SelectionKeyImpl ski; + while ((ski = updateKeys.pollFirst()) != null) { + if (ski.isValid()) { + int fd = ski.getFDVal(); + // add to fdToKey if needed + SelectionKeyImpl previous = fdToKey.putIfAbsent(fd, ski); + assert (previous == null) || (previous == ski); + + int newEvents = ski.translateInterestOps(); + int registeredEvents = ski.registeredEvents(); + if (newEvents != registeredEvents) { + if (newEvents == 0) { + // remove from epoll + EPoll.ctl(epfd, EPOLL_CTL_DEL, fd, 0); + } else { + if (registeredEvents == 0) { + // add to epoll + EPoll.ctl(epfd, EPOLL_CTL_ADD, fd, newEvents); + } else { + // modify events + EPoll.ctl(epfd, EPOLL_CTL_MOD, fd, newEvents); + } + } + ski.registeredEvents(newEvents); + } + } + } + } + } + + /** + * Process the polled events. + * If the interrupt fd has been selected, drain it and clear the interrupt. + */ + private int processEvents(int numEntries, Consumer action) + throws IOException + { + assert Thread.holdsLock(this); + + boolean interrupted = false; + int numKeysUpdated = 0; + for (int i=0; i + #include + #include + #include + +#include "jni.h" +#include "jni_util.h" +#include "jvm.h" +#include "jlong.h" +#include "nio.h" +#include "nio_util.h" + +#include "sun_nio_ch_EPoll.h" + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_EPoll_eventSize(JNIEnv* env, jclass clazz) +{ + return sizeof(struct epoll_event); +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_EPoll_eventsOffset(JNIEnv* env, jclass clazz) +{ + return offsetof(struct epoll_event, events); +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_EPoll_dataOffset(JNIEnv* env, jclass clazz) +{ + return offsetof(struct epoll_event, data); +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_EPoll_create(JNIEnv *env, jclass clazz) { + int epfd = epoll_create1(EPOLL_CLOEXEC); + if (epfd < 0) { + JNU_ThrowIOExceptionWithLastError(env, "epoll_create1 failed"); + } + return epfd; +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_EPoll_ctl(JNIEnv *env, jclass clazz, jint epfd, + jint opcode, jint fd, jint events) +{ + struct epoll_event event; + int res; + + event.events = events; + event.data.fd = fd; + + res = epoll_ctl(epfd, (int)opcode, (int)fd, &event); + return (res == 0) ? 0 : errno; +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_EPoll_wait(JNIEnv *env, jclass clazz, jint epfd, + jlong address, jint numfds, jint timeout) +{ + struct epoll_event *events = jlong_to_ptr(address); + int res = epoll_wait(epfd, events, numfds, timeout); + if (res < 0) { + if (errno == EINTR) { + return IOS_INTERRUPTED; + } else { + JNU_ThrowIOExceptionWithLastError(env, "epoll_wait failed"); + return IOS_THROWN; + } + } + return res; +} --- /dev/null +++ a/src/java.base/solaris/classes/sun/nio/ch/SolarisEventPortPoller.java @@ -0,0 +1,105 @@ +/* +* Copyright (c) 2008, 2020, 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 sun.nio.ch; + +import java.io.IOException; +import jdk.internal.misc.Unsafe; + +import static sun.nio.ch.SolarisEventPort.OFFSETOF_OBJECT; +import static sun.nio.ch.SolarisEventPort.POLLIN; +import static sun.nio.ch.SolarisEventPort.POLLOUT; +import static sun.nio.ch.SolarisEventPort.PORT_SOURCE_FD; +import static sun.nio.ch.SolarisEventPort.SIZEOF_PORT_EVENT; + +class SolarisEventPortPoller extends Poller { + + private static final Unsafe unsafe = Unsafe.getUnsafe(); + + private static final int MAX_EVENTS = 512; + + // File descriptor to event port. + private final int epid; + private final int event; + + // the poll array (populated by port_getn) + private final long pollArrayAddress; + private final AllocatedNativeObject pollArray; + + SolarisEventPortPoller(boolean subPoller, boolean read) throws IOException { + this.epid = SolarisEventPort.port_create(); + this.event = (read) ? POLLIN : POLLOUT; + + int allocationSize = MAX_EVENTS * SIZEOF_PORT_EVENT; + this.pollArray = new AllocatedNativeObject(allocationSize, false); + this.pollArrayAddress = pollArray.address(); + } + + @Override + int fdVal() { + return epid; + } + + @Override + void implRegister(int fdVal) throws IOException { + boolean result = SolarisEventPort.port_associate(epid, PORT_SOURCE_FD, fdVal, event); + // 'SolarisEventPort.c' will already throw an IOException if the native 'port_associate' method returns + // an error code which is not 'EBADFD'. + if (!result) { + throw new IOException("Event ports 'port_associate' call failed. Error code: " + result); + } + } + + @Override + void implDeregister(int fdVal, boolean polled) { + // event is disabled if already polled + if (!polled) { + try{ + SolarisEventPort.port_dissociate(epid, PORT_SOURCE_FD, fdVal); + } catch (IOException e) { + // Ignore. + } + } + } + + @Override + int poll(int timeout) throws IOException { + int numEvents = SolarisEventPort.port_getn(epid, pollArrayAddress, MAX_EVENTS, timeout); + if (numEvents < 0) { + throw new IOException("Event ports 'port_getn' call failed. Error code: " + numEvents); + } + + int i = 0; + while (i < numEvents) { + long eventAddress = pollArrayAddress + (SIZEOF_PORT_EVENT * i); + // pe->portev_object is file descriptor + int fdVal = (int)unsafe.getAddress(eventAddress + OFFSETOF_OBJECT); + polled(fdVal); + i++; + } + + return numEvents; + } +}