Made the AIO transport adhere to Netty thread model strictly
- Fixed data races - Simplified channel creation using dummy AsyncChannelGroup
This commit is contained in:
parent
613834f326
commit
cef7dfc02f
@ -32,8 +32,6 @@ import io.netty.logging.InternalLoggerFactory;
|
|||||||
import io.netty.util.internal.DetectionUtil;
|
import io.netty.util.internal.DetectionUtil;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.DatagramSocket;
|
|
||||||
import java.net.Socket;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.ClosedChannelException;
|
import java.nio.channels.ClosedChannelException;
|
||||||
import java.nio.channels.DatagramChannel;
|
import java.nio.channels.DatagramChannel;
|
||||||
@ -721,7 +719,6 @@ public class SslHandler
|
|||||||
"SSLEngine.closeInbound() raised an exception after " +
|
"SSLEngine.closeInbound() raised an exception after " +
|
||||||
"a handshake failure.", e);
|
"a handshake failure.", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@ -757,7 +754,7 @@ public class SslHandler
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (future.setSuccess()) {
|
if (future.setSuccess()) {
|
||||||
logger.debug("close_notify write attempt timed out. Force-closing the connection.");
|
logger.warn("close_notify write attempt timed out. Force-closing the connection.");
|
||||||
ctx.close(ctx.newFuture());
|
ctx.close(ctx.newFuture());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -768,9 +765,10 @@ public class SslHandler
|
|||||||
@Override
|
@Override
|
||||||
public void operationComplete(ChannelFuture f)
|
public void operationComplete(ChannelFuture f)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
timeoutFuture.cancel(false);
|
if (timeoutFuture.cancel(false)) {
|
||||||
ctx.close(future);
|
ctx.close(future);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,6 @@ import java.util.concurrent.ThreadFactory;
|
|||||||
|
|
||||||
public abstract class MultithreadEventLoop extends MultithreadEventExecutor implements EventLoop {
|
public abstract class MultithreadEventLoop extends MultithreadEventExecutor implements EventLoop {
|
||||||
|
|
||||||
|
|
||||||
protected MultithreadEventLoop(int nThreads, ThreadFactory threadFactory,
|
protected MultithreadEventLoop(int nThreads, ThreadFactory threadFactory,
|
||||||
Object... args) {
|
Object... args) {
|
||||||
super(nThreads, threadFactory, args);
|
super(nThreads, threadFactory, args);
|
||||||
|
@ -36,15 +36,19 @@ final class LocalChildEventLoop extends SingleThreadEventLoop {
|
|||||||
// Waken up by interruptThread()
|
// Waken up by interruptThread()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isShutdown() && peekTask() == null) {
|
if (isShutdown()) {
|
||||||
|
task = pollTask();
|
||||||
|
if (task == null) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
task.run();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void wakeup(boolean inEventLoop) {
|
protected void wakeup(boolean inEventLoop) {
|
||||||
if (!inEventLoop) {
|
if (!inEventLoop && isShutdown()) {
|
||||||
interruptThread();
|
interruptThread();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ import java.util.concurrent.TimeUnit;
|
|||||||
|
|
||||||
public abstract class AbstractAioChannel extends AbstractChannel {
|
public abstract class AbstractAioChannel extends AbstractChannel {
|
||||||
|
|
||||||
protected volatile AsynchronousChannel ch;
|
private final AsynchronousChannel ch;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The future of the current connection attempt. If not null, subsequent
|
* The future of the current connection attempt. If not null, subsequent
|
||||||
@ -39,23 +39,18 @@ public abstract class AbstractAioChannel extends AbstractChannel {
|
|||||||
protected ScheduledFuture<?> connectTimeoutFuture;
|
protected ScheduledFuture<?> connectTimeoutFuture;
|
||||||
private ConnectException connectTimeoutException;
|
private ConnectException connectTimeoutException;
|
||||||
|
|
||||||
protected AbstractAioChannel(Channel parent, Integer id) {
|
protected AbstractAioChannel(Channel parent, Integer id, AsynchronousChannel ch) {
|
||||||
super(parent, id);
|
super(parent, id);
|
||||||
|
this.ch = ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InetSocketAddress localAddress() {
|
public InetSocketAddress localAddress() {
|
||||||
if (ch == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return (InetSocketAddress) super.localAddress();
|
return (InetSocketAddress) super.localAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InetSocketAddress remoteAddress() {
|
public InetSocketAddress remoteAddress() {
|
||||||
if (ch == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return (InetSocketAddress) super.remoteAddress();
|
return (InetSocketAddress) super.remoteAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,7 +60,7 @@ public abstract class AbstractAioChannel extends AbstractChannel {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isOpen() {
|
public boolean isOpen() {
|
||||||
return ch == null || ch.isOpen();
|
return ch.isOpen();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -36,15 +36,19 @@ final class AioChildEventLoop extends SingleThreadEventLoop {
|
|||||||
// Waken up by interruptThread()
|
// Waken up by interruptThread()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isShutdown() && peekTask() == null) {
|
if (isShutdown()) {
|
||||||
|
task = pollTask();
|
||||||
|
if (task == null) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
task.run();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void wakeup(boolean inEventLoop) {
|
protected void wakeup(boolean inEventLoop) {
|
||||||
if (!inEventLoop) {
|
if (!inEventLoop && isShutdown()) {
|
||||||
interruptThread();
|
interruptThread();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,26 +37,55 @@ abstract class AioCompletionHandler<V, A extends Channel> implements CompletionH
|
|||||||
*/
|
*/
|
||||||
protected abstract void failed0(Throwable exc, A channel);
|
protected abstract void failed0(Throwable exc, A channel);
|
||||||
|
|
||||||
|
private static final int MAX_STACK_DEPTH = 4;
|
||||||
|
private static final ThreadLocal<Integer> STACK_DEPTH = new ThreadLocal<Integer>() {
|
||||||
|
@Override
|
||||||
|
protected Integer initialValue() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void completed(final V result, final A channel) {
|
public final void completed(final V result, final A channel) {
|
||||||
if (channel.eventLoop().inEventLoop()) {
|
EventLoop loop = channel.eventLoop();
|
||||||
|
if (loop.inEventLoop()) {
|
||||||
|
Integer d = STACK_DEPTH.get();
|
||||||
|
if (d < MAX_STACK_DEPTH) {
|
||||||
|
STACK_DEPTH.set(d + 1);
|
||||||
|
try {
|
||||||
completed0(result, channel);
|
completed0(result, channel);
|
||||||
} else {
|
} finally {
|
||||||
channel.eventLoop().execute(new Runnable() {
|
STACK_DEPTH.set(d);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loop.execute(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
completed0(result, channel);
|
completed0(result, channel);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void failed(final Throwable exc, final A channel) {
|
public final void failed(final Throwable exc, final A channel) {
|
||||||
if (channel.eventLoop().inEventLoop()) {
|
EventLoop loop = channel.eventLoop();
|
||||||
|
if (loop.inEventLoop()) {
|
||||||
|
Integer d = STACK_DEPTH.get();
|
||||||
|
if (d < MAX_STACK_DEPTH) {
|
||||||
|
STACK_DEPTH.set(d + 1);
|
||||||
|
try {
|
||||||
failed0(exc, channel);
|
failed0(exc, channel);
|
||||||
} else {
|
} finally {
|
||||||
channel.eventLoop().execute(new Runnable() {
|
STACK_DEPTH.set(d);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loop.execute(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
failed0(exc, channel);
|
failed0(exc, channel);
|
||||||
@ -64,4 +93,3 @@ abstract class AioCompletionHandler<V, A extends Channel> implements CompletionH
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@ -0,0 +1,61 @@
|
|||||||
|
package io.netty.channel.socket.aio;
|
||||||
|
|
||||||
|
import java.nio.channels.AsynchronousChannelGroup;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.AbstractExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
final class AioGroup {
|
||||||
|
|
||||||
|
static final AsynchronousChannelGroup GROUP;
|
||||||
|
|
||||||
|
static {
|
||||||
|
AsynchronousChannelGroup group;
|
||||||
|
try {
|
||||||
|
group = AsynchronousChannelGroup.withThreadPool(new AioGroupExecutor());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new Error(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
GROUP = group;
|
||||||
|
}
|
||||||
|
|
||||||
|
private AioGroup() {
|
||||||
|
// Unused
|
||||||
|
}
|
||||||
|
|
||||||
|
static final class AioGroupExecutor extends AbstractExecutorService {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void shutdown() {
|
||||||
|
// Unstoppable
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Runnable> shutdownNow() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isShutdown() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTerminated() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
|
||||||
|
Thread.sleep(unit.toMillis(timeout));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(Runnable command) {
|
||||||
|
command.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -26,7 +26,6 @@ import io.netty.logging.InternalLoggerFactory;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
import java.nio.channels.AsynchronousChannelGroup;
|
|
||||||
import java.nio.channels.AsynchronousCloseException;
|
import java.nio.channels.AsynchronousCloseException;
|
||||||
import java.nio.channels.AsynchronousServerSocketChannel;
|
import java.nio.channels.AsynchronousServerSocketChannel;
|
||||||
import java.nio.channels.AsynchronousSocketChannel;
|
import java.nio.channels.AsynchronousSocketChannel;
|
||||||
@ -39,11 +38,20 @@ public class AioServerSocketChannel extends AbstractAioChannel implements Server
|
|||||||
private static final InternalLogger logger =
|
private static final InternalLogger logger =
|
||||||
InternalLoggerFactory.getInstance(AioServerSocketChannel.class);
|
InternalLoggerFactory.getInstance(AioServerSocketChannel.class);
|
||||||
|
|
||||||
private final AioServerSocketChannelConfig config = new AioServerSocketChannelConfig();
|
private final AioServerSocketChannelConfig config;
|
||||||
private boolean closed;
|
private boolean closed;
|
||||||
|
|
||||||
|
private static AsynchronousServerSocketChannel newSocket() {
|
||||||
|
try {
|
||||||
|
return AsynchronousServerSocketChannel.open(AioGroup.GROUP);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ChannelException("Failed to open a socket.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public AioServerSocketChannel() {
|
public AioServerSocketChannel() {
|
||||||
super(null, null);
|
super(null, null, newSocket());
|
||||||
|
config = new AioServerSocketChannelConfig(javaChannel());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -53,15 +61,7 @@ public class AioServerSocketChannel extends AbstractAioChannel implements Server
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isActive() {
|
public boolean isActive() {
|
||||||
AsynchronousServerSocketChannel channel = javaChannel();
|
return javaChannel().isOpen() && localAddress0() != null;
|
||||||
try {
|
|
||||||
if (channel != null && channel.getLocalAddress() != null) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -85,9 +85,9 @@ public class AioServerSocketChannel extends AbstractAioChannel implements Server
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doBind(SocketAddress localAddress) throws Exception {
|
protected void doBind(SocketAddress localAddress) throws Exception {
|
||||||
javaChannel().bind(localAddress);
|
AsynchronousServerSocketChannel ch = javaChannel();
|
||||||
javaChannel().accept(this, ACCEPT_HANDLER);
|
ch.bind(localAddress);
|
||||||
|
ch.accept(this, ACCEPT_HANDLER);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -116,9 +116,6 @@ public class AioServerSocketChannel extends AbstractAioChannel implements Server
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Runnable doRegister() throws Exception {
|
protected Runnable doRegister() throws Exception {
|
||||||
ch = AsynchronousServerSocketChannel.open(AsynchronousChannelGroup.withThreadPool(eventLoop()));
|
|
||||||
config.setChannel(javaChannel());
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,26 +33,11 @@ import java.util.Map;
|
|||||||
final class AioServerSocketChannelConfig extends DefaultChannelConfig
|
final class AioServerSocketChannelConfig extends DefaultChannelConfig
|
||||||
implements ServerSocketChannelConfig {
|
implements ServerSocketChannelConfig {
|
||||||
|
|
||||||
private volatile AsynchronousServerSocketChannel channel;
|
private final AsynchronousServerSocketChannel channel;
|
||||||
private volatile Integer receiveBufferSize;
|
|
||||||
private volatile Boolean reuseAddress;
|
|
||||||
private volatile int backlog = NetworkConstants.SOMAXCONN;
|
private volatile int backlog = NetworkConstants.SOMAXCONN;
|
||||||
|
|
||||||
void setChannel(AsynchronousServerSocketChannel channel) {
|
AioServerSocketChannelConfig(AsynchronousServerSocketChannel channel) {
|
||||||
if (channel == null) {
|
|
||||||
throw new NullPointerException("channel");
|
|
||||||
}
|
|
||||||
if (this.channel != null) {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
this.channel = channel;
|
this.channel = channel;
|
||||||
|
|
||||||
if (receiveBufferSize != null) {
|
|
||||||
setReceiveBufferSize(receiveBufferSize);
|
|
||||||
}
|
|
||||||
if (reuseAddress != null) {
|
|
||||||
setReuseAddress(reuseAddress);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -94,14 +79,6 @@ final class AioServerSocketChannelConfig extends DefaultChannelConfig
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isReuseAddress() {
|
public boolean isReuseAddress() {
|
||||||
AsynchronousServerSocketChannel channel = this.channel;
|
|
||||||
if (channel == null) {
|
|
||||||
if (reuseAddress == null) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return reuseAddress;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
return channel.getOption(StandardSocketOptions.SO_REUSEADDR);
|
return channel.getOption(StandardSocketOptions.SO_REUSEADDR);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -111,10 +88,6 @@ final class AioServerSocketChannelConfig extends DefaultChannelConfig
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setReuseAddress(boolean reuseAddress) {
|
public void setReuseAddress(boolean reuseAddress) {
|
||||||
AsynchronousServerSocketChannel channel = this.channel;
|
|
||||||
if (channel == null) {
|
|
||||||
this.reuseAddress = reuseAddress;
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
channel.setOption(StandardSocketOptions.SO_REUSEADDR, reuseAddress);
|
channel.setOption(StandardSocketOptions.SO_REUSEADDR, reuseAddress);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -124,14 +97,6 @@ final class AioServerSocketChannelConfig extends DefaultChannelConfig
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getReceiveBufferSize() {
|
public int getReceiveBufferSize() {
|
||||||
AsynchronousServerSocketChannel channel = this.channel;
|
|
||||||
if (channel == null) {
|
|
||||||
if (receiveBufferSize == null) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
return receiveBufferSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
return channel.getOption(StandardSocketOptions.SO_RCVBUF);
|
return channel.getOption(StandardSocketOptions.SO_RCVBUF);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -141,12 +106,6 @@ final class AioServerSocketChannelConfig extends DefaultChannelConfig
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setReceiveBufferSize(int receiveBufferSize) {
|
public void setReceiveBufferSize(int receiveBufferSize) {
|
||||||
AsynchronousServerSocketChannel channel = this.channel;
|
|
||||||
if (channel == null) {
|
|
||||||
this.receiveBufferSize = receiveBufferSize;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
channel.setOption(StandardSocketOptions.SO_RCVBUF, receiveBufferSize);
|
channel.setOption(StandardSocketOptions.SO_RCVBUF, receiveBufferSize);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -17,6 +17,7 @@ package io.netty.channel.socket.aio;
|
|||||||
|
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.ChannelBufType;
|
import io.netty.buffer.ChannelBufType;
|
||||||
|
import io.netty.channel.ChannelException;
|
||||||
import io.netty.channel.ChannelFuture;
|
import io.netty.channel.ChannelFuture;
|
||||||
import io.netty.channel.ChannelMetadata;
|
import io.netty.channel.ChannelMetadata;
|
||||||
import io.netty.channel.ChannelPipeline;
|
import io.netty.channel.ChannelPipeline;
|
||||||
@ -26,12 +27,10 @@ import java.io.IOException;
|
|||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.AsynchronousChannelGroup;
|
|
||||||
import java.nio.channels.AsynchronousCloseException;
|
import java.nio.channels.AsynchronousCloseException;
|
||||||
import java.nio.channels.AsynchronousSocketChannel;
|
import java.nio.channels.AsynchronousSocketChannel;
|
||||||
import java.nio.channels.ClosedChannelException;
|
import java.nio.channels.ClosedChannelException;
|
||||||
import java.nio.channels.CompletionHandler;
|
import java.nio.channels.CompletionHandler;
|
||||||
import java.nio.channels.NetworkChannel;
|
|
||||||
|
|
||||||
|
|
||||||
public class AioSocketChannel extends AbstractAioChannel implements SocketChannel {
|
public class AioSocketChannel extends AbstractAioChannel implements SocketChannel {
|
||||||
@ -42,29 +41,30 @@ public class AioSocketChannel extends AbstractAioChannel implements SocketChanne
|
|||||||
private static final CompletionHandler<Integer, AioSocketChannel> READ_HANDLER = new ReadHandler();
|
private static final CompletionHandler<Integer, AioSocketChannel> READ_HANDLER = new ReadHandler();
|
||||||
private static final CompletionHandler<Integer, AioSocketChannel> WRITE_HANDLER = new WriteHandler();
|
private static final CompletionHandler<Integer, AioSocketChannel> WRITE_HANDLER = new WriteHandler();
|
||||||
|
|
||||||
private final AioSocketChannelConfig config = new AioSocketChannelConfig();
|
private final AioSocketChannelConfig config;
|
||||||
private boolean closed;
|
private boolean closed;
|
||||||
private boolean flushing;
|
private boolean flushing;
|
||||||
|
|
||||||
public AioSocketChannel() {
|
private static AsynchronousSocketChannel newSocket() {
|
||||||
this(null, null, null);
|
try {
|
||||||
|
return AsynchronousSocketChannel.open(AioGroup.GROUP);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ChannelException("Failed to open a socket.", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public AioSocketChannel(AioServerSocketChannel parent, Integer id, AsynchronousSocketChannel channel) {
|
public AioSocketChannel() {
|
||||||
super(parent, id);
|
this(null, null, newSocket());
|
||||||
ch = channel;
|
|
||||||
if (ch != null) {
|
|
||||||
config.setChannel(channel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AioSocketChannel(AioServerSocketChannel parent, Integer id, AsynchronousSocketChannel ch) {
|
||||||
|
super(parent, id, ch);
|
||||||
|
config = new AioSocketChannelConfig(ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isActive() {
|
public boolean isActive() {
|
||||||
if (ch == null) {
|
return javaChannel().isOpen() && remoteAddress0() != null;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
AsynchronousSocketChannel ch = javaChannel();
|
|
||||||
return ch.isOpen() && remoteAddress() != null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -79,7 +79,6 @@ public class AioSocketChannel extends AbstractAioChannel implements SocketChanne
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doConnect(SocketAddress remoteAddress, SocketAddress localAddress, final ChannelFuture future) {
|
protected void doConnect(SocketAddress remoteAddress, SocketAddress localAddress, final ChannelFuture future) {
|
||||||
assert ch != null;
|
|
||||||
if (localAddress != null) {
|
if (localAddress != null) {
|
||||||
try {
|
try {
|
||||||
javaChannel().bind(localAddress);
|
javaChannel().bind(localAddress);
|
||||||
@ -112,11 +111,10 @@ public class AioSocketChannel extends AbstractAioChannel implements SocketChanne
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Runnable doRegister() throws Exception {
|
protected Runnable doRegister() throws Exception {
|
||||||
if (ch == null) {
|
if (remoteAddress() == null) {
|
||||||
ch = AsynchronousSocketChannel.open(AsynchronousChannelGroup.withThreadPool(eventLoop()));
|
|
||||||
config.setChannel((NetworkChannel) ch);
|
|
||||||
return null;
|
return null;
|
||||||
} else if (remoteAddress() != null) {
|
}
|
||||||
|
|
||||||
return new Runnable() {
|
return new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@ -124,15 +122,17 @@ public class AioSocketChannel extends AbstractAioChannel implements SocketChanne
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trigger a read from the {@link AioSocketChannel}
|
* Trigger a read from the {@link AioSocketChannel}
|
||||||
*/
|
*/
|
||||||
void read() {
|
void read() {
|
||||||
ByteBuf byteBuf = pipeline().inboundByteBuffer();
|
ByteBuf byteBuf = pipeline().inboundByteBuffer();
|
||||||
|
if (!byteBuf.readable()) {
|
||||||
|
byteBuf.clear();
|
||||||
|
} else {
|
||||||
expandReadBuffer(byteBuf);
|
expandReadBuffer(byteBuf);
|
||||||
|
}
|
||||||
// Get a ByteBuffer view on the ByteBuf
|
// Get a ByteBuffer view on the ByteBuf
|
||||||
ByteBuffer buffer = byteBuf.nioBuffer(byteBuf.writerIndex(), byteBuf.writableBytes());
|
ByteBuffer buffer = byteBuf.nioBuffer(byteBuf.writerIndex(), byteBuf.writableBytes());
|
||||||
javaChannel().read(buffer, this, READ_HANDLER);
|
javaChannel().read(buffer, this, READ_HANDLER);
|
||||||
@ -264,6 +264,7 @@ public class AioSocketChannel extends AbstractAioChannel implements SocketChanne
|
|||||||
// This is needed as the ByteBuffer and the ByteBuf does not share
|
// This is needed as the ByteBuffer and the ByteBuf does not share
|
||||||
// each others index
|
// each others index
|
||||||
byteBuf.writerIndex(byteBuf.writerIndex() + localReadAmount);
|
byteBuf.writerIndex(byteBuf.writerIndex() + localReadAmount);
|
||||||
|
expandReadBuffer(byteBuf);
|
||||||
|
|
||||||
read = true;
|
read = true;
|
||||||
} else if (localReadAmount < 0) {
|
} else if (localReadAmount < 0) {
|
||||||
@ -338,11 +339,6 @@ public class AioSocketChannel extends AbstractAioChannel implements SocketChanne
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AioSocketChannelConfig config() {
|
public AioSocketChannelConfig config() {
|
||||||
if (config == null) {
|
|
||||||
throw new IllegalStateException("Channel not open yet");
|
|
||||||
}
|
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -32,48 +32,17 @@ import java.util.Map;
|
|||||||
final class AioSocketChannelConfig extends DefaultChannelConfig
|
final class AioSocketChannelConfig extends DefaultChannelConfig
|
||||||
implements SocketChannelConfig {
|
implements SocketChannelConfig {
|
||||||
|
|
||||||
private volatile NetworkChannel channel;
|
private final NetworkChannel channel;
|
||||||
private volatile Integer receiveBufferSize;
|
|
||||||
private volatile Integer sendBufferSize;
|
|
||||||
private volatile Boolean tcpNoDelay;
|
|
||||||
private volatile Boolean keepAlive;
|
|
||||||
private volatile Boolean reuseAddress;
|
|
||||||
private volatile Integer soLinger;
|
|
||||||
private volatile Integer trafficClass;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance.
|
* Creates a new instance.
|
||||||
*/
|
*/
|
||||||
void setChannel(NetworkChannel channel) {
|
AioSocketChannelConfig(NetworkChannel channel) {
|
||||||
if (channel == null) {
|
if (channel == null) {
|
||||||
throw new NullPointerException("channel");
|
throw new NullPointerException("channel");
|
||||||
}
|
}
|
||||||
if (this.channel != null) {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
this.channel = channel;
|
|
||||||
|
|
||||||
if (receiveBufferSize != null) {
|
this.channel = channel;
|
||||||
setReceiveBufferSize(receiveBufferSize);
|
|
||||||
}
|
|
||||||
if (sendBufferSize != null) {
|
|
||||||
setSendBufferSize(sendBufferSize);
|
|
||||||
}
|
|
||||||
if (reuseAddress != null) {
|
|
||||||
setReuseAddress(reuseAddress);
|
|
||||||
}
|
|
||||||
if (tcpNoDelay != null) {
|
|
||||||
setTcpNoDelay(tcpNoDelay);
|
|
||||||
}
|
|
||||||
if (keepAlive != null) {
|
|
||||||
setKeepAlive(keepAlive);
|
|
||||||
}
|
|
||||||
if (soLinger != null) {
|
|
||||||
setSoLinger(soLinger);
|
|
||||||
}
|
|
||||||
if (trafficClass != null) {
|
|
||||||
setTrafficClass(trafficClass);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -137,15 +106,6 @@ final class AioSocketChannelConfig extends DefaultChannelConfig
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getReceiveBufferSize() {
|
public int getReceiveBufferSize() {
|
||||||
NetworkChannel channel = this.channel;
|
|
||||||
if (channel == null) {
|
|
||||||
if (receiveBufferSize == null) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
return receiveBufferSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return channel.getOption(StandardSocketOptions.SO_RCVBUF);
|
return channel.getOption(StandardSocketOptions.SO_RCVBUF);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -155,15 +115,6 @@ final class AioSocketChannelConfig extends DefaultChannelConfig
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getSendBufferSize() {
|
public int getSendBufferSize() {
|
||||||
NetworkChannel channel = this.channel;
|
|
||||||
if (channel == null) {
|
|
||||||
if (sendBufferSize == null) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
return sendBufferSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return channel.getOption(StandardSocketOptions.SO_SNDBUF);
|
return channel.getOption(StandardSocketOptions.SO_SNDBUF);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -173,15 +124,6 @@ final class AioSocketChannelConfig extends DefaultChannelConfig
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getSoLinger() {
|
public int getSoLinger() {
|
||||||
NetworkChannel channel = this.channel;
|
|
||||||
if (channel == null) {
|
|
||||||
if (soLinger == null) {
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
return soLinger;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return channel.getOption(StandardSocketOptions.SO_LINGER);
|
return channel.getOption(StandardSocketOptions.SO_LINGER);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -191,15 +133,6 @@ final class AioSocketChannelConfig extends DefaultChannelConfig
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getTrafficClass() {
|
public int getTrafficClass() {
|
||||||
NetworkChannel channel = this.channel;
|
|
||||||
if (channel == null) {
|
|
||||||
if (trafficClass == null) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
return trafficClass;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return channel.getOption(StandardSocketOptions.IP_TOS);
|
return channel.getOption(StandardSocketOptions.IP_TOS);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -209,15 +142,6 @@ final class AioSocketChannelConfig extends DefaultChannelConfig
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isKeepAlive() {
|
public boolean isKeepAlive() {
|
||||||
NetworkChannel channel = this.channel;
|
|
||||||
if (channel == null) {
|
|
||||||
if (keepAlive == null) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return keepAlive;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return channel.getOption(StandardSocketOptions.SO_KEEPALIVE);
|
return channel.getOption(StandardSocketOptions.SO_KEEPALIVE);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -227,15 +151,6 @@ final class AioSocketChannelConfig extends DefaultChannelConfig
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isReuseAddress() {
|
public boolean isReuseAddress() {
|
||||||
NetworkChannel channel = this.channel;
|
|
||||||
if (channel == null) {
|
|
||||||
if (reuseAddress == null) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return reuseAddress;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return channel.getOption(StandardSocketOptions.SO_REUSEADDR);
|
return channel.getOption(StandardSocketOptions.SO_REUSEADDR);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -245,15 +160,6 @@ final class AioSocketChannelConfig extends DefaultChannelConfig
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isTcpNoDelay() {
|
public boolean isTcpNoDelay() {
|
||||||
NetworkChannel channel = this.channel;
|
|
||||||
if (channel == null) {
|
|
||||||
if (tcpNoDelay == null) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return tcpNoDelay;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return channel.getOption(StandardSocketOptions.SO_REUSEADDR);
|
return channel.getOption(StandardSocketOptions.SO_REUSEADDR);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -263,12 +169,6 @@ final class AioSocketChannelConfig extends DefaultChannelConfig
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setKeepAlive(boolean keepAlive) {
|
public void setKeepAlive(boolean keepAlive) {
|
||||||
NetworkChannel channel = this.channel;
|
|
||||||
if (channel == null) {
|
|
||||||
this.keepAlive = keepAlive;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
channel.setOption(StandardSocketOptions.SO_KEEPALIVE, keepAlive);
|
channel.setOption(StandardSocketOptions.SO_KEEPALIVE, keepAlive);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -284,12 +184,6 @@ final class AioSocketChannelConfig extends DefaultChannelConfig
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setReceiveBufferSize(int receiveBufferSize) {
|
public void setReceiveBufferSize(int receiveBufferSize) {
|
||||||
NetworkChannel channel = this.channel;
|
|
||||||
if (channel == null) {
|
|
||||||
this.receiveBufferSize = receiveBufferSize;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
channel.setOption(StandardSocketOptions.SO_RCVBUF, receiveBufferSize);
|
channel.setOption(StandardSocketOptions.SO_RCVBUF, receiveBufferSize);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -299,12 +193,6 @@ final class AioSocketChannelConfig extends DefaultChannelConfig
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setReuseAddress(boolean reuseAddress) {
|
public void setReuseAddress(boolean reuseAddress) {
|
||||||
NetworkChannel channel = this.channel;
|
|
||||||
if (channel == null) {
|
|
||||||
this.reuseAddress = reuseAddress;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
channel.setOption(StandardSocketOptions.SO_REUSEADDR, reuseAddress);
|
channel.setOption(StandardSocketOptions.SO_REUSEADDR, reuseAddress);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -314,12 +202,6 @@ final class AioSocketChannelConfig extends DefaultChannelConfig
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setSendBufferSize(int sendBufferSize) {
|
public void setSendBufferSize(int sendBufferSize) {
|
||||||
NetworkChannel channel = this.channel;
|
|
||||||
if (channel == null) {
|
|
||||||
this.sendBufferSize = sendBufferSize;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
channel.setOption(StandardSocketOptions.SO_SNDBUF, sendBufferSize);
|
channel.setOption(StandardSocketOptions.SO_SNDBUF, sendBufferSize);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -329,12 +211,6 @@ final class AioSocketChannelConfig extends DefaultChannelConfig
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setSoLinger(int soLinger) {
|
public void setSoLinger(int soLinger) {
|
||||||
NetworkChannel channel = this.channel;
|
|
||||||
if (channel == null) {
|
|
||||||
this.soLinger = soLinger;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
channel.setOption(StandardSocketOptions.SO_LINGER, soLinger);
|
channel.setOption(StandardSocketOptions.SO_LINGER, soLinger);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -344,12 +220,6 @@ final class AioSocketChannelConfig extends DefaultChannelConfig
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setTcpNoDelay(boolean tcpNoDelay) {
|
public void setTcpNoDelay(boolean tcpNoDelay) {
|
||||||
NetworkChannel channel = this.channel;
|
|
||||||
if (channel == null) {
|
|
||||||
this.tcpNoDelay = tcpNoDelay;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
channel.setOption(StandardSocketOptions.TCP_NODELAY, tcpNoDelay);
|
channel.setOption(StandardSocketOptions.TCP_NODELAY, tcpNoDelay);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -359,11 +229,6 @@ final class AioSocketChannelConfig extends DefaultChannelConfig
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setTrafficClass(int trafficClass) {
|
public void setTrafficClass(int trafficClass) {
|
||||||
NetworkChannel channel = this.channel;
|
|
||||||
if (channel == null) {
|
|
||||||
this.trafficClass = trafficClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
channel.setOption(StandardSocketOptions.IP_TOS, trafficClass);
|
channel.setOption(StandardSocketOptions.IP_TOS, trafficClass);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -290,7 +290,7 @@ public class SingleThreadEventLoopTest {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void wakeup(boolean inEventLoop) {
|
protected void wakeup(boolean inEventLoop) {
|
||||||
if (!inEventLoop) {
|
if (!inEventLoop && isShutdown()) {
|
||||||
interruptThread();
|
interruptThread();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user