1 /* 2 * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package sun.nio.ch; 26 27 import java.io.IOException; 28 import java.lang.ref.Cleaner.Cleanable; 29 import jdk.internal.ref.CleanerFactory; 30 import static sun.nio.ch.EPoll.*; 31 32 /** 33 * Poller implementation based on the epoll facility. 34 */ 35 36 class EPollPoller extends Poller { 37 private static final int ENOENT = 2; 38 39 private final int epfd; 40 private final int event; 41 private final int maxEvents; 42 private final long address; 43 private final EventFD eventfd; // wakeup event, used for shutdown 44 45 // close action, and cleaner if this is subpoller 46 private final Runnable closer; 47 private final Cleanable cleaner; 48 49 EPollPoller(Poller.Mode mode, boolean subPoller, boolean read) throws IOException { 50 int maxEvents = (subPoller) ? 16 : 64; 51 52 int epfd = EPoll.create(); 53 long address = 0L; 54 EventFD eventfd = null; 55 try { 56 address = EPoll.allocatePollArray(maxEvents); 57 58 // register event with epoll to allow for wakeup 59 if (subPoller && (mode == Poller.Mode.POLLER_PER_CARRIER)) { 60 eventfd = new EventFD(); 61 IOUtil.configureBlocking(eventfd.efd(), false); 62 EPoll.ctl(epfd, EPOLL_CTL_ADD, eventfd.efd(), EPOLLIN); 63 } 64 } catch (Throwable e) { 65 FileDispatcherImpl.closeIntFD(epfd); 66 if (address != 0L) EPoll.freePollArray(address); 67 if (eventfd != null) eventfd.close(); 68 throw e; 69 } 70 71 this.epfd = epfd; 72 this.event = (read) ? EPOLLIN : EPOLLOUT; 73 this.maxEvents = maxEvents; 74 this.address = address; 75 this.eventfd = eventfd; 76 77 // create action to close epoll instance, register cleaner if this is a subpoller 78 this.closer = closer(epfd, address, eventfd); 79 if (subPoller) { 80 this.cleaner = CleanerFactory.cleaner().register(this, closer); 81 } else { 82 this.cleaner = null; 83 } 84 } 85 86 /** 87 * Returns an action to close the epoll instance and release other resources. 88 */ 89 private static Runnable closer(int epfd, long address, EventFD eventfd) { 90 return () -> { 91 try { 92 FileDispatcherImpl.closeIntFD(epfd); 93 EPoll.freePollArray(address); 94 if (eventfd != null) eventfd.close(); 95 } catch (IOException _) { } 96 }; 97 } 98 99 @Override 100 void close() { 101 if (cleaner != null) { 102 cleaner.clean(); 103 } else { 104 closer.run(); 105 } 106 } 107 108 @Override 109 int fdVal() { 110 return epfd; 111 } 112 113 @Override 114 void implRegister(int fdVal) throws IOException { 115 // re-enable if already registered but disabled (previously polled) 116 int err = EPoll.ctl(epfd, EPOLL_CTL_MOD, fdVal, (event | EPOLLONESHOT)); 117 if (err == ENOENT) 118 err = EPoll.ctl(epfd, EPOLL_CTL_ADD, fdVal, (event | EPOLLONESHOT)); 119 if (err != 0) 120 throw new IOException("epoll_ctl failed: " + err); 121 } 122 123 @Override 124 void implDeregister(int fdVal, boolean polled) { 125 // event is disabled if already polled 126 if (!polled) { 127 EPoll.ctl(epfd, EPOLL_CTL_DEL, fdVal, 0); 128 } 129 } 130 131 @Override 132 void wakeupPoller() throws IOException { 133 if (eventfd == null) { 134 throw new UnsupportedOperationException(); 135 } 136 eventfd.set(); 137 } 138 139 @Override 140 int poll(int timeout) throws IOException { 141 int n = EPoll.wait(epfd, address, maxEvents, timeout); 142 int polled = 0; 143 int i = 0; 144 while (i < n) { 145 long eventAddress = EPoll.getEvent(address, i); 146 int fd = EPoll.getDescriptor(eventAddress); 147 if (eventfd == null || fd != eventfd.efd()) { 148 polled(fd); 149 polled++; 150 } 151 i++; 152 } 153 return polled; 154 } 155 } 156