[#3848] Respect EPOLLERR event

Motivation:

Some glibc/kernel versions will trigger an EPOLLERR event to notify
about failed connect and not an EPOLLOUT. Also EPOLLERR may be triggered
when a connection is broke.

Modification:

React on EPOLLERR like if an EPOLLOUT / EPOLLIN was received, this will work in
all cases as we handle errors in EPOLLOUT / EPOLLIN anyway.

Result:

Correctly detect errors.
This commit is contained in:
Norman Maurer 2015-06-01 21:17:51 +02:00
parent 455682cae0
commit f51465977e
4 changed files with 21 additions and 2 deletions

View File

@ -1615,6 +1615,10 @@ JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_epollrdhup(JNIEnv* env
return EPOLLRDHUP; return EPOLLRDHUP;
} }
JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_epollerr(JNIEnv* env, jclass clazz) {
return EPOLLERR;
}
JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_sizeofEpollEvent(JNIEnv* env, jclass clazz) { JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_sizeofEpollEvent(JNIEnv* env, jclass clazz) {
return sizeof(struct epoll_event); return sizeof(struct epoll_event);
} }

View File

@ -121,6 +121,7 @@ jint Java_io_netty_channel_epoll_Native_epollin(JNIEnv* env, jclass clazz);
jint Java_io_netty_channel_epoll_Native_epollout(JNIEnv* env, jclass clazz); jint Java_io_netty_channel_epoll_Native_epollout(JNIEnv* env, jclass clazz);
jint Java_io_netty_channel_epoll_Native_epollrdhup(JNIEnv* env, jclass clazz); jint Java_io_netty_channel_epoll_Native_epollrdhup(JNIEnv* env, jclass clazz);
jint Java_io_netty_channel_epoll_Native_epollet(JNIEnv* env, jclass clazz); jint Java_io_netty_channel_epoll_Native_epollet(JNIEnv* env, jclass clazz);
jint Java_io_netty_channel_epoll_Native_epollerr(JNIEnv* env, jclass clazz);
jint Java_io_netty_channel_epoll_Native_sizeofEpollEvent(JNIEnv* env, jclass clazz); jint Java_io_netty_channel_epoll_Native_sizeofEpollEvent(JNIEnv* env, jclass clazz);
jint Java_io_netty_channel_epoll_Native_offsetofEpollData(JNIEnv* env, jclass clazz); jint Java_io_netty_channel_epoll_Native_offsetofEpollData(JNIEnv* env, jclass clazz);

View File

@ -317,10 +317,18 @@ final class EpollEventLoop extends SingleThreadEventLoop {
// past. // past.
AbstractEpollUnsafe unsafe = (AbstractEpollUnsafe) ch.unsafe(); AbstractEpollUnsafe unsafe = (AbstractEpollUnsafe) ch.unsafe();
// Check if an error was the cause of the wakeup.
boolean err = (ev & Native.EPOLLERR) != 0;
// First check for EPOLLOUT as we may need to fail the connect ChannelPromise before try // First check for EPOLLOUT as we may need to fail the connect ChannelPromise before try
// to read from the file descriptor. // to read from the file descriptor.
// See https://github.com/netty/netty/issues/3785 // See https://github.com/netty/netty/issues/3785
if ((ev & Native.EPOLLOUT) != 0 && ch.isOpen()) { //
// It is possible for an EPOLLOUT or EPOLLERR to be generated when a connection is refused.
// In either case epollOutReady() will do the correct thing (finish connecting, or fail
// the connection).
// See https://github.com/netty/netty/issues/3848
if (err || ((ev & Native.EPOLLOUT) != 0) && ch.isOpen()) {
// Force flush of data as the epoll is writable again // Force flush of data as the epoll is writable again
unsafe.epollOutReady(); unsafe.epollOutReady();
} }
@ -331,7 +339,11 @@ final class EpollEventLoop extends SingleThreadEventLoop {
if ((ev & Native.EPOLLRDHUP) != 0) { if ((ev & Native.EPOLLRDHUP) != 0) {
unsafe.epollRdHupReady(); unsafe.epollRdHupReady();
} }
if ((ev & Native.EPOLLIN) != 0 && ch.isOpen()) {
// If EPOLLOUT or EPOLLING was received and the channel is still open call epollInReady().
// This will try to read from the underlying filedescriptor and so notify the user about the
// error.
if ((err || (ev & Native.EPOLLIN) != 0) && ch.isOpen()) {
// The Channel is still open and there is something to read. Do it now. // The Channel is still open and there is something to read. Do it now.
unsafe.epollInReady(); unsafe.epollInReady();
} }

View File

@ -55,6 +55,7 @@ public final class Native {
public static final int EPOLLOUT = epollout(); public static final int EPOLLOUT = epollout();
public static final int EPOLLRDHUP = epollrdhup(); public static final int EPOLLRDHUP = epollrdhup();
public static final int EPOLLET = epollet(); public static final int EPOLLET = epollet();
public static final int EPOLLERR = epollerr();
public static final int IOV_MAX = iovMax(); public static final int IOV_MAX = iovMax();
public static final int UIO_MAX_IOV = uioMaxIov(); public static final int UIO_MAX_IOV = uioMaxIov();
@ -701,6 +702,7 @@ public final class Native {
private static native int epollout(); private static native int epollout();
private static native int epollrdhup(); private static native int epollrdhup();
private static native int epollet(); private static native int epollet();
private static native int epollerr();
private static native long ssizeMax(); private static native long ssizeMax();
private Native() { private Native() {