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(boolean subPoller, boolean read) throws IOException { 50 int maxEvents = (subPoller) ? 16 : 64; 51 52 int epfd = -1; 53 long address = 0L; 54 EventFD eventfd = null; 55 try { 56 epfd = EPoll.create(); 57 address = EPoll.allocatePollArray(maxEvents); 58 59 // register event with epoll to allow for wakeup 60 eventfd = new EventFD(); 61 IOUtil.configureBlocking(eventfd.efd(), false); 62 EPoll.ctl(epfd, EPOLL_CTL_ADD, eventfd.efd(), EPOLLIN); 63 } catch (Throwable e) { 64 if (epfd >= 0) FileDispatcherImpl.closeIntFD(epfd); 65 if (address != 0L) EPoll.freePollArray(address); 66 if (eventfd != null) eventfd.close(); 67 throw e; 68 } 69 70 this.epfd = epfd; 71 this.event = (read) ? EPOLLIN : EPOLLOUT; 72 this.maxEvents = maxEvents; 73 this.address = address; 74 this.eventfd = eventfd; 75 76 // create action to close epoll instance, register cleaner if this is a subpoller 77 this.closer = closer(epfd, address, eventfd); 78 if (subPoller) { 79 this.cleaner = CleanerFactory.cleaner().register(this, closer); 80 } else { 81 this.cleaner = null; 82 } 83 } 84 85 /** 86 * Returns an action to close the epoll instance and release other resources. 87 */ 88 private static Runnable closer(int epfd, long address, EventFD eventfd) { 89 return () -> { 90 try { 91 FileDispatcherImpl.closeIntFD(epfd); 92 EPoll.freePollArray(address); 93 eventfd.close(); 94 } catch (IOException _) { } 95 }; 96 } 97 98 @Override 99 void close() { 100 if (cleaner != null) { 101 cleaner.clean(); 102 } else { 103 closer.run(); 104 } 105 } 106 107 @Override 108 int fdVal() { 109 return epfd; 110 } 111 112 @Override 113 void implRegister(int fdVal) throws IOException { 114 // re-enable if already registered but disabled (previously polled) 115 int err = EPoll.ctl(epfd, EPOLL_CTL_MOD, fdVal, (event | EPOLLONESHOT)); 116 if (err == ENOENT) 117 err = EPoll.ctl(epfd, EPOLL_CTL_ADD, fdVal, (event | EPOLLONESHOT)); 118 if (err != 0) 119 throw new IOException("epoll_ctl failed: " + err); 120 } 121 122 @Override 123 void implDeregister(int fdVal, boolean polled) { 124 // event is disabled if already polled 125 if (!polled) { 126 EPoll.ctl(epfd, EPOLL_CTL_DEL, fdVal, 0); 127 } 128 } 129 130 @Override 131 void wakeupPoller() throws IOException { 132 eventfd.set(); 133 } 134 135 @Override 136 int poll(int timeout) throws IOException { 137 int n = EPoll.wait(epfd, address, maxEvents, timeout); 138 int polled = 0; 139 int i = 0; 140 while (i < n) { 141 long eventAddress = EPoll.getEvent(address, i); 142 int fd = EPoll.getDescriptor(eventAddress); 143 if (fd != eventfd.efd()) { 144 polled(fd); 145 polled++; 146 } 147 i++; 148 } 149 return polled; 150 } 151 } 152