6823609: (se) Selector.select hangs on Windows under load

Reviewed-by: sherman
This commit is contained in:
Alan Bateman 2009-04-03 22:10:36 +01:00
parent 78e9762656
commit 9676f044cb
2 changed files with 97 additions and 17 deletions

View File

@ -34,7 +34,6 @@ import java.nio.channels.Selector;
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 @@ final class WindowsSelectorImpl extends SelectorImpl {
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 @@ final class WindowsSelectorImpl extends SelectorImpl {
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 @@ final class WindowsSelectorImpl extends SelectorImpl {
// 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 @@ final class WindowsSelectorImpl extends SelectorImpl {
//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 @@ final class WindowsSelectorImpl extends SelectorImpl {
} 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 @@ final class WindowsSelectorImpl extends SelectorImpl {
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 @@ final class WindowsSelectorImpl extends SelectorImpl {
}
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();
}
}
}
}

View File

@ -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;
}
}