--- a/jdk/src/windows/classes/sun/nio/ch/WindowsSelectorImpl.java Thu Apr 02 19:47:24 2009 +0100
+++ b/jdk/src/windows/classes/sun/nio/ch/WindowsSelectorImpl.java Fri Apr 03 22:10:36 2009 +0100
@@ -34,7 +34,6 @@
import java.nio.channels.ClosedSelectorException;
import java.nio.channels.Pipe;
import java.nio.channels.SelectableChannel;
-import java.nio.channels.SelectionKey;
import java.io.IOException;
import java.util.List;
import java.util.ArrayList;
@@ -72,7 +71,7 @@
private int threadsCount = 0;
// A list of helper threads for select.
- private final List<Thread> threads = new ArrayList<Thread>();
+ private final List<SelectThread> threads = new ArrayList<SelectThread>();
//Pipe used as a wakeup object.
private final Pipe wakeupPipe;
@@ -201,7 +200,7 @@
Thread.currentThread().interrupt();
}
}
- if (thread.index >= threads.size()) { // redundant thread
+ if (thread.isZombie()) { // redundant thread
return true; // will cause run() to exit.
} else {
thread.lastRun = runsCounter; // update lastRun
@@ -388,9 +387,10 @@
// Represents a helper thread used for select.
private final class SelectThread extends Thread {
- private int index; // index of this thread
- SubSelector subSelector;
+ private final int index; // index of this thread
+ final SubSelector subSelector;
private long lastRun = 0; // last run number
+ private volatile boolean zombie;
// Creates a new thread
private SelectThread(int i) {
this.index = i;
@@ -398,6 +398,12 @@
//make sure we wait for next round of poll
this.lastRun = startLock.runsCounter;
}
+ void makeZombie() {
+ zombie = true;
+ }
+ boolean isZombie() {
+ return zombie;
+ }
public void run() {
while (true) { // poll loop
// wait for the start of poll. If this thread has become
@@ -432,7 +438,7 @@
} else if (threadsCount < threads.size()) {
// Some threads become redundant. Remove them from the threads List.
for (int i = threads.size() - 1 ; i >= threadsCount; i--)
- threads.remove(i);
+ threads.remove(i).makeZombie();
}
}
@@ -468,10 +474,9 @@
updateCount++;
int numKeysUpdated = 0;
numKeysUpdated += subSelector.processSelectedKeys(updateCount);
- Iterator it = threads.iterator();
- while (it.hasNext())
- numKeysUpdated += ((SelectThread)it.next()).subSelector.
- processSelectedKeys(updateCount);
+ for (SelectThread t: threads) {
+ numKeysUpdated += t.subSelector.processSelectedKeys(updateCount);
+ }
return numKeysUpdated;
}
@@ -495,13 +500,13 @@
}
pollWrapper.free();
pollWrapper = null;
- selectedKeys = null;
- channelArray = null;
- threads.clear();
- // Call startThreads. All remaining helper threads now exit,
- // since threads.size() = 0;
- startLock.startThreads();
- }
+ selectedKeys = null;
+ channelArray = null;
+ // Make all remaining helper threads exit
+ for (SelectThread t: threads)
+ t.makeZombie();
+ startLock.startThreads();
+ }
}
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/channels/Selector/HelperSlowToDie.java Fri Apr 03 22:10:36 2009 +0100
@@ -0,0 +1,75 @@
+/*
+ * 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 6823609
+ * @summary Selector.select can hangs on Windows for cases where a helper thread
+ * becomes redudant but a new helper is immediately needed.
+ */
+
+import java.nio.channels.*;
+import java.io.IOException;
+
+public class HelperSlowToDie {
+ private static final int CHANNELS_PER_THREAD = 1023;
+ private static volatile boolean done;
+
+ public static void main(String[] args) throws IOException {
+ Selector sel = Selector.open();
+
+ // register channels
+ SocketChannel[] channels = new SocketChannel[CHANNELS_PER_THREAD];
+ for (int i=0; i<CHANNELS_PER_THREAD; i++) {
+ SocketChannel sc = SocketChannel.open();
+ sc.configureBlocking(false);
+ sc.register(sel, SelectionKey.OP_CONNECT);
+ channels[i] = sc;
+ }
+ sel.selectNow();
+
+ // Start threads to swamp all cores but one. This improves the chances
+ // of duplicating the bug.
+ Runnable busy = new Runnable() {
+ public void run() {
+ while (!done) ; // no nothing
+ }
+ };
+ int ncores = Runtime.getRuntime().availableProcessors();
+ for (int i=0; i<ncores-1; i++)
+ new Thread(busy).start();
+
+ // Loop changing the number of channels from 1023 to 1024 and back.
+ for (int i=0; i<1000; i++) {
+ SocketChannel sc = SocketChannel.open();
+ sc.configureBlocking(false);
+ sc.register(sel, SelectionKey.OP_CONNECT);
+ sel.selectNow(); // cause helper to spin up
+ sc.close();
+ sel.selectNow(); // cause helper to retire
+ }
+
+ // terminate busy threads
+ done = true;
+ }
+}