oio and nio transport now make sure that a upstream event get only
executed from an io thread. See #140 and #187
This commit is contained in:
parent
c4a437e16b
commit
ef64e8c332
@ -298,6 +298,21 @@ public final class Channels {
|
|||||||
ctx.getChannel(), message, remoteAddress));
|
ctx.getChannel(), message, remoteAddress));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a {@code "writeComplete"} event to the first
|
||||||
|
* {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
|
||||||
|
* the specified {@link Channel} in the next io-thread.
|
||||||
|
*/
|
||||||
|
public static void fireWriteCompleteLater(Channel channel, long amount) {
|
||||||
|
if (amount == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
channel.getPipeline().sendUpstreamLater(
|
||||||
|
new DefaultWriteCompletionEvent(channel, amount));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a {@code "writeComplete"} event to the first
|
* Sends a {@code "writeComplete"} event to the first
|
||||||
* {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
|
* {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of
|
||||||
|
@ -398,6 +398,7 @@ abstract class AbstractNioWorker implements Worker {
|
|||||||
boolean open = true;
|
boolean open = true;
|
||||||
boolean addOpWrite = false;
|
boolean addOpWrite = false;
|
||||||
boolean removeOpWrite = false;
|
boolean removeOpWrite = false;
|
||||||
|
boolean iothread = isIoThread(channel);
|
||||||
|
|
||||||
long writtenBytes = 0;
|
long writtenBytes = 0;
|
||||||
|
|
||||||
@ -468,7 +469,11 @@ abstract class AbstractNioWorker implements Worker {
|
|||||||
buf = null;
|
buf = null;
|
||||||
evt = null;
|
evt = null;
|
||||||
future.setFailure(t);
|
future.setFailure(t);
|
||||||
|
if (iothread) {
|
||||||
fireExceptionCaught(channel, t);
|
fireExceptionCaught(channel, t);
|
||||||
|
} else {
|
||||||
|
fireExceptionCaughtLater(channel, t);
|
||||||
|
}
|
||||||
if (t instanceof IOException) {
|
if (t instanceof IOException) {
|
||||||
open = false;
|
open = false;
|
||||||
close(channel, succeededFuture(channel));
|
close(channel, succeededFuture(channel));
|
||||||
@ -491,8 +496,15 @@ abstract class AbstractNioWorker implements Worker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (iothread) {
|
||||||
fireWriteComplete(channel, writtenBytes);
|
fireWriteComplete(channel, writtenBytes);
|
||||||
|
} else {
|
||||||
|
fireWriteCompleteLater(channel, writtenBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean isIoThread(AbstractNioChannel<?> channel) {
|
||||||
|
return Thread.currentThread() == channel.worker.thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setOpWrite(AbstractNioChannel<?> channel) {
|
private void setOpWrite(AbstractNioChannel<?> channel) {
|
||||||
@ -545,6 +557,8 @@ abstract class AbstractNioWorker implements Worker {
|
|||||||
void close(AbstractNioChannel<?> channel, ChannelFuture future) {
|
void close(AbstractNioChannel<?> channel, ChannelFuture future) {
|
||||||
boolean connected = channel.isConnected();
|
boolean connected = channel.isConnected();
|
||||||
boolean bound = channel.isBound();
|
boolean bound = channel.isBound();
|
||||||
|
boolean iothread = isIoThread(channel);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
channel.channel.close();
|
channel.channel.close();
|
||||||
cancelledKeys ++;
|
cancelledKeys ++;
|
||||||
@ -552,20 +566,36 @@ abstract class AbstractNioWorker implements Worker {
|
|||||||
if (channel.setClosed()) {
|
if (channel.setClosed()) {
|
||||||
future.setSuccess();
|
future.setSuccess();
|
||||||
if (connected) {
|
if (connected) {
|
||||||
|
if (iothread) {
|
||||||
fireChannelDisconnected(channel);
|
fireChannelDisconnected(channel);
|
||||||
|
} else {
|
||||||
|
fireChannelDisconnectedLater(channel);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (bound) {
|
if (bound) {
|
||||||
|
if (iothread) {
|
||||||
fireChannelUnbound(channel);
|
fireChannelUnbound(channel);
|
||||||
|
} else {
|
||||||
|
fireChannelUnboundLater(channel);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanUpWriteBuffer(channel);
|
cleanUpWriteBuffer(channel);
|
||||||
|
if (iothread) {
|
||||||
fireChannelClosed(channel);
|
fireChannelClosed(channel);
|
||||||
|
} else {
|
||||||
|
fireChannelClosedLater(channel);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
future.setSuccess();
|
future.setSuccess();
|
||||||
}
|
}
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
future.setFailure(t);
|
future.setFailure(t);
|
||||||
|
if (iothread) {
|
||||||
fireExceptionCaught(channel, t);
|
fireExceptionCaught(channel, t);
|
||||||
|
} else {
|
||||||
|
fireExceptionCaughtLater(channel, t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -618,12 +648,17 @@ abstract class AbstractNioWorker implements Worker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (fireExceptionCaught) {
|
if (fireExceptionCaught) {
|
||||||
|
if (isIoThread(channel)) {
|
||||||
fireExceptionCaught(channel, cause);
|
fireExceptionCaught(channel, cause);
|
||||||
|
} else {
|
||||||
|
fireExceptionCaughtLater(channel, cause);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setInterestOps(AbstractNioChannel<?> channel, ChannelFuture future, int interestOps) {
|
void setInterestOps(AbstractNioChannel<?> channel, ChannelFuture future, int interestOps) {
|
||||||
boolean changed = false;
|
boolean changed = false;
|
||||||
|
boolean iothread = isIoThread(channel);
|
||||||
try {
|
try {
|
||||||
// interestOps can change at any time and at any thread.
|
// interestOps can change at any time and at any thread.
|
||||||
// Acquire a lock to avoid possible race condition.
|
// Acquire a lock to avoid possible race condition.
|
||||||
@ -684,16 +719,28 @@ abstract class AbstractNioWorker implements Worker {
|
|||||||
|
|
||||||
future.setSuccess();
|
future.setSuccess();
|
||||||
if (changed) {
|
if (changed) {
|
||||||
|
if (iothread) {
|
||||||
fireChannelInterestChanged(channel);
|
fireChannelInterestChanged(channel);
|
||||||
|
} else {
|
||||||
|
fireChannelInterestChangedLater(channel);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (CancelledKeyException e) {
|
} catch (CancelledKeyException e) {
|
||||||
// setInterestOps() was called on a closed channel.
|
// setInterestOps() was called on a closed channel.
|
||||||
ClosedChannelException cce = new ClosedChannelException();
|
ClosedChannelException cce = new ClosedChannelException();
|
||||||
future.setFailure(cce);
|
future.setFailure(cce);
|
||||||
|
if (iothread) {
|
||||||
fireExceptionCaught(channel, cce);
|
fireExceptionCaught(channel, cce);
|
||||||
|
} else {
|
||||||
|
fireExceptionCaughtLater(channel, cce);
|
||||||
|
}
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
future.setFailure(t);
|
future.setFailure(t);
|
||||||
|
if (iothread) {
|
||||||
fireExceptionCaught(channel, t);
|
fireExceptionCaught(channel, t);
|
||||||
|
} else {
|
||||||
|
fireExceptionCaughtLater(channel, t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,9 @@
|
|||||||
package io.netty.channel.socket.nio;
|
package io.netty.channel.socket.nio;
|
||||||
|
|
||||||
import static io.netty.channel.Channels.fireChannelDisconnected;
|
import static io.netty.channel.Channels.fireChannelDisconnected;
|
||||||
|
import static io.netty.channel.Channels.fireChannelDisconnectedLater;
|
||||||
import static io.netty.channel.Channels.fireExceptionCaught;
|
import static io.netty.channel.Channels.fireExceptionCaught;
|
||||||
|
import static io.netty.channel.Channels.fireExceptionCaughtLater;
|
||||||
import static io.netty.channel.Channels.fireMessageReceived;
|
import static io.netty.channel.Channels.fireMessageReceived;
|
||||||
import static io.netty.channel.Channels.succeededFuture;
|
import static io.netty.channel.Channels.succeededFuture;
|
||||||
import io.netty.buffer.ChannelBufferFactory;
|
import io.netty.buffer.ChannelBufferFactory;
|
||||||
@ -126,15 +128,24 @@ class NioDatagramWorker extends AbstractNioWorker {
|
|||||||
|
|
||||||
static void disconnect(NioDatagramChannel channel, ChannelFuture future) {
|
static void disconnect(NioDatagramChannel channel, ChannelFuture future) {
|
||||||
boolean connected = channel.isConnected();
|
boolean connected = channel.isConnected();
|
||||||
|
boolean iothread = isIoThread(channel);
|
||||||
try {
|
try {
|
||||||
channel.getDatagramChannel().disconnect();
|
channel.getDatagramChannel().disconnect();
|
||||||
future.setSuccess();
|
future.setSuccess();
|
||||||
if (connected) {
|
if (connected) {
|
||||||
|
if (iothread) {
|
||||||
fireChannelDisconnected(channel);
|
fireChannelDisconnected(channel);
|
||||||
|
} else {
|
||||||
|
fireChannelDisconnectedLater(channel);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
future.setFailure(t);
|
future.setFailure(t);
|
||||||
|
if (iothread) {
|
||||||
fireExceptionCaught(channel, t);
|
fireExceptionCaught(channel, t);
|
||||||
|
} else {
|
||||||
|
fireExceptionCaughtLater(channel, t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,12 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package io.netty.channel.socket.oio;
|
package io.netty.channel.socket.oio;
|
||||||
|
|
||||||
import static io.netty.channel.Channels.fireChannelClosed;
|
import static io.netty.channel.Channels.*;
|
||||||
import static io.netty.channel.Channels.fireChannelDisconnected;
|
|
||||||
import static io.netty.channel.Channels.fireChannelInterestChanged;
|
|
||||||
import static io.netty.channel.Channels.fireChannelUnbound;
|
|
||||||
import static io.netty.channel.Channels.fireExceptionCaught;
|
|
||||||
import static io.netty.channel.Channels.succeededFuture;
|
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
import io.netty.channel.ChannelFuture;
|
import io.netty.channel.ChannelFuture;
|
||||||
import io.netty.channel.Channels;
|
import io.netty.channel.Channels;
|
||||||
@ -89,6 +84,9 @@ abstract class AbstractOioWorker<C extends AbstractOioChannel> implements Worker
|
|||||||
close(channel, succeededFuture(channel));
|
close(channel, succeededFuture(channel));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static boolean isIoThead(AbstractOioChannel channel) {
|
||||||
|
return Thread.currentThread() == channel.workerThread;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void executeInIoThread(Runnable eventRunnable) {
|
public void executeInIoThread(Runnable eventRunnable) {
|
||||||
@ -120,6 +118,7 @@ abstract class AbstractOioWorker<C extends AbstractOioChannel> implements Worker
|
|||||||
|
|
||||||
static void setInterestOps(
|
static void setInterestOps(
|
||||||
AbstractOioChannel channel, ChannelFuture future, int interestOps) {
|
AbstractOioChannel channel, ChannelFuture future, int interestOps) {
|
||||||
|
boolean iothread = isIoThead(channel);
|
||||||
|
|
||||||
// Override OP_WRITE flag - a user cannot change this flag.
|
// Override OP_WRITE flag - a user cannot change this flag.
|
||||||
interestOps &= ~Channel.OP_WRITE;
|
interestOps &= ~Channel.OP_WRITE;
|
||||||
@ -148,18 +147,27 @@ abstract class AbstractOioWorker<C extends AbstractOioChannel> implements Worker
|
|||||||
workerThread.interrupt();
|
workerThread.interrupt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (iothread) {
|
||||||
fireChannelInterestChanged(channel);
|
fireChannelInterestChanged(channel);
|
||||||
|
} else {
|
||||||
|
fireChannelInterestChangedLater(channel);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
future.setFailure(t);
|
future.setFailure(t);
|
||||||
|
if (iothread) {
|
||||||
fireExceptionCaught(channel, t);
|
fireExceptionCaught(channel, t);
|
||||||
|
} else {
|
||||||
|
fireExceptionCaughtLater(channel, t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void close(AbstractOioChannel channel, ChannelFuture future) {
|
static void close(AbstractOioChannel channel, ChannelFuture future) {
|
||||||
boolean connected = channel.isConnected();
|
boolean connected = channel.isConnected();
|
||||||
boolean bound = channel.isBound();
|
boolean bound = channel.isBound();
|
||||||
|
boolean iothread = isIoThead(channel);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
channel.closeSocket();
|
channel.closeSocket();
|
||||||
if (channel.setClosed()) {
|
if (channel.setClosed()) {
|
||||||
@ -171,18 +179,34 @@ abstract class AbstractOioWorker<C extends AbstractOioChannel> implements Worker
|
|||||||
if (workerThread != null && currentThread != workerThread) {
|
if (workerThread != null && currentThread != workerThread) {
|
||||||
workerThread.interrupt();
|
workerThread.interrupt();
|
||||||
}
|
}
|
||||||
|
if (iothread) {
|
||||||
fireChannelDisconnected(channel);
|
fireChannelDisconnected(channel);
|
||||||
|
} else {
|
||||||
|
fireChannelDisconnectedLater(channel);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (bound) {
|
if (bound) {
|
||||||
|
if (iothread) {
|
||||||
fireChannelUnbound(channel);
|
fireChannelUnbound(channel);
|
||||||
|
} else {
|
||||||
|
fireChannelUnboundLater(channel);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (iothread) {
|
||||||
fireChannelClosed(channel);
|
fireChannelClosed(channel);
|
||||||
|
} else {
|
||||||
|
fireChannelClosedLater(channel);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
future.setSuccess();
|
future.setSuccess();
|
||||||
}
|
}
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
future.setFailure(t);
|
future.setFailure(t);
|
||||||
|
if (iothread) {
|
||||||
fireExceptionCaught(channel, t);
|
fireExceptionCaught(channel, t);
|
||||||
|
} else {
|
||||||
|
fireExceptionCaughtLater(channel, t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,6 +63,8 @@ class OioDatagramWorker extends AbstractOioWorker<OioDatagramChannel> {
|
|||||||
static void write(
|
static void write(
|
||||||
OioDatagramChannel channel, ChannelFuture future,
|
OioDatagramChannel channel, ChannelFuture future,
|
||||||
Object message, SocketAddress remoteAddress) {
|
Object message, SocketAddress remoteAddress) {
|
||||||
|
boolean iothread = isIoThead(channel);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ChannelBuffer buf = (ChannelBuffer) message;
|
ChannelBuffer buf = (ChannelBuffer) message;
|
||||||
int offset = buf.readerIndex();
|
int offset = buf.readerIndex();
|
||||||
@ -84,27 +86,45 @@ class OioDatagramWorker extends AbstractOioWorker<OioDatagramChannel> {
|
|||||||
packet.setSocketAddress(remoteAddress);
|
packet.setSocketAddress(remoteAddress);
|
||||||
}
|
}
|
||||||
channel.socket.send(packet);
|
channel.socket.send(packet);
|
||||||
|
if (iothread) {
|
||||||
fireWriteComplete(channel, length);
|
fireWriteComplete(channel, length);
|
||||||
|
} else {
|
||||||
|
fireWriteCompleteLater(channel, length);
|
||||||
|
}
|
||||||
future.setSuccess();
|
future.setSuccess();
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
future.setFailure(t);
|
future.setFailure(t);
|
||||||
|
if (iothread) {
|
||||||
fireExceptionCaught(channel, t);
|
fireExceptionCaught(channel, t);
|
||||||
|
} else {
|
||||||
|
fireExceptionCaughtLater(channel, t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void disconnect(OioDatagramChannel channel, ChannelFuture future) {
|
static void disconnect(OioDatagramChannel channel, ChannelFuture future) {
|
||||||
boolean connected = channel.isConnected();
|
boolean connected = channel.isConnected();
|
||||||
|
boolean iothread = isIoThead(channel);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
channel.socket.disconnect();
|
channel.socket.disconnect();
|
||||||
future.setSuccess();
|
future.setSuccess();
|
||||||
if (connected) {
|
if (connected) {
|
||||||
// Notify.
|
// Notify.
|
||||||
|
if (iothread) {
|
||||||
fireChannelDisconnected(channel);
|
fireChannelDisconnected(channel);
|
||||||
|
} else {
|
||||||
|
fireChannelDisconnectedLater(channel);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
future.setFailure(t);
|
future.setFailure(t);
|
||||||
|
if (iothread) {
|
||||||
fireExceptionCaught(channel, t);
|
fireExceptionCaught(channel, t);
|
||||||
|
} else {
|
||||||
|
fireExceptionCaughtLater(channel, t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,11 +65,16 @@ class OioWorker extends AbstractOioWorker<OioSocketChannel> {
|
|||||||
OioSocketChannel channel, ChannelFuture future,
|
OioSocketChannel channel, ChannelFuture future,
|
||||||
Object message) {
|
Object message) {
|
||||||
|
|
||||||
|
boolean iothread = isIoThead(channel);
|
||||||
OutputStream out = channel.getOutputStream();
|
OutputStream out = channel.getOutputStream();
|
||||||
if (out == null) {
|
if (out == null) {
|
||||||
Exception e = new ClosedChannelException();
|
Exception e = new ClosedChannelException();
|
||||||
future.setFailure(e);
|
future.setFailure(e);
|
||||||
|
if (iothread) {
|
||||||
fireExceptionCaught(channel, e);
|
fireExceptionCaught(channel, e);
|
||||||
|
} else {
|
||||||
|
fireExceptionCaughtLater(channel, e);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,7 +111,11 @@ class OioWorker extends AbstractOioWorker<OioSocketChannel> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (iothread) {
|
||||||
fireWriteComplete(channel, length);
|
fireWriteComplete(channel, length);
|
||||||
|
} else {
|
||||||
|
fireWriteCompleteLater(channel, length);
|
||||||
|
}
|
||||||
future.setSuccess();
|
future.setSuccess();
|
||||||
|
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
@ -118,7 +127,11 @@ class OioWorker extends AbstractOioWorker<OioSocketChannel> {
|
|||||||
t = new ClosedChannelException();
|
t = new ClosedChannelException();
|
||||||
}
|
}
|
||||||
future.setFailure(t);
|
future.setFailure(t);
|
||||||
|
if (iothread) {
|
||||||
fireExceptionCaught(channel, t);
|
fireExceptionCaught(channel, t);
|
||||||
|
} else {
|
||||||
|
fireExceptionCaughtLater(channel, t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user