From 181c000be74f72d57f9006ff5a8ea808c5f6947a Mon Sep 17 00:00:00 2001 From: alanb Date: Thu, 2 Apr 2009 19:47:24 +0100 Subject: [PATCH] 6824477: (se) Selector.select fails with IOException: "Invalid argument" if maximum file descriptors is low Reviewed-by: sherman --- .../sun/nio/ch/DevPollArrayWrapper.java | 107 ++++++------------ .../nio/channels/Selector/LotsOfUpdates.java | 38 +++++++ .../nio/channels/Selector/lots_of_updates.sh | 49 ++++++++ 3 files changed, 123 insertions(+), 71 deletions(-) create mode 100644 test/java/nio/channels/Selector/LotsOfUpdates.java create mode 100644 test/java/nio/channels/Selector/lots_of_updates.sh diff --git a/src/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java b/src/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java index f569c2dbe..53693383e 100644 --- a/src/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java +++ b/src/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java @@ -76,20 +76,19 @@ class DevPollArrayWrapper { // Base address of the native pollArray private long pollArrayAddress; + // Array of pollfd structs used for driver updates + private AllocatedNativeObject updatePollArray; + // Maximum number of POLL_FD structs to update at once - private int MAX_UPDATE_SIZE = 10000; + private int MAX_UPDATE_SIZE = Math.min(OPEN_MAX, 10000); DevPollArrayWrapper() { int allocationSize = NUM_POLLFDS * SIZE_POLLFD; pollArray = new AllocatedNativeObject(allocationSize, true); pollArrayAddress = pollArray.address(); + allocationSize = MAX_UPDATE_SIZE * SIZE_POLLFD; + updatePollArray = new AllocatedNativeObject(allocationSize, true); wfd = init(); - - for (int i=0; i 0) { - // Construct a pollfd array with updated masks; we may overallocate - // by some amount because if the events are already POLLREMOVE - // then the second pollfd of that pair will not be needed. The - // number of entries is limited to a reasonable number to avoid - // allocating a lot of memory. - int maxUpdates = Math.min(updateSize * 2, MAX_UPDATE_SIZE); - int allocationSize = maxUpdates * SIZE_POLLFD; - AllocatedNativeObject updatePollArray = - new AllocatedNativeObject(allocationSize, true); - - try { - synchronized (updateList) { - while (updateList.size() > 0) { - // We have to insert a dummy node in between each - // real update to use POLLREMOVE on the fd first because - // otherwise the changes are simply OR'd together - int index = 0; - Updator u = null; - while ((u = updateList.poll()) != null) { - // First add pollfd struct to clear out this fd - putPollFD(updatePollArray, index, u.fd, POLLREMOVE); - index++; - // Now add pollfd to update this fd, if necessary - if (u.mask != POLLREMOVE) { - putPollFD(updatePollArray, index, u.fd, - (short)u.mask); - index++; - } - - // Check against the max allocation size; these are - // all we will process. Valid index ranges from 0 to - // (maxUpdates - 1) and we can use up to 2 per loop - if (index > maxUpdates - 2) - break; - } - // Register the changes with /dev/poll - registerMultiple(wfd, updatePollArray.address(), index); - } + while (updateList.size() > 0) { + // We have to insert a dummy node in between each + // real update to use POLLREMOVE on the fd first because + // otherwise the changes are simply OR'd together + int index = 0; + Updator u = null; + while ((u = updateList.poll()) != null) { + // First add pollfd struct to clear out this fd + putPollFD(updatePollArray, index, u.fd, POLLREMOVE); + index++; + // Now add pollfd to update this fd, if necessary + if (u.mask != POLLREMOVE) { + putPollFD(updatePollArray, index, u.fd, (short)u.mask); + index++; + } + + // Check against the max update size; these are + // all we will process. Valid index ranges from 0 to + // (MAX_UPDATE_SIZE - 1) and we can use up to 2 per loop + if (index > MAX_UPDATE_SIZE - 2) + break; } - } finally { - // Free the native array - updatePollArray.free(); - // BUG: If an exception was thrown then the selector now believes - // that the last set of changes was updated but it probably - // was not. This should not be a likely occurrence. - } + // Register the changes with /dev/poll + registerMultiple(wfd, updatePollArray.address(), index); + } } } @@ -275,7 +239,8 @@ class DevPollArrayWrapper { private native int init(); private native void register(int wfd, int fd, int mask); - private native void registerMultiple(int wfd, long address, int len); + private native void registerMultiple(int wfd, long address, int len) + throws IOException; private native int poll0(long pollAddress, int numfds, long timeout, int wfd); private static native void interrupt(int fd); diff --git a/test/java/nio/channels/Selector/LotsOfUpdates.java b/test/java/nio/channels/Selector/LotsOfUpdates.java new file mode 100644 index 000000000..71018fa8d --- /dev/null +++ b/test/java/nio/channels/Selector/LotsOfUpdates.java @@ -0,0 +1,38 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * 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 + * published by the Free Software Foundation. + * + * 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. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +import java.nio.channels.*; +import java.io.IOException; + +public class LotsOfUpdates { + public static void main(String[] args) throws IOException { + Selector sel = Selector.open(); + SocketChannel sc = SocketChannel.open(); + sc.configureBlocking(false); + SelectionKey key = sc.register(sel, 0); + for (int i=0; i<50000; i++) { + key.interestOps(0); + } + sel.selectNow(); + } +} diff --git a/test/java/nio/channels/Selector/lots_of_updates.sh b/test/java/nio/channels/Selector/lots_of_updates.sh new file mode 100644 index 000000000..5054f18cc --- /dev/null +++ b/test/java/nio/channels/Selector/lots_of_updates.sh @@ -0,0 +1,49 @@ +# +# Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. +# 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 +# published by the Free Software Foundation. +# +# 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. +# +# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, +# CA 95054 USA or visit www.sun.com if you need additional information or +# have any questions. +# + +# @test +# @bug 6824477 +# @summary Selector.select can fail with IOException "Invalid argument" on +# Solaris if maximum number of file descriptors is less than 10000 +# @build LotsOfUpdates +# @run shell lots_of_updates.sh + +OS=`uname -s` +case "$OS" in + Windows_* ) + echo "ulimit not on Windows" + exit 0 + ;; + * ) + CLASSPATH=${TESTCLASSES}:${TESTSRC} + ;; +esac +export CLASSPATH + +# hard limit needs to be less than 10000 for this bug +NOFILES=`ulimit -n -H` +if [ "$NOFILES" = "unlimited" ] || [ $NOFILES -ge 10000 ]; then + ulimit -n 2048 +fi + +${TESTJAVA}/bin/java LotsOfUpdates -- GitLab