6823609: (se) Selector.select hangs on Windows under load
Reviewed-by: sherman
This commit is contained in:
parent
78e9762656
commit
9676f044cb
@ -34,7 +34,6 @@ import java.nio.channels.Selector;
|
|||||||
import java.nio.channels.ClosedSelectorException;
|
import java.nio.channels.ClosedSelectorException;
|
||||||
import java.nio.channels.Pipe;
|
import java.nio.channels.Pipe;
|
||||||
import java.nio.channels.SelectableChannel;
|
import java.nio.channels.SelectableChannel;
|
||||||
import java.nio.channels.SelectionKey;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -72,7 +71,7 @@ final class WindowsSelectorImpl extends SelectorImpl {
|
|||||||
private int threadsCount = 0;
|
private int threadsCount = 0;
|
||||||
|
|
||||||
// A list of helper threads for select.
|
// 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.
|
//Pipe used as a wakeup object.
|
||||||
private final Pipe wakeupPipe;
|
private final Pipe wakeupPipe;
|
||||||
@ -201,7 +200,7 @@ final class WindowsSelectorImpl extends SelectorImpl {
|
|||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (thread.index >= threads.size()) { // redundant thread
|
if (thread.isZombie()) { // redundant thread
|
||||||
return true; // will cause run() to exit.
|
return true; // will cause run() to exit.
|
||||||
} else {
|
} else {
|
||||||
thread.lastRun = runsCounter; // update lastRun
|
thread.lastRun = runsCounter; // update lastRun
|
||||||
@ -388,9 +387,10 @@ final class WindowsSelectorImpl extends SelectorImpl {
|
|||||||
|
|
||||||
// Represents a helper thread used for select.
|
// Represents a helper thread used for select.
|
||||||
private final class SelectThread extends Thread {
|
private final class SelectThread extends Thread {
|
||||||
private int index; // index of this thread
|
private final int index; // index of this thread
|
||||||
SubSelector subSelector;
|
final SubSelector subSelector;
|
||||||
private long lastRun = 0; // last run number
|
private long lastRun = 0; // last run number
|
||||||
|
private volatile boolean zombie;
|
||||||
// Creates a new thread
|
// Creates a new thread
|
||||||
private SelectThread(int i) {
|
private SelectThread(int i) {
|
||||||
this.index = i;
|
this.index = i;
|
||||||
@ -398,6 +398,12 @@ final class WindowsSelectorImpl extends SelectorImpl {
|
|||||||
//make sure we wait for next round of poll
|
//make sure we wait for next round of poll
|
||||||
this.lastRun = startLock.runsCounter;
|
this.lastRun = startLock.runsCounter;
|
||||||
}
|
}
|
||||||
|
void makeZombie() {
|
||||||
|
zombie = true;
|
||||||
|
}
|
||||||
|
boolean isZombie() {
|
||||||
|
return zombie;
|
||||||
|
}
|
||||||
public void run() {
|
public void run() {
|
||||||
while (true) { // poll loop
|
while (true) { // poll loop
|
||||||
// wait for the start of poll. If this thread has become
|
// 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()) {
|
} else if (threadsCount < threads.size()) {
|
||||||
// Some threads become redundant. Remove them from the threads List.
|
// Some threads become redundant. Remove them from the threads List.
|
||||||
for (int i = threads.size() - 1 ; i >= threadsCount; i--)
|
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++;
|
updateCount++;
|
||||||
int numKeysUpdated = 0;
|
int numKeysUpdated = 0;
|
||||||
numKeysUpdated += subSelector.processSelectedKeys(updateCount);
|
numKeysUpdated += subSelector.processSelectedKeys(updateCount);
|
||||||
Iterator it = threads.iterator();
|
for (SelectThread t: threads) {
|
||||||
while (it.hasNext())
|
numKeysUpdated += t.subSelector.processSelectedKeys(updateCount);
|
||||||
numKeysUpdated += ((SelectThread)it.next()).subSelector.
|
}
|
||||||
processSelectedKeys(updateCount);
|
|
||||||
return numKeysUpdated;
|
return numKeysUpdated;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -495,13 +500,13 @@ final class WindowsSelectorImpl extends SelectorImpl {
|
|||||||
}
|
}
|
||||||
pollWrapper.free();
|
pollWrapper.free();
|
||||||
pollWrapper = null;
|
pollWrapper = null;
|
||||||
selectedKeys = null;
|
selectedKeys = null;
|
||||||
channelArray = null;
|
channelArray = null;
|
||||||
threads.clear();
|
// Make all remaining helper threads exit
|
||||||
// Call startThreads. All remaining helper threads now exit,
|
for (SelectThread t: threads)
|
||||||
// since threads.size() = 0;
|
t.makeZombie();
|
||||||
startLock.startThreads();
|
startLock.startThreads();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
75
jdk/test/java/nio/channels/Selector/HelperSlowToDie.java
Normal file
75
jdk/test/java/nio/channels/Selector/HelperSlowToDie.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user