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.KQueue.*; 31 32 /** 33 * Poller implementation based on the kqueue facility. 34 */ 35 class KQueuePoller extends Poller { 36 private final int kqfd; 37 private final int filter; 38 private final int maxEvents; 39 private final long address; 40 41 // file descriptors used for wakeup during shutdown 42 private final int fd0; 43 private final int fd1; 44 45 // close action, and cleaner if this is subpoller 46 private final Runnable closer; 47 private final Cleanable cleaner; 48 49 KQueuePoller(Poller.Mode mode, boolean subPoller, boolean read) throws IOException { 50 int maxEvents = (subPoller) ? 16 : 64; 51 52 int kqfd = KQueue.create(); 53 long address = 0L; 54 int fd0 = -1; 55 int fd1 = -1; 56 try { 57 address = KQueue.allocatePollArray(maxEvents); 58 59 // register one of the pipe with kqueue to allow for wakeup 60 if (subPoller && (mode == Mode.POLLER_PER_CARRIER)) { 61 long fds = IOUtil.makePipe(false); 62 fd0 = (int) (fds >>> 32); 63 fd1 = (int) fds; 64 KQueue.register(kqfd, fd0, EVFILT_READ, EV_ADD); 65 } 66 } catch (Throwable e) { 67 FileDispatcherImpl.closeIntFD(kqfd); 68 if (address != 0L) KQueue.freePollArray(address); 69 if (fd0 >= 0) FileDispatcherImpl.closeIntFD(fd0); 70 if (fd1 >= 0) FileDispatcherImpl.closeIntFD(fd1); 71 throw e; 72 } 73 74 this.kqfd = kqfd; 75 this.filter = (read) ? EVFILT_READ : EVFILT_WRITE; 76 this.maxEvents = maxEvents; 77 this.address = address; 78 this.fd0 = fd0; 79 this.fd1 = fd1; 80 81 // create action to close kqueue, register cleaner if this is a subpoller 82 this.closer = closer(kqfd, address, fd0, fd1); 83 if (subPoller) { 84 this.cleaner = CleanerFactory.cleaner().register(this, closer); 85 } else { 86 this.cleaner = null; 87 } 88 } 89 90 /** 91 * Returns an action to close the kqueue and release other resources. 92 */ 93 private static Runnable closer(int kqfd, long address, int fd0, int fd1) { 94 return () -> { 95 try { 96 FileDispatcherImpl.closeIntFD(kqfd); 97 KQueue.freePollArray(address); 98 if (fd0 >= 0) FileDispatcherImpl.closeIntFD(fd0); 99 if (fd1 >= 0) FileDispatcherImpl.closeIntFD(fd1); 100 } catch (IOException _) { } 101 }; 102 } 103 104 @Override 105 void close() { 106 if (cleaner != null) { 107 cleaner.clean(); 108 } else { 109 closer.run(); 110 } 111 } 112 113 @Override 114 int fdVal() { 115 return kqfd; 116 } 117 118 @Override 119 void implRegister(int fdVal) throws IOException { 120 int err = KQueue.register(kqfd, fdVal, filter, (EV_ADD|EV_ONESHOT)); 121 if (err != 0) 122 throw new IOException("kevent failed: " + err); 123 } 124 125 @Override 126 void implDeregister(int fdVal, boolean polled) { 127 // event was deleted if already polled 128 if (!polled) { 129 KQueue.register(kqfd, fdVal, filter, EV_DELETE); 130 } 131 } 132 133 @Override 134 void wakeupPoller() throws IOException { 135 if (fd1 < 0) { 136 throw new UnsupportedOperationException(); 137 } 138 IOUtil.write1(fd1, (byte)0); 139 } 140 141 @Override 142 int poll(int timeout) throws IOException { 143 int n = KQueue.poll(kqfd, address, maxEvents, timeout); 144 int polled = 0; 145 int i = 0; 146 while (i < n) { 147 long keventAddress = KQueue.getEvent(address, i); 148 int fdVal = KQueue.getDescriptor(keventAddress); 149 if (fdVal != fd0) { 150 polled(fdVal); 151 polled++; 152 } 153 i++; 154 } 155 return polled; 156 } 157 }