DevPollArrayWrapper.java 10.5 KB
Newer Older
D
duke 已提交
1
/*
2
 * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
D
duke 已提交
3 4 5 6
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
7
 * published by the Free Software Foundation.  Oracle designates this
D
duke 已提交
8
 * particular file as subject to the "Classpath" exception as provided
9
 * by Oracle in the LICENSE file that accompanied this code.
D
duke 已提交
10 11 12 13 14 15 16 17 18 19 20
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
21 22 23
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
D
duke 已提交
24 25 26 27 28
 */

package sun.nio.ch;

import java.io.IOException;
29 30 31
import java.util.BitSet;
import java.util.Map;
import java.util.HashMap;
D
duke 已提交
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69


/**
 * Manipulates a native array of pollfd structs on Solaris:
 *
 * typedef struct pollfd {
 *    int fd;
 *    short events;
 *    short revents;
 * } pollfd_t;
 *
 * @author Mike McCloskey
 * @since 1.4
 */

class DevPollArrayWrapper {

    // Event masks
    static final short POLLIN       = 0x0001;
    static final short POLLPRI      = 0x0002;
    static final short POLLOUT      = 0x0004;
    static final short POLLRDNORM   = 0x0040;
    static final short POLLWRNORM   = POLLOUT;
    static final short POLLRDBAND   = 0x0080;
    static final short POLLWRBAND   = 0x0100;
    static final short POLLNORM     = POLLRDNORM;
    static final short POLLERR      = 0x0008;
    static final short POLLHUP      = 0x0010;
    static final short POLLNVAL     = 0x0020;
    static final short POLLREMOVE   = 0x0800;
    static final short POLLCONN     = POLLOUT;

    // Miscellaneous constants
    static final short SIZE_POLLFD   = 8;
    static final short FD_OFFSET     = 0;
    static final short EVENT_OFFSET  = 4;
    static final short REVENT_OFFSET = 6;

70
    // Special value to indicate that an update should be ignored
71
    static final byte  IGNORE        = (byte)-1;
72

D
duke 已提交
73
    // Maximum number of open file descriptors
74
    static final int   OPEN_MAX      = IOUtil.fdLimit();
D
duke 已提交
75 76

    // Number of pollfd structures to create.
77
    // dpwrite/ioctl(DP_POLL) allows up to OPEN_MAX-1
D
duke 已提交
78 79
    static final int   NUM_POLLFDS   = Math.min(OPEN_MAX-1, 8192);

80 81
    // Initial size of arrays for fd registration changes
    private final int INITIAL_PENDING_UPDATE_SIZE = 64;
D
duke 已提交
82

83 84
    // maximum size of updatesLow
    private final int MAX_UPDATE_ARRAY_SIZE = Math.min(OPEN_MAX, 64*1024);
D
duke 已提交
85 86

    // The pollfd array for results from devpoll driver
87 88 89 90
    private final AllocatedNativeObject pollArray;

    // Base address of the native pollArray
    private final long pollArrayAddress;
D
duke 已提交
91 92

    // The fd of the devpoll driver
93
    private int wfd;
D
duke 已提交
94 95

    // The fd of the interrupt line going out
96
    private int outgoingInterruptFD;
D
duke 已提交
97 98

    // The fd of the interrupt line coming in
99
    private int incomingInterruptFD;
D
duke 已提交
100 101

    // The index of the interrupt FD
102
    private int interruptedIndex;
D
duke 已提交
103 104 105 106

    // Number of updated pollfd entries
    int updated;

107 108 109 110 111 112 113 114 115 116
    // object to synchronize fd registration changes
    private final Object updateLock = new Object();

    // number of file descriptors with registration changes pending
    private int updateCount;

    // file descriptors with registration changes pending
    private int[] updateDescriptors = new int[INITIAL_PENDING_UPDATE_SIZE];

    // events for file descriptors with registration changes pending, indexed
117 118 119 120 121 122 123 124 125
    // by file descriptor and stored as bytes for efficiency reasons. For
    // file descriptors higher than MAX_UPDATE_ARRAY_SIZE (unlimited case at
    // least then the update is stored in a map.
    private final byte[] eventsLow = new byte[MAX_UPDATE_ARRAY_SIZE];
    private Map<Integer,Byte> eventsHigh;

    // Used by release and updateRegistrations to track whether a file
    // descriptor is registered with /dev/poll.
    private final BitSet registered = new BitSet();
126

127 128 129 130 131 132 133 134
    DevPollArrayWrapper() {
        int allocationSize = NUM_POLLFDS * SIZE_POLLFD;
        pollArray = new AllocatedNativeObject(allocationSize, true);
        pollArrayAddress = pollArray.address();
        wfd = init();
        if (OPEN_MAX > MAX_UPDATE_ARRAY_SIZE)
            eventsHigh = new HashMap<>();
    }
135

D
duke 已提交
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
    void initInterrupt(int fd0, int fd1) {
        outgoingInterruptFD = fd1;
        incomingInterruptFD = fd0;
        register(wfd, fd0, POLLIN);
    }

    void putReventOps(int i, int revent) {
        int offset = SIZE_POLLFD * i + REVENT_OFFSET;
        pollArray.putShort(offset, (short)revent);
    }

    int getEventOps(int i) {
        int offset = SIZE_POLLFD * i + EVENT_OFFSET;
        return pollArray.getShort(offset);
    }

    int getReventOps(int i) {
        int offset = SIZE_POLLFD * i + REVENT_OFFSET;
        return pollArray.getShort(offset);
    }

    int getDescriptor(int i) {
        int offset = SIZE_POLLFD * i + FD_OFFSET;
        return pollArray.getInt(offset);
    }

162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
    private void setUpdateEvents(int fd, byte events) {
        if (fd < MAX_UPDATE_ARRAY_SIZE) {
            eventsLow[fd] = events;
        } else {
            eventsHigh.put(Integer.valueOf(fd), Byte.valueOf(events));
        }
    }

    private byte getUpdateEvents(int fd) {
        if (fd < MAX_UPDATE_ARRAY_SIZE) {
            return eventsLow[fd];
        } else {
            Byte result = eventsHigh.get(Integer.valueOf(fd));
            // result should never be null
            return result.byteValue();
        }
    }

D
duke 已提交
180
    void setInterest(int fd, int mask) {
181 182 183 184
        synchronized (updateLock) {
            // record the file descriptor and events, expanding the
            // respective arrays first if necessary.
            int oldCapacity = updateDescriptors.length;
185
            if (updateCount == oldCapacity) {
186 187 188 189 190 191 192 193 194
                int newCapacity = oldCapacity + INITIAL_PENDING_UPDATE_SIZE;
                int[] newDescriptors = new int[newCapacity];
                System.arraycopy(updateDescriptors, 0, newDescriptors, 0, oldCapacity);
                updateDescriptors = newDescriptors;
            }
            updateDescriptors[updateCount++] = fd;

            // events are stored as bytes for efficiency reasons
            byte b = (byte)mask;
195
            assert (b == mask) && (b != IGNORE);
196
            setUpdateEvents(fd, b);
D
duke 已提交
197 198 199 200
        }
    }

    void release(int fd) {
201
        synchronized (updateLock) {
202 203
            // ignore any pending update for this file descriptor
            setUpdateEvents(fd, IGNORE);
204 205

            // remove from /dev/poll
206 207 208 209
            if (registered.get(fd)) {
                register(wfd, fd, POLLREMOVE);
                registered.clear(fd);
            }
D
duke 已提交
210 211 212 213
        }
    }

    void closeDevPollFD() throws IOException {
214
        FileDispatcherImpl.closeIntFD(wfd);
D
duke 已提交
215 216 217
        pollArray.free();
    }

218
    int poll(long timeout) throws IOException {
D
duke 已提交
219 220 221 222 223 224 225 226 227 228 229 230
        updateRegistrations();
        updated = poll0(pollArrayAddress, NUM_POLLFDS, timeout, wfd);
        for (int i=0; i<updated; i++) {
            if (getDescriptor(i) == incomingInterruptFD) {
                interruptedIndex = i;
                interrupted = true;
                break;
            }
        }
        return updated;
    }

231
    void updateRegistrations() throws IOException {
232
        synchronized (updateLock) {
233
            // Populate pollfd array with updated masks
234 235 236 237
            int j = 0;
            int index = 0;
            while (j < updateCount) {
                int fd = updateDescriptors[j];
238
                short events = getUpdateEvents(fd);
239
                boolean wasRegistered = registered.get(fd);
240

241
                // events = 0 => POLLREMOVE or do-nothing
242
                if (events != IGNORE) {
243
                    if (events == 0) {
244
                        if (wasRegistered) {
245 246 247
                            events = POLLREMOVE;
                            registered.clear(fd);
                        } else {
248
                            events = IGNORE;
249 250
                        }
                    } else {
251
                        if (!wasRegistered) {
252 253 254 255
                            registered.set(fd);
                        }
                    }
                }
256

257
                // populate pollfd array with updated event
258 259 260 261 262 263
                if (events != IGNORE) {
                    // insert POLLREMOVE if changing events
                    if (wasRegistered && events != POLLREMOVE) {
                        putPollFD(pollArray, index, fd, POLLREMOVE);
                        index++;
                    }
264
                    putPollFD(pollArray, index, fd, events);
265
                    index++;
266
                    if (index >= (NUM_POLLFDS-1)) {
267
                        registerMultiple(wfd, pollArray.address(), index);
268
                        index = 0;
269
                    }
270 271 272

                    // events for this fd now up to date
                    setUpdateEvents(fd, IGNORE);
D
duke 已提交
273
                }
274 275 276 277 278
                j++;
            }

            // write any remaining updates
            if (index > 0)
279
                registerMultiple(wfd, pollArray.address(), index);
280 281

            updateCount = 0;
D
duke 已提交
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
        }
    }

    private void putPollFD(AllocatedNativeObject array, int index, int fd,
                           short event)
    {
        int structIndex = SIZE_POLLFD * index;
        array.putInt(structIndex + FD_OFFSET, fd);
        array.putShort(structIndex + EVENT_OFFSET, event);
        array.putShort(structIndex + REVENT_OFFSET, (short)0);
    }

    boolean interrupted = false;

    public void interrupt() {
        interrupt(outgoingInterruptFD);
    }

    public int interruptedIndex() {
        return interruptedIndex;
    }

    boolean interrupted() {
        return interrupted;
    }

    void clearInterrupted() {
        interrupted = false;
    }

    private native int init();
    private native void register(int wfd, int fd, int mask);
314 315
    private native void registerMultiple(int wfd, long address, int len)
        throws IOException;
D
duke 已提交
316 317 318
    private native int poll0(long pollAddress, int numfds, long timeout,
                             int wfd);
    private static native void interrupt(int fd);
319 320 321 322

    static {
        IOUtil.load();
    }
D
duke 已提交
323
}