4632N/A/*
4632N/A * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
4632N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4632N/A *
4632N/A * This code is free software; you can redistribute it and/or modify it
4632N/A * under the terms of the GNU General Public License version 2 only, as
5020N/A * published by the Free Software Foundation. Oracle designates this
5020N/A * particular file as subject to the "Classpath" exception as provided
5020N/A * by Oracle in the LICENSE file that accompanied this code.
4632N/A *
4632N/A * This code is distributed in the hope that it will be useful, but WITHOUT
4632N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
4632N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
4632N/A * version 2 for more details (a copy is included in the LICENSE file that
4632N/A * accompanied this code).
4632N/A *
4632N/A * You should have received a copy of the GNU General Public License version
4632N/A * 2 along with this work; if not, write to the Free Software Foundation,
4632N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
4632N/A *
4632N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
4632N/A * or visit www.oracle.com if you need additional information or have any
4632N/A * questions.
4632N/A */
4632N/A
4632N/A/*
4632N/A * KQueueArrayWrapper.java
4632N/A * Implementation of Selector using FreeBSD / Mac OS X kqueues
4632N/A * Derived from Sun's DevPollArrayWrapper
4632N/A */
4632N/A
4632N/Apackage sun.nio.ch;
4632N/A
4632N/Aimport sun.misc.*;
4632N/Aimport java.io.IOException;
4632N/Aimport java.io.FileDescriptor;
5318N/Aimport java.util.Iterator;
5318N/Aimport java.util.LinkedList;
4632N/A
4632N/A/*
4632N/A * struct kevent { // 32-bit 64-bit
4632N/A * uintptr_t ident; // 4 8
4632N/A * short filter; // 2 2
4632N/A * u_short flags; // 2 2
4632N/A * u_int fflags; // 4 4
4632N/A * intptr_t data; // 4 8
4632N/A * void *udata; // 4 8
4632N/A * } // Total: 20 32
4632N/A *
4632N/A * The implementation works in 32-bit and 64-bit world. We do this by calling a
4632N/A * native function that actually sets the sizes and offsets of the fields based
4632N/A * on which mode we're in.
4632N/A */
4632N/A
4632N/Aclass KQueueArrayWrapper {
4632N/A // Event masks
4632N/A static final short POLLIN = AbstractPollArrayWrapper.POLLIN;
4632N/A static final short POLLOUT = AbstractPollArrayWrapper.POLLOUT;
4632N/A
4632N/A // kevent filters
4632N/A static short EVFILT_READ;
4632N/A static short EVFILT_WRITE;
4632N/A
4632N/A // kevent struct
4632N/A // These fields are now set by initStructSizes in the static initializer.
4632N/A static short SIZEOF_KEVENT;
4632N/A static short FD_OFFSET;
4632N/A static short FILTER_OFFSET;
4632N/A
5020N/A // kevent array size
5020N/A static final int NUM_KEVENTS = 128;
4632N/A
4632N/A // Are we in a 64-bit VM?
4632N/A static boolean is64bit = false;
4632N/A
4632N/A // The kevent array (used for outcoming events only)
4632N/A private AllocatedNativeObject keventArray = null;
4632N/A private long keventArrayAddress;
4632N/A
4632N/A // The kqueue fd
4632N/A private int kq = -1;
4632N/A
4632N/A // The fd of the interrupt line going out
4632N/A private int outgoingInterruptFD;
4632N/A
4632N/A // The fd of the interrupt line coming in
4632N/A private int incomingInterruptFD;
4632N/A
4632N/A static {
4632N/A initStructSizes();
4632N/A String datamodel = (String) java.security.AccessController.doPrivileged(
4632N/A new sun.security.action.GetPropertyAction("sun.arch.data.model"));
4632N/A is64bit = datamodel.equals("64");
4632N/A }
4632N/A
4632N/A KQueueArrayWrapper() {
4632N/A int allocationSize = SIZEOF_KEVENT * NUM_KEVENTS;
4632N/A keventArray = new AllocatedNativeObject(allocationSize, true);
4632N/A keventArrayAddress = keventArray.address();
4632N/A kq = init();
4632N/A }
4632N/A
5318N/A // Used to update file description registrations
5318N/A private static class Update {
5318N/A SelChImpl channel;
5318N/A int events;
5318N/A Update(SelChImpl channel, int events) {
5318N/A this.channel = channel;
5318N/A this.events = events;
5318N/A }
5318N/A }
5318N/A
5318N/A private LinkedList<Update> updateList = new LinkedList<Update>();
5318N/A
4632N/A void initInterrupt(int fd0, int fd1) {
4632N/A outgoingInterruptFD = fd1;
4632N/A incomingInterruptFD = fd0;
4632N/A register0(kq, fd0, 1, 0);
4632N/A }
4632N/A
4632N/A int getReventOps(int index) {
4632N/A int result = 0;
4632N/A int offset = SIZEOF_KEVENT*index + FILTER_OFFSET;
4632N/A short filter = keventArray.getShort(offset);
4632N/A
4632N/A // This is all that's necessary based on inspection of usage:
4632N/A // SinkChannelImpl, SourceChannelImpl, DatagramChannelImpl,
4632N/A // ServerSocketChannelImpl, SocketChannelImpl
4632N/A if (filter == EVFILT_READ) {
4632N/A result |= POLLIN;
4632N/A } else if (filter == EVFILT_WRITE) {
4632N/A result |= POLLOUT;
4632N/A }
4632N/A
4632N/A return result;
4632N/A }
4632N/A
4632N/A int getDescriptor(int index) {
4632N/A int offset = SIZEOF_KEVENT*index + FD_OFFSET;
4632N/A /* The ident field is 8 bytes in 64-bit world, however the API wants us
4632N/A * to return an int. Hence read the 8 bytes but return as an int.
4632N/A */
4632N/A if (is64bit) {
4632N/A long fd = keventArray.getLong(offset);
4632N/A assert fd <= Integer.MAX_VALUE;
4632N/A return (int) fd;
4632N/A } else {
4632N/A return keventArray.getInt(offset);
4632N/A }
4632N/A }
4632N/A
5318N/A void setInterest(SelChImpl channel, int events) {
5318N/A synchronized (updateList) {
5318N/A // update existing registration
5318N/A updateList.add(new Update(channel, events));
5318N/A }
4632N/A }
4632N/A
5318N/A void release(SelChImpl channel) {
5318N/A synchronized (updateList) {
5318N/A // flush any pending updates
5318N/A for (Iterator<Update> it = updateList.iterator(); it.hasNext();) {
5318N/A if (it.next().channel == channel) {
5318N/A it.remove();
5318N/A }
5318N/A }
5318N/A
5318N/A // remove
5318N/A register0(kq, channel.getFDVal(), 0, 0);
5318N/A }
4632N/A }
4632N/A
5318N/A void updateRegistrations() {
5318N/A synchronized (updateList) {
5318N/A Update u = null;
5318N/A while ((u = updateList.poll()) != null) {
5318N/A SelChImpl ch = u.channel;
5318N/A if (!ch.isOpen())
5318N/A continue;
5318N/A
5318N/A register0(kq, ch.getFDVal(), u.events & POLLIN, u.events & POLLOUT);
5318N/A }
5318N/A }
5318N/A }
5318N/A
5318N/A
4632N/A void close() throws IOException {
4632N/A if (keventArray != null) {
4632N/A keventArray.free();
4632N/A keventArray = null;
4632N/A }
4632N/A if (kq >= 0) {
4632N/A FileDispatcherImpl.closeIntFD(kq);
4632N/A kq = -1;
4632N/A }
4632N/A }
4632N/A
4632N/A int poll(long timeout) {
5318N/A updateRegistrations();
4632N/A int updated = kevent0(kq, keventArrayAddress, NUM_KEVENTS, timeout);
4632N/A return updated;
4632N/A }
4632N/A
4632N/A void interrupt() {
4632N/A interrupt(outgoingInterruptFD);
4632N/A }
4632N/A
4632N/A private native int init();
4632N/A private static native void initStructSizes();
4632N/A
4632N/A private native void register0(int kq, int fd, int read, int write);
4632N/A private native int kevent0(int kq, long keventAddress, int keventCount,
4632N/A long timeout);
4632N/A private static native void interrupt(int fd);
4632N/A}