提交 4c231751 编写于 作者: S sherman

5025260: Register methods should throw ClosedChannelException instead of NPE

Summary: update the spec and implementation to throw ClosedSelectorException
Reviewed-by: alanb
上级 38db87eb
...@@ -191,6 +191,9 @@ public abstract class SelectableChannel ...@@ -191,6 +191,9 @@ public abstract class SelectableChannel
* @throws ClosedChannelException * @throws ClosedChannelException
* If this channel is closed * If this channel is closed
* *
* @throws ClosedSelectorException
* If the selector is closed
*
* @throws IllegalBlockingModeException * @throws IllegalBlockingModeException
* If this channel is in blocking mode * If this channel is in blocking mode
* *
...@@ -246,6 +249,9 @@ public abstract class SelectableChannel ...@@ -246,6 +249,9 @@ public abstract class SelectableChannel
* @throws ClosedChannelException * @throws ClosedChannelException
* If this channel is closed * If this channel is closed
* *
* @throws ClosedSelectorException
* If the selector is closed
*
* @throws IllegalBlockingModeException * @throws IllegalBlockingModeException
* If this channel is in blocking mode * If this channel is in blocking mode
* *
......
...@@ -175,6 +175,16 @@ public abstract class AbstractSelectableChannel ...@@ -175,6 +175,16 @@ public abstract class AbstractSelectableChannel
* the selector is invoked while holding the appropriate locks. The * the selector is invoked while holding the appropriate locks. The
* resulting key is added to this channel's key set before being returned. * resulting key is added to this channel's key set before being returned.
* </p> * </p>
*
* @throws ClosedSelectorException {@inheritDoc}
*
* @throws IllegalBlockingModeException {@inheritDoc}
*
* @throws IllegalSelectorException {@inheritDoc}
*
* @throws CancelledKeyException {@inheritDoc}
*
* @throws IllegalArgumentException {@inheritDoc}
*/ */
public final SelectionKey register(Selector sel, int ops, public final SelectionKey register(Selector sel, int ops,
Object att) Object att)
......
...@@ -58,6 +58,9 @@ abstract class AbstractPollSelectorImpl ...@@ -58,6 +58,9 @@ abstract class AbstractPollSelectorImpl
// True if this Selector has been closed // True if this Selector has been closed
private boolean closed = false; private boolean closed = false;
// Lock for close and cleanup
private Object closeLock = new Object();
AbstractPollSelectorImpl(SelectorProvider sp, int channels, int offset) { AbstractPollSelectorImpl(SelectorProvider sp, int channels, int offset) {
super(sp); super(sp);
this.totalChannels = channels; this.totalChannels = channels;
...@@ -65,7 +68,11 @@ abstract class AbstractPollSelectorImpl ...@@ -65,7 +68,11 @@ abstract class AbstractPollSelectorImpl
} }
void putEventOps(SelectionKeyImpl sk, int ops) { void putEventOps(SelectionKeyImpl sk, int ops) {
pollWrapper.putEventOps(sk.getIndex(), ops); synchronized (closeLock) {
if (closed)
throw new ClosedSelectorException();
pollWrapper.putEventOps(sk.getIndex(), ops);
}
} }
public Selector wakeup() { public Selector wakeup() {
...@@ -76,7 +83,9 @@ abstract class AbstractPollSelectorImpl ...@@ -76,7 +83,9 @@ abstract class AbstractPollSelectorImpl
protected abstract int doSelect(long timeout) throws IOException; protected abstract int doSelect(long timeout) throws IOException;
protected void implClose() throws IOException { protected void implClose() throws IOException {
if (!closed) { synchronized (closeLock) {
if (closed)
return;
closed = true; closed = true;
// Deregister channels // Deregister channels
for(int i=channelOffset; i<totalChannels; i++) { for(int i=channelOffset; i<totalChannels; i++) {
...@@ -129,23 +138,28 @@ abstract class AbstractPollSelectorImpl ...@@ -129,23 +138,28 @@ abstract class AbstractPollSelectorImpl
} }
protected void implRegister(SelectionKeyImpl ski) { protected void implRegister(SelectionKeyImpl ski) {
// Check to see if the array is large enough synchronized (closeLock) {
if (channelArray.length == totalChannels) { if (closed)
// Make a larger array throw new ClosedSelectorException();
int newSize = pollWrapper.totalChannels * 2;
SelectionKeyImpl temp[] = new SelectionKeyImpl[newSize]; // Check to see if the array is large enough
// Copy over if (channelArray.length == totalChannels) {
for (int i=channelOffset; i<totalChannels; i++) // Make a larger array
temp[i] = channelArray[i]; int newSize = pollWrapper.totalChannels * 2;
channelArray = temp; SelectionKeyImpl temp[] = new SelectionKeyImpl[newSize];
// Grow the NativeObject poll array // Copy over
pollWrapper.grow(newSize); for (int i=channelOffset; i<totalChannels; i++)
temp[i] = channelArray[i];
channelArray = temp;
// Grow the NativeObject poll array
pollWrapper.grow(newSize);
}
channelArray[totalChannels] = ski;
ski.setIndex(totalChannels);
pollWrapper.addEntry(ski.channel);
totalChannels++;
keys.add(ski);
} }
channelArray[totalChannels] = ski;
ski.setIndex(totalChannels);
pollWrapper.addEntry(ski.channel);
totalChannels++;
keys.add(ski);
} }
protected void implDereg(SelectionKeyImpl ski) throws IOException { protected void implDereg(SelectionKeyImpl ski) throws IOException {
......
...@@ -46,15 +46,15 @@ class DevPollSelectorImpl ...@@ -46,15 +46,15 @@ class DevPollSelectorImpl
// The poll object // The poll object
DevPollArrayWrapper pollWrapper; DevPollArrayWrapper pollWrapper;
// The number of valid channels in this Selector's poll array
private int totalChannels;
// Maps from file descriptors to keys // Maps from file descriptors to keys
private Map<Integer,SelectionKeyImpl> fdToKey; private Map<Integer,SelectionKeyImpl> fdToKey;
// True if this Selector has been closed // True if this Selector has been closed
private boolean closed = false; private boolean closed = false;
// Lock for close/cleanup
private Object closeLock = new Object();
// Lock for interrupt triggering and clearing // Lock for interrupt triggering and clearing
private Object interruptLock = new Object(); private Object interruptLock = new Object();
private boolean interruptTriggered = false; private boolean interruptTriggered = false;
...@@ -72,7 +72,6 @@ class DevPollSelectorImpl ...@@ -72,7 +72,6 @@ class DevPollSelectorImpl
pollWrapper = new DevPollArrayWrapper(); pollWrapper = new DevPollArrayWrapper();
pollWrapper.initInterrupt(fd0, fd1); pollWrapper.initInterrupt(fd0, fd1);
fdToKey = new HashMap<Integer,SelectionKeyImpl>(); fdToKey = new HashMap<Integer,SelectionKeyImpl>();
totalChannels = 1;
} }
protected int doSelect(long timeout) protected int doSelect(long timeout)
...@@ -131,45 +130,39 @@ class DevPollSelectorImpl ...@@ -131,45 +130,39 @@ class DevPollSelectorImpl
} }
protected void implClose() throws IOException { protected void implClose() throws IOException {
if (!closed) { if (closed)
closed = true; return;
closed = true;
// prevent further wakeup
synchronized (interruptLock) {
interruptTriggered = true;
}
FileDispatcher.closeIntFD(fd0); // prevent further wakeup
FileDispatcher.closeIntFD(fd1); synchronized (interruptLock) {
if (pollWrapper != null) { interruptTriggered = true;
}
pollWrapper.release(fd0);
pollWrapper.closeDevPollFD();
pollWrapper = null;
selectedKeys = null;
// Deregister channels
Iterator i = keys.iterator();
while (i.hasNext()) {
SelectionKeyImpl ski = (SelectionKeyImpl)i.next();
deregister(ski);
SelectableChannel selch = ski.channel();
if (!selch.isOpen() && !selch.isRegistered())
((SelChImpl)selch).kill();
i.remove();
}
totalChannels = 0;
} FileDispatcher.closeIntFD(fd0);
fd0 = -1; FileDispatcher.closeIntFD(fd1);
fd1 = -1;
pollWrapper.release(fd0);
pollWrapper.closeDevPollFD();
selectedKeys = null;
// Deregister channels
Iterator i = keys.iterator();
while (i.hasNext()) {
SelectionKeyImpl ski = (SelectionKeyImpl)i.next();
deregister(ski);
SelectableChannel selch = ski.channel();
if (!selch.isOpen() && !selch.isRegistered())
((SelChImpl)selch).kill();
i.remove();
} }
fd0 = -1;
fd1 = -1;
} }
protected void implRegister(SelectionKeyImpl ski) { protected void implRegister(SelectionKeyImpl ski) {
int fd = IOUtil.fdVal(ski.channel.getFD()); int fd = IOUtil.fdVal(ski.channel.getFD());
fdToKey.put(Integer.valueOf(fd), ski); fdToKey.put(Integer.valueOf(fd), ski);
totalChannels++;
keys.add(ski); keys.add(ski);
} }
...@@ -179,7 +172,6 @@ class DevPollSelectorImpl ...@@ -179,7 +172,6 @@ class DevPollSelectorImpl
int fd = ski.channel.getFDVal(); int fd = ski.channel.getFDVal();
fdToKey.remove(Integer.valueOf(fd)); fdToKey.remove(Integer.valueOf(fd));
pollWrapper.release(fd); pollWrapper.release(fd);
totalChannels--;
ski.setIndex(-1); ski.setIndex(-1);
keys.remove(ski); keys.remove(ski);
selectedKeys.remove(ski); selectedKeys.remove(ski);
...@@ -190,6 +182,8 @@ class DevPollSelectorImpl ...@@ -190,6 +182,8 @@ class DevPollSelectorImpl
} }
void putEventOps(SelectionKeyImpl sk, int ops) { void putEventOps(SelectionKeyImpl sk, int ops) {
if (closed)
throw new ClosedSelectorException();
int fd = IOUtil.fdVal(sk.channel.getFD()); int fd = IOUtil.fdVal(sk.channel.getFD());
pollWrapper.setInterest(fd, ops); pollWrapper.setInterest(fd, ops);
} }
......
/* /*
* Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2005-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -31,7 +31,6 @@ import java.nio.channels.spi.*; ...@@ -31,7 +31,6 @@ import java.nio.channels.spi.*;
import java.util.*; import java.util.*;
import sun.misc.*; import sun.misc.*;
/** /**
* An implementation of Selector for Linux 2.6+ kernels that uses * An implementation of Selector for Linux 2.6+ kernels that uses
* the epoll event notification facility. * the epoll event notification facility.
...@@ -51,7 +50,7 @@ class EPollSelectorImpl ...@@ -51,7 +50,7 @@ class EPollSelectorImpl
private Map<Integer,SelectionKeyImpl> fdToKey; private Map<Integer,SelectionKeyImpl> fdToKey;
// True if this Selector has been closed // True if this Selector has been closed
private boolean closed = false; private volatile boolean closed = false;
// Lock for interrupt triggering and clearing // Lock for interrupt triggering and clearing
private Object interruptLock = new Object(); private Object interruptLock = new Object();
...@@ -128,40 +127,41 @@ class EPollSelectorImpl ...@@ -128,40 +127,41 @@ class EPollSelectorImpl
} }
protected void implClose() throws IOException { protected void implClose() throws IOException {
if (!closed) { if (closed)
closed = true; return;
closed = true;
// prevent further wakeup // prevent further wakeup
synchronized (interruptLock) { synchronized (interruptLock) {
interruptTriggered = true; interruptTriggered = true;
} }
FileDispatcher.closeIntFD(fd0); FileDispatcher.closeIntFD(fd0);
FileDispatcher.closeIntFD(fd1); FileDispatcher.closeIntFD(fd1);
if (pollWrapper != null) {
pollWrapper.release(fd0);
pollWrapper.release(fd0); pollWrapper.closeEPollFD();
pollWrapper.closeEPollFD(); // it is possible
pollWrapper = null; selectedKeys = null;
selectedKeys = null;
// Deregister channels
// Deregister channels Iterator i = keys.iterator();
Iterator i = keys.iterator(); while (i.hasNext()) {
while (i.hasNext()) { SelectionKeyImpl ski = (SelectionKeyImpl)i.next();
SelectionKeyImpl ski = (SelectionKeyImpl)i.next(); deregister(ski);
deregister(ski); SelectableChannel selch = ski.channel();
SelectableChannel selch = ski.channel(); if (!selch.isOpen() && !selch.isRegistered())
if (!selch.isOpen() && !selch.isRegistered()) ((SelChImpl)selch).kill();
((SelChImpl)selch).kill(); i.remove();
i.remove();
}
}
fd0 = -1;
fd1 = -1;
} }
fd0 = -1;
fd1 = -1;
} }
protected void implRegister(SelectionKeyImpl ski) { protected void implRegister(SelectionKeyImpl ski) {
if (closed)
throw new ClosedSelectorException();
int fd = IOUtil.fdVal(ski.channel.getFD()); int fd = IOUtil.fdVal(ski.channel.getFD());
fdToKey.put(Integer.valueOf(fd), ski); fdToKey.put(Integer.valueOf(fd), ski);
pollWrapper.add(fd); pollWrapper.add(fd);
...@@ -183,6 +183,8 @@ class EPollSelectorImpl ...@@ -183,6 +183,8 @@ class EPollSelectorImpl
} }
void putEventOps(SelectionKeyImpl sk, int ops) { void putEventOps(SelectionKeyImpl sk, int ops) {
if (closed)
throw new ClosedSelectorException();
int fd = IOUtil.fdVal(sk.channel.getFD()); int fd = IOUtil.fdVal(sk.channel.getFD());
pollWrapper.setInterest(fd, ops); pollWrapper.setInterest(fd, ops);
} }
......
/* /*
* Copyright 2002-2008 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -80,6 +80,9 @@ final class WindowsSelectorImpl extends SelectorImpl { ...@@ -80,6 +80,9 @@ final class WindowsSelectorImpl extends SelectorImpl {
// File descriptors corresponding to source and sink // File descriptors corresponding to source and sink
private final int wakeupSourceFd, wakeupSinkFd; private final int wakeupSourceFd, wakeupSinkFd;
// Lock for close cleanup
private Object closeLock = new Object();
// Maps file descriptors to their indices in pollArray // Maps file descriptors to their indices in pollArray
private final static class FdMap extends HashMap<Integer, MapEntry> { private final static class FdMap extends HashMap<Integer, MapEntry> {
static final long serialVersionUID = 0L; static final long serialVersionUID = 0L;
...@@ -473,42 +476,48 @@ final class WindowsSelectorImpl extends SelectorImpl { ...@@ -473,42 +476,48 @@ final class WindowsSelectorImpl extends SelectorImpl {
} }
protected void implClose() throws IOException { protected void implClose() throws IOException {
if (channelArray != null) { synchronized (closeLock) {
if (pollWrapper != null) { if (channelArray != null) {
// prevent further wakeup if (pollWrapper != null) {
synchronized (interruptLock) { // prevent further wakeup
interruptTriggered = true; synchronized (interruptLock) {
} interruptTriggered = true;
wakeupPipe.sink().close();
wakeupPipe.source().close();
for(int i = 1; i < totalChannels; i++) { // Deregister channels
if (i % MAX_SELECTABLE_FDS != 0) { // skip wakeupEvent
deregister(channelArray[i]);
SelectableChannel selch = channelArray[i].channel();
if (!selch.isOpen() && !selch.isRegistered())
((SelChImpl)selch).kill();
} }
} wakeupPipe.sink().close();
pollWrapper.free(); wakeupPipe.source().close();
pollWrapper = null; for(int i = 1; i < totalChannels; i++) { // Deregister channels
selectedKeys = null; if (i % MAX_SELECTABLE_FDS != 0) { // skip wakeupEvent
channelArray = null; deregister(channelArray[i]);
threads.clear(); SelectableChannel selch = channelArray[i].channel();
// Call startThreads. All remaining helper threads now exit, if (!selch.isOpen() && !selch.isRegistered())
// since threads.size() = 0; ((SelChImpl)selch).kill();
startLock.startThreads(); }
}
pollWrapper.free();
pollWrapper = null;
selectedKeys = null;
channelArray = null;
threads.clear();
// Call startThreads. All remaining helper threads now exit,
// since threads.size() = 0;
startLock.startThreads();
}
} }
} }
} }
protected void implRegister(SelectionKeyImpl ski) { protected void implRegister(SelectionKeyImpl ski) {
growIfNeeded(); synchronized (closeLock) {
channelArray[totalChannels] = ski; if (pollWrapper == null)
ski.setIndex(totalChannels); throw new ClosedSelectorException();
fdMap.put(ski); growIfNeeded();
keys.add(ski); channelArray[totalChannels] = ski;
pollWrapper.addEntry(totalChannels, ski); ski.setIndex(totalChannels);
totalChannels++; fdMap.put(ski);
keys.add(ski);
pollWrapper.addEntry(totalChannels, ski);
totalChannels++;
}
} }
private void growIfNeeded() { private void growIfNeeded() {
...@@ -554,7 +563,11 @@ final class WindowsSelectorImpl extends SelectorImpl { ...@@ -554,7 +563,11 @@ final class WindowsSelectorImpl extends SelectorImpl {
} }
void putEventOps(SelectionKeyImpl sk, int ops) { void putEventOps(SelectionKeyImpl sk, int ops) {
pollWrapper.putEventOps(sk.getIndex(), ops); synchronized (closeLock) {
if (pollWrapper == null)
throw new ClosedSelectorException();
pollWrapper.putEventOps(sk.getIndex(), ops);
}
} }
public Selector wakeup() { public Selector wakeup() {
......
/*
* Copyright 2008 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 5025260
* @summary ClosedSelectorException is expected when register after close
*/
import java.net.*;
import java.nio.channels.*;
public class CloseThenRegister {
public static void main (String [] args) throws Exception {
try {
Selector s = Selector.open();
s.close();
ServerSocketChannel c = ServerSocketChannel.open();
c.socket().bind(new InetSocketAddress(40000));
c.configureBlocking(false);
c.register(s, SelectionKey.OP_ACCEPT);
} catch (ClosedSelectorException cse) {
return;
}
throw new RuntimeException("register after close does not cause CSE!");
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册