8236246: SelectorProvider support for creating a DatagramChannel that is not interruptible
Reviewed-by: chegar
This commit is contained in:
parent
d1ad0eaf8f
commit
c6a4cea7a0
src/java.base
aix/classes/sun/nio/ch
linux/classes/sun/nio/ch
macosx/classes/sun/nio/ch
share/classes
java/nio/channels/spi
sun/nio/ch
solaris/classes/sun/nio/ch
windows/classes/sun/nio/ch
test/jdk/java
nio/channels/DatagramChannel
rmi
activation/rmidViaInheritedChannel
testlibrary
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. 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
|
||||
@ -25,13 +25,19 @@
|
||||
|
||||
package sun.nio.ch;
|
||||
|
||||
import java.nio.channels.spi.SelectorProvider;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
/**
|
||||
* Creates this platform's default SelectorProvider
|
||||
*/
|
||||
|
||||
public class DefaultSelectorProvider {
|
||||
private static final SelectorProviderImpl INSTANCE;
|
||||
static {
|
||||
PrivilegedAction<SelectorProviderImpl> pa = PollSelectorProvider::new;
|
||||
INSTANCE = AccessController.doPrivileged(pa);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent instantiation.
|
||||
@ -39,9 +45,9 @@ public class DefaultSelectorProvider {
|
||||
private DefaultSelectorProvider() { }
|
||||
|
||||
/**
|
||||
* Returns the default SelectorProvider.
|
||||
* Returns the default SelectorProvider implementation.
|
||||
*/
|
||||
public static SelectorProvider create() {
|
||||
return new PollSelectorProvider();
|
||||
public static SelectorProviderImpl get() {
|
||||
return INSTANCE;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. 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
|
||||
@ -25,13 +25,19 @@
|
||||
|
||||
package sun.nio.ch;
|
||||
|
||||
import java.nio.channels.spi.SelectorProvider;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
/**
|
||||
* Creates this platform's default SelectorProvider
|
||||
*/
|
||||
|
||||
public class DefaultSelectorProvider {
|
||||
private static final SelectorProviderImpl INSTANCE;
|
||||
static {
|
||||
PrivilegedAction<SelectorProviderImpl> pa = EPollSelectorProvider::new;
|
||||
INSTANCE = AccessController.doPrivileged(pa);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent instantiation.
|
||||
@ -39,9 +45,9 @@ public class DefaultSelectorProvider {
|
||||
private DefaultSelectorProvider() { }
|
||||
|
||||
/**
|
||||
* Returns the default SelectorProvider.
|
||||
* Returns the default SelectorProvider implementation.
|
||||
*/
|
||||
public static SelectorProvider create() {
|
||||
return new EPollSelectorProvider();
|
||||
public static SelectorProviderImpl get() {
|
||||
return INSTANCE;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. 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
|
||||
@ -25,13 +25,19 @@
|
||||
|
||||
package sun.nio.ch;
|
||||
|
||||
import java.nio.channels.spi.SelectorProvider;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
/**
|
||||
* Creates this platform's default SelectorProvider
|
||||
*/
|
||||
|
||||
public class DefaultSelectorProvider {
|
||||
private static final SelectorProviderImpl INSTANCE;
|
||||
static {
|
||||
PrivilegedAction<SelectorProviderImpl> pa = KQueueSelectorProvider::new;
|
||||
INSTANCE = AccessController.doPrivileged(pa);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent instantiation.
|
||||
@ -39,9 +45,9 @@ public class DefaultSelectorProvider {
|
||||
private DefaultSelectorProvider() { }
|
||||
|
||||
/**
|
||||
* Returns the default SelectorProvider.
|
||||
* Returns the default SelectorProvider implementation.
|
||||
*/
|
||||
public static SelectorProvider create() {
|
||||
return new KQueueSelectorProvider();
|
||||
public static SelectorProviderImpl get() {
|
||||
return INSTANCE;
|
||||
}
|
||||
}
|
||||
|
@ -26,15 +26,18 @@
|
||||
package java.nio.channels.spi;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.ProtocolFamily;
|
||||
import java.nio.channels.*;
|
||||
import java.nio.channels.Channel;
|
||||
import java.nio.channels.DatagramChannel;
|
||||
import java.nio.channels.Pipe;
|
||||
import java.nio.channels.ServerSocketChannel;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Iterator;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.ServiceConfigurationError;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
|
||||
/**
|
||||
* Service-provider class for selectors and selectable channels.
|
||||
@ -68,9 +71,6 @@ import sun.security.action.GetPropertyAction;
|
||||
|
||||
public abstract class SelectorProvider {
|
||||
|
||||
private static final Object lock = new Object();
|
||||
private static SelectorProvider provider = null;
|
||||
|
||||
private static Void checkPermission() {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null)
|
||||
@ -90,45 +90,53 @@ public abstract class SelectorProvider {
|
||||
this(checkPermission());
|
||||
}
|
||||
|
||||
private static boolean loadProviderFromProperty() {
|
||||
String cn = System.getProperty("java.nio.channels.spi.SelectorProvider");
|
||||
if (cn == null)
|
||||
return false;
|
||||
try {
|
||||
@SuppressWarnings("deprecation")
|
||||
Object tmp = Class.forName(cn, true,
|
||||
ClassLoader.getSystemClassLoader()).newInstance();
|
||||
provider = (SelectorProvider)tmp;
|
||||
return true;
|
||||
} catch (ClassNotFoundException x) {
|
||||
throw new ServiceConfigurationError(null, x);
|
||||
} catch (IllegalAccessException x) {
|
||||
throw new ServiceConfigurationError(null, x);
|
||||
} catch (InstantiationException x) {
|
||||
throw new ServiceConfigurationError(null, x);
|
||||
} catch (SecurityException x) {
|
||||
throw new ServiceConfigurationError(null, x);
|
||||
private static class Holder {
|
||||
static final SelectorProvider INSTANCE = provider();
|
||||
|
||||
static SelectorProvider provider() {
|
||||
PrivilegedAction<SelectorProvider> pa = () -> {
|
||||
SelectorProvider sp;
|
||||
if ((sp = loadProviderFromProperty()) != null)
|
||||
return sp;
|
||||
if ((sp = loadProviderAsService()) != null)
|
||||
return sp;
|
||||
return sun.nio.ch.DefaultSelectorProvider.get();
|
||||
};
|
||||
return AccessController.doPrivileged(pa);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean loadProviderAsService() {
|
||||
|
||||
ServiceLoader<SelectorProvider> sl =
|
||||
ServiceLoader.load(SelectorProvider.class,
|
||||
ClassLoader.getSystemClassLoader());
|
||||
Iterator<SelectorProvider> i = sl.iterator();
|
||||
for (;;) {
|
||||
private static SelectorProvider loadProviderFromProperty() {
|
||||
String cn = System.getProperty("java.nio.channels.spi.SelectorProvider");
|
||||
if (cn == null)
|
||||
return null;
|
||||
try {
|
||||
if (!i.hasNext())
|
||||
return false;
|
||||
provider = i.next();
|
||||
return true;
|
||||
} catch (ServiceConfigurationError sce) {
|
||||
if (sce.getCause() instanceof SecurityException) {
|
||||
// Ignore the security exception, try the next provider
|
||||
continue;
|
||||
Class<?> clazz = Class.forName(cn, true, ClassLoader.getSystemClassLoader());
|
||||
return (SelectorProvider) clazz.getConstructor().newInstance();
|
||||
} catch (ClassNotFoundException |
|
||||
NoSuchMethodException |
|
||||
IllegalAccessException |
|
||||
InvocationTargetException |
|
||||
InstantiationException |
|
||||
SecurityException x) {
|
||||
throw new ServiceConfigurationError(null, x);
|
||||
}
|
||||
}
|
||||
|
||||
private static SelectorProvider loadProviderAsService() {
|
||||
ServiceLoader<SelectorProvider> sl =
|
||||
ServiceLoader.load(SelectorProvider.class,
|
||||
ClassLoader.getSystemClassLoader());
|
||||
Iterator<SelectorProvider> i = sl.iterator();
|
||||
for (;;) {
|
||||
try {
|
||||
return i.hasNext() ? i.next() : null;
|
||||
} catch (ServiceConfigurationError sce) {
|
||||
if (sce.getCause() instanceof SecurityException) {
|
||||
// Ignore the security exception, try the next provider
|
||||
continue;
|
||||
}
|
||||
throw sce;
|
||||
}
|
||||
throw sce;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -169,21 +177,7 @@ public abstract class SelectorProvider {
|
||||
* @return The system-wide default selector provider
|
||||
*/
|
||||
public static SelectorProvider provider() {
|
||||
synchronized (lock) {
|
||||
if (provider != null)
|
||||
return provider;
|
||||
return AccessController.doPrivileged(
|
||||
new PrivilegedAction<>() {
|
||||
public SelectorProvider run() {
|
||||
if (loadProviderFromProperty())
|
||||
return provider;
|
||||
if (loadProviderAsService())
|
||||
return provider;
|
||||
provider = sun.nio.ch.DefaultSelectorProvider.create();
|
||||
return provider;
|
||||
}
|
||||
});
|
||||
}
|
||||
return Holder.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -317,8 +311,8 @@ public abstract class SelectorProvider {
|
||||
*
|
||||
* @since 1.5
|
||||
*/
|
||||
public Channel inheritedChannel() throws IOException {
|
||||
public Channel inheritedChannel() throws IOException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -84,6 +84,9 @@ class DatagramChannelImpl
|
||||
// Used to make native read and write calls
|
||||
private static final NativeDispatcher nd = new DatagramDispatcher();
|
||||
|
||||
// true if interruptible (can be false to emulate legacy DatagramSocket)
|
||||
private final boolean interruptible;
|
||||
|
||||
// The protocol family of the socket
|
||||
private final ProtocolFamily family;
|
||||
|
||||
@ -158,13 +161,14 @@ class DatagramChannelImpl
|
||||
// -- End of fields protected by stateLock
|
||||
|
||||
|
||||
public DatagramChannelImpl(SelectorProvider sp) throws IOException {
|
||||
DatagramChannelImpl(SelectorProvider sp, boolean interruptible) throws IOException {
|
||||
this(sp, (Net.isIPv6Available()
|
||||
? StandardProtocolFamily.INET6
|
||||
: StandardProtocolFamily.INET));
|
||||
: StandardProtocolFamily.INET),
|
||||
interruptible);
|
||||
}
|
||||
|
||||
public DatagramChannelImpl(SelectorProvider sp, ProtocolFamily family)
|
||||
DatagramChannelImpl(SelectorProvider sp, ProtocolFamily family, boolean interruptible)
|
||||
throws IOException
|
||||
{
|
||||
super(sp);
|
||||
@ -184,6 +188,7 @@ class DatagramChannelImpl
|
||||
ResourceManager.beforeUdpCreate();
|
||||
boolean initialized = false;
|
||||
try {
|
||||
this.interruptible = interruptible;
|
||||
this.family = family;
|
||||
this.fd = fd = Net.socket(family, false);
|
||||
this.fdVal = IOUtil.fdVal(fd);
|
||||
@ -211,7 +216,7 @@ class DatagramChannelImpl
|
||||
this.cleaner = CleanerFactory.cleaner().register(this, releaser);
|
||||
}
|
||||
|
||||
public DatagramChannelImpl(SelectorProvider sp, FileDescriptor fd)
|
||||
DatagramChannelImpl(SelectorProvider sp, FileDescriptor fd)
|
||||
throws IOException
|
||||
{
|
||||
super(sp);
|
||||
@ -221,6 +226,7 @@ class DatagramChannelImpl
|
||||
ResourceManager.beforeUdpCreate();
|
||||
boolean initialized = false;
|
||||
try {
|
||||
this.interruptible = true;
|
||||
this.family = Net.isIPv6Available()
|
||||
? StandardProtocolFamily.INET6
|
||||
: StandardProtocolFamily.INET;
|
||||
@ -476,7 +482,7 @@ class DatagramChannelImpl
|
||||
private SocketAddress beginRead(boolean blocking, boolean mustBeConnected)
|
||||
throws IOException
|
||||
{
|
||||
if (blocking) {
|
||||
if (blocking && interruptible) {
|
||||
// set hook for Thread.interrupt
|
||||
begin();
|
||||
}
|
||||
@ -509,8 +515,12 @@ class DatagramChannelImpl
|
||||
tryFinishClose();
|
||||
}
|
||||
}
|
||||
// remove hook for Thread.interrupt
|
||||
end(completed);
|
||||
if (interruptible) {
|
||||
// remove hook for Thread.interrupt (may throw AsynchronousCloseException)
|
||||
end(completed);
|
||||
} else if (!completed && !isOpen()) {
|
||||
throw new AsynchronousCloseException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -951,7 +961,7 @@ class DatagramChannelImpl
|
||||
beginRead(blocking, true);
|
||||
n = IOUtil.read(fd, dsts, offset, length, nd);
|
||||
if (blocking) {
|
||||
while (IOStatus.okayToRetry(n) && isOpen()) {
|
||||
while (IOStatus.okayToRetry(n) && isOpen()) {
|
||||
park(Net.POLLIN);
|
||||
n = IOUtil.read(fd, dsts, offset, length, nd);
|
||||
}
|
||||
@ -978,7 +988,7 @@ class DatagramChannelImpl
|
||||
private SocketAddress beginWrite(boolean blocking, boolean mustBeConnected)
|
||||
throws IOException
|
||||
{
|
||||
if (blocking) {
|
||||
if (blocking && interruptible) {
|
||||
// set hook for Thread.interrupt
|
||||
begin();
|
||||
}
|
||||
@ -1011,8 +1021,13 @@ class DatagramChannelImpl
|
||||
tryFinishClose();
|
||||
}
|
||||
}
|
||||
// remove hook for Thread.interrupt
|
||||
end(completed);
|
||||
|
||||
if (interruptible) {
|
||||
// remove hook for Thread.interrupt (may throw AsynchronousCloseException)
|
||||
end(completed);
|
||||
} else if (!completed && !isOpen()) {
|
||||
throw new AsynchronousCloseException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. 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
|
||||
@ -25,37 +25,50 @@
|
||||
|
||||
package sun.nio.ch;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.ProtocolFamily;
|
||||
import java.nio.channels.*;
|
||||
import java.nio.channels.spi.*;
|
||||
|
||||
import java.nio.channels.DatagramChannel;
|
||||
import java.nio.channels.Pipe;
|
||||
import java.nio.channels.ServerSocketChannel;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.nio.channels.spi.AbstractSelector;
|
||||
import java.nio.channels.spi.SelectorProvider;
|
||||
|
||||
public abstract class SelectorProviderImpl
|
||||
extends SelectorProvider
|
||||
{
|
||||
|
||||
@Override
|
||||
public DatagramChannel openDatagramChannel() throws IOException {
|
||||
return new DatagramChannelImpl(this);
|
||||
return new DatagramChannelImpl(this, /*interruptible*/true);
|
||||
}
|
||||
|
||||
/**
|
||||
* SelectorProviderImpl specific method to create a DatagramChannel that
|
||||
* is not interruptible.
|
||||
*/
|
||||
public DatagramChannel openUninterruptibleDatagramChannel() throws IOException {
|
||||
return new DatagramChannelImpl(this, /*interruptible*/false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DatagramChannel openDatagramChannel(ProtocolFamily family) throws IOException {
|
||||
return new DatagramChannelImpl(this, family);
|
||||
return new DatagramChannelImpl(this, family, /*interruptible*/true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pipe openPipe() throws IOException {
|
||||
return new PipeImpl(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract AbstractSelector openSelector() throws IOException;
|
||||
|
||||
@Override
|
||||
public ServerSocketChannel openServerSocketChannel() throws IOException {
|
||||
return new ServerSocketChannelImpl(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocketChannel openSocketChannel() throws IOException {
|
||||
return new SocketChannelImpl(this);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. 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
|
||||
@ -25,13 +25,19 @@
|
||||
|
||||
package sun.nio.ch;
|
||||
|
||||
import java.nio.channels.spi.SelectorProvider;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
/**
|
||||
* Creates this platform's default SelectorProvider
|
||||
*/
|
||||
|
||||
public class DefaultSelectorProvider {
|
||||
private static final SelectorProviderImpl INSTANCE;
|
||||
static {
|
||||
PrivilegedAction<SelectorProviderImpl> pa = DevPollSelectorProvider::new;
|
||||
INSTANCE = AccessController.doPrivileged(pa);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent instantiation.
|
||||
@ -39,9 +45,9 @@ public class DefaultSelectorProvider {
|
||||
private DefaultSelectorProvider() { }
|
||||
|
||||
/**
|
||||
* Returns the default SelectorProvider.
|
||||
* Returns the default SelectorProvider implementation.
|
||||
*/
|
||||
public static SelectorProvider create() {
|
||||
return new DevPollSelectorProvider();
|
||||
public static SelectorProviderImpl get() {
|
||||
return INSTANCE;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2002, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2019, Oracle and/or its affiliates. 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
|
||||
@ -25,14 +25,19 @@
|
||||
|
||||
package sun.nio.ch;
|
||||
|
||||
import java.nio.channels.spi.SelectorProvider;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
/**
|
||||
* Creates this platform's default SelectorProvider
|
||||
*/
|
||||
|
||||
public class DefaultSelectorProvider {
|
||||
private static final SelectorProviderImpl INSTANCE;
|
||||
static {
|
||||
PrivilegedAction<SelectorProviderImpl> pa = WindowsSelectorProvider::new;
|
||||
INSTANCE = AccessController.doPrivileged(pa);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent instantiation.
|
||||
@ -40,10 +45,9 @@ public class DefaultSelectorProvider {
|
||||
private DefaultSelectorProvider() { }
|
||||
|
||||
/**
|
||||
* Returns the default SelectorProvider.
|
||||
* Returns the default SelectorProvider implementation.
|
||||
*/
|
||||
public static SelectorProvider create() {
|
||||
return new sun.nio.ch.WindowsSelectorProvider();
|
||||
public static SelectorProviderImpl get() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8236246
|
||||
* @modules java.base/sun.nio.ch
|
||||
* @run testng InterruptibleOrNot
|
||||
* @summary Test SelectorProviderImpl.openDatagramChannel(boolean) to create
|
||||
* DatagramChannel objects that optionally support interrupt
|
||||
*/
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.AsynchronousCloseException;
|
||||
import java.nio.channels.ClosedByInterruptException;
|
||||
import java.nio.channels.DatagramChannel;
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import sun.nio.ch.DefaultSelectorProvider;
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
@Test
|
||||
public class InterruptibleOrNot {
|
||||
|
||||
public void testInterruptBeforeInterruptibleReceive() throws Exception {
|
||||
testInterruptBeforeReceive(true);
|
||||
}
|
||||
|
||||
public void testInterruptDuringInterruptibleReceive() throws Exception {
|
||||
testInterruptDuringReceive(true);
|
||||
}
|
||||
|
||||
public void testInterruptBeforeUninterruptibleReceive() throws Exception {
|
||||
testInterruptBeforeReceive(false);
|
||||
}
|
||||
|
||||
public void testInterruptDuringUninterruptibleReceive() throws Exception {
|
||||
testInterruptDuringReceive(false);
|
||||
}
|
||||
|
||||
public void testInterruptBeforeInterruptibleSend() throws Exception {
|
||||
testInterruptBeforeSend(true);
|
||||
}
|
||||
|
||||
public void testInterruptBeforeUninterruptibleSend() throws Exception {
|
||||
testInterruptBeforeSend(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test invoking DatagramChannel receive with interrupt status set
|
||||
*/
|
||||
static void testInterruptBeforeReceive(boolean interruptible)
|
||||
throws Exception
|
||||
{
|
||||
try (DatagramChannel dc = openDatagramChannel(interruptible)) {
|
||||
dc.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
|
||||
Future<?> timeout = scheduleClose(dc, Duration.ofSeconds(2));
|
||||
try {
|
||||
ByteBuffer buf = ByteBuffer.allocate(100);
|
||||
Thread.currentThread().interrupt();
|
||||
assertThrows(expectedException(interruptible), () -> dc.receive(buf));
|
||||
} finally {
|
||||
timeout.cancel(false);
|
||||
}
|
||||
} finally {
|
||||
Thread.interrupted(); // clear interrupt
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Thread.interrupt when target thread is blocked in DatagramChannel receive
|
||||
*/
|
||||
static void testInterruptDuringReceive(boolean interruptible)
|
||||
throws Exception
|
||||
{
|
||||
try (DatagramChannel dc = openDatagramChannel(interruptible)) {
|
||||
dc.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
|
||||
Future<?> timerTask = scheduleClose(dc, Duration.ofSeconds(5));
|
||||
Future<?> interruptTask = scheduleInterrupt(Thread.currentThread(), Duration.ofSeconds(1));
|
||||
try {
|
||||
ByteBuffer buf = ByteBuffer.allocate(100);
|
||||
assertThrows(expectedException(interruptible), () -> dc.receive(buf));
|
||||
} finally {
|
||||
timerTask.cancel(false);
|
||||
interruptTask.cancel(false);
|
||||
}
|
||||
} finally {
|
||||
Thread.interrupted(); // clear interrupt
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test invoking DatagramChannel send with interrupt status set
|
||||
*/
|
||||
static void testInterruptBeforeSend(boolean interruptible)
|
||||
throws Exception
|
||||
{
|
||||
try (DatagramChannel dc = openDatagramChannel(interruptible)) {
|
||||
dc.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
|
||||
Future<?> timeout = scheduleClose(dc, Duration.ofSeconds(2));
|
||||
try {
|
||||
ByteBuffer buf = ByteBuffer.allocate(100);
|
||||
SocketAddress target = dc.getLocalAddress();
|
||||
Thread.currentThread().interrupt();
|
||||
if (interruptible) {
|
||||
assertThrows(ClosedByInterruptException.class, () -> dc.send(buf, target));
|
||||
} else {
|
||||
int n = dc.send(buf, target);
|
||||
assertTrue(n == 100);
|
||||
}
|
||||
} finally {
|
||||
timeout.cancel(false);
|
||||
}
|
||||
} finally {
|
||||
Thread.interrupted(); // clear interrupt
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a DatagramChannel that is interruptible or not.
|
||||
*/
|
||||
static DatagramChannel openDatagramChannel(boolean interruptible) throws IOException {
|
||||
if (interruptible) {
|
||||
return DatagramChannel.open();
|
||||
} else {
|
||||
return DefaultSelectorProvider.get().openUninterruptibleDatagramChannel();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Expect ClosedByInterruptException if interruptible.
|
||||
*/
|
||||
static Class<? extends Exception> expectedException(boolean expectInterrupt) {
|
||||
if (expectInterrupt) {
|
||||
return ClosedByInterruptException.class;
|
||||
} else {
|
||||
return AsynchronousCloseException.class;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule the given object to be closed.
|
||||
*/
|
||||
static Future<?> scheduleClose(Closeable c, Duration timeout) {
|
||||
long nanos = TimeUnit.NANOSECONDS.convert(timeout);
|
||||
return STPE.schedule(() -> {
|
||||
c.close();
|
||||
return null;
|
||||
}, nanos, TimeUnit.NANOSECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule the given thread to be interrupted.
|
||||
*/
|
||||
static Future<?> scheduleInterrupt(Thread t, Duration timeout) {
|
||||
long nanos = TimeUnit.NANOSECONDS.convert(timeout);
|
||||
return STPE.schedule(t::interrupt, nanos, TimeUnit.NANOSECONDS);
|
||||
}
|
||||
|
||||
static final ScheduledExecutorService STPE = Executors.newScheduledThreadPool(0);
|
||||
}
|
@ -138,7 +138,7 @@ public class InheritedChannelNotServerSocket {
|
||||
private volatile SocketChannel channel = null;
|
||||
|
||||
public SP() {
|
||||
provider = sun.nio.ch.DefaultSelectorProvider.create();
|
||||
provider = sun.nio.ch.DefaultSelectorProvider.get();
|
||||
}
|
||||
|
||||
public DatagramChannel openDatagramChannel() throws IOException {
|
||||
|
@ -47,7 +47,7 @@ public class RMIDSelectorProvider extends SelectorProvider {
|
||||
private ServerSocketChannel channel;
|
||||
|
||||
public RMIDSelectorProvider() {
|
||||
provider = sun.nio.ch.DefaultSelectorProvider.create();
|
||||
provider = sun.nio.ch.DefaultSelectorProvider.get();
|
||||
}
|
||||
|
||||
public DatagramChannel openDatagramChannel()
|
||||
|
Loading…
x
Reference in New Issue
Block a user