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