diff --git a/transport-native-epoll/src/main/c/io_netty_channel_epoll_Native.c b/transport-native-epoll/src/main/c/io_netty_channel_epoll_Native.c index 1454f69e33..1886b37556 100644 --- a/transport-native-epoll/src/main/c/io_netty_channel_epoll_Native.c +++ b/transport-native-epoll/src/main/c/io_netty_channel_epoll_Native.c @@ -686,27 +686,30 @@ JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_epollWait0(JNIEnv* env return ready; } -JNIEXPORT void JNICALL Java_io_netty_channel_epoll_Native_epollCtlAdd(JNIEnv* env, jclass clazz, jint efd, jint fd, jint flags) { - if (epollCtl(env, efd, EPOLL_CTL_ADD, fd, flags) < 0) { - int err = errno; - throwRuntimeException(env, exceptionMessage("epoll_ctl() failed: ", err)); +JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_epollCtlAdd0(JNIEnv* env, jclass clazz, jint efd, jint fd, jint flags) { + int res = epollCtl(env, efd, EPOLL_CTL_ADD, fd, flags); + if (res < 0) { + return -errno; } + return res; } -JNIEXPORT void JNICALL Java_io_netty_channel_epoll_Native_epollCtlMod(JNIEnv* env, jclass clazz, jint efd, jint fd, jint flags) { - if (epollCtl(env, efd, EPOLL_CTL_MOD, fd, flags) < 0) { - int err = errno; - throwRuntimeException(env, exceptionMessage("epoll_ctl() failed: ", err)); +JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_epollCtlMod0(JNIEnv* env, jclass clazz, jint efd, jint fd, jint flags) { + int res = epollCtl(env, efd, EPOLL_CTL_MOD, fd, flags); + if (res < 0) { + return -errno; } + return res; } -JNIEXPORT void JNICALL Java_io_netty_channel_epoll_Native_epollCtlDel(JNIEnv* env, jclass clazz, jint efd, jint fd) { +JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_epollCtlDel0(JNIEnv* env, jclass clazz, jint efd, jint fd) { // Create an empty event to workaround a bug in older kernels which can not handle NULL. struct epoll_event event = { 0 }; - if (epoll_ctl(efd, EPOLL_CTL_DEL, fd, &event) < 0) { - int err = errno; - throwRuntimeException(env, exceptionMessage("epoll_ctl() failed: ", err)); + int res = epoll_ctl(efd, EPOLL_CTL_DEL, fd, &event); + if (res < 0) { + return -errno; } + return res; } static inline jint _write(JNIEnv* env, jclass clazz, jint fd, void* buffer, jint pos, jint limit) { diff --git a/transport-native-epoll/src/main/c/io_netty_channel_epoll_Native.h b/transport-native-epoll/src/main/c/io_netty_channel_epoll_Native.h index 1472b36f60..113a6e17ea 100644 --- a/transport-native-epoll/src/main/c/io_netty_channel_epoll_Native.h +++ b/transport-native-epoll/src/main/c/io_netty_channel_epoll_Native.h @@ -38,9 +38,9 @@ void Java_io_netty_channel_epoll_Native_eventFdWrite(JNIEnv* env, jclass clazz, void Java_io_netty_channel_epoll_Native_eventFdRead(JNIEnv* env, jclass clazz, jint fd); jint Java_io_netty_channel_epoll_Native_epollCreate(JNIEnv* env, jclass clazz); jint Java_io_netty_channel_epoll_Native_epollWait0(JNIEnv* env, jclass clazz, jint efd, jlong address, jint length, jint timeout); -void Java_io_netty_channel_epoll_Native_epollCtlAdd(JNIEnv* env, jclass clazz, jint efd, jint fd, jint flags); -void Java_io_netty_channel_epoll_Native_epollCtlMod(JNIEnv* env, jclass clazz, jint efd, jint fd, jint flags); -void Java_io_netty_channel_epoll_Native_epollCtlDel(JNIEnv* env, jclass clazz, jint efd, jint fd); +jint Java_io_netty_channel_epoll_Native_epollCtlAdd0(JNIEnv* env, jclass clazz, jint efd, jint fd, jint flags); +jint Java_io_netty_channel_epoll_Native_epollCtlMod0(JNIEnv* env, jclass clazz, jint efd, jint fd, jint flags); +jint Java_io_netty_channel_epoll_Native_epollCtlDel0(JNIEnv* env, jclass clazz, jint efd, jint fd); jint Java_io_netty_channel_epoll_Native_write0(JNIEnv* env, jclass clazz, jint fd, jobject jbuffer, jint pos, jint limit); jint Java_io_netty_channel_epoll_Native_writeAddress0(JNIEnv* env, jclass clazz, jint fd, jlong address, jint pos, jint limit); jlong Java_io_netty_channel_epoll_Native_writev0(JNIEnv* env, jclass clazz, jint fd, jobjectArray buffers, jint offset, jint length); diff --git a/transport-native-epoll/src/main/java/io/netty/channel/epoll/AbstractEpollChannel.java b/transport-native-epoll/src/main/java/io/netty/channel/epoll/AbstractEpollChannel.java index 82dd680a49..39adca2fb9 100644 --- a/transport-native-epoll/src/main/java/io/netty/channel/epoll/AbstractEpollChannel.java +++ b/transport-native-epoll/src/main/java/io/netty/channel/epoll/AbstractEpollChannel.java @@ -28,6 +28,7 @@ import io.netty.channel.unix.UnixChannel; import io.netty.util.ReferenceCountUtil; import io.netty.util.internal.OneTimeTask; +import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.UnresolvedAddressException; @@ -59,14 +60,14 @@ abstract class AbstractEpollChannel extends AbstractChannel implements UnixChann fileDescriptor = fd; } - void setFlag(int flag) { + void setFlag(int flag) throws IOException { if (!isFlagSet(flag)) { flags |= flag; modifyEvents(); } } - void clearFlag(int flag) { + void clearFlag(int flag) throws IOException { if (isFlagSet(flag)) { flags &= ~flag; modifyEvents(); @@ -160,7 +161,7 @@ abstract class AbstractEpollChannel extends AbstractChannel implements UnixChann } } - private void modifyEvents() { + private void modifyEvents() throws IOException { if (isOpen() && isRegistered()) { ((EpollEventLoop) eventLoop()).modify(this); } @@ -325,7 +326,15 @@ abstract class AbstractEpollChannel extends AbstractChannel implements UnixChann } protected final void clearEpollIn0() { - clearFlag(readFlag); + assert eventLoop().inEventLoop(); + try { + clearFlag(readFlag); + } catch (IOException e) { + // When this happens there is something completely wrong with either the filedescriptor or epoll, + // so fire the exception through the pipeline and close the Channel. + pipeline().fireExceptionCaught(e); + unsafe().close(unsafe().voidPromise()); + } } } } diff --git a/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollChannelConfig.java b/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollChannelConfig.java index 107274c773..9429315f24 100644 --- a/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollChannelConfig.java +++ b/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollChannelConfig.java @@ -16,11 +16,13 @@ package io.netty.channel.epoll; import io.netty.buffer.ByteBufAllocator; +import io.netty.channel.ChannelException; import io.netty.channel.ChannelOption; import io.netty.channel.DefaultChannelConfig; import io.netty.channel.MessageSizeEstimator; import io.netty.channel.RecvByteBufAllocator; +import java.io.IOException; import java.util.Map; public class EpollChannelConfig extends DefaultChannelConfig { @@ -133,7 +135,8 @@ public class EpollChannelConfig extends DefaultChannelConfig { if (mode == null) { throw new NullPointerException("mode"); } - switch (mode) { + try { + switch (mode) { case EDGE_TRIGGERED: checkChannelNotRegistered(); channel.setFlag(Native.EPOLLET); @@ -143,7 +146,10 @@ public class EpollChannelConfig extends DefaultChannelConfig { channel.clearFlag(Native.EPOLLET); break; default: - throw new Error(); + throw new Error(); + } + } catch (IOException e) { + throw new ChannelException(e); } return this; } diff --git a/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollEventLoop.java b/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollEventLoop.java index b3bad00bcd..81063fe9dc 100644 --- a/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollEventLoop.java +++ b/transport-native-epoll/src/main/java/io/netty/channel/epoll/EpollEventLoop.java @@ -73,7 +73,11 @@ final class EpollEventLoop extends SingleThreadEventLoop { try { this.epollFd = epollFd = Native.epollCreate(); this.eventFd = eventFd = Native.eventFd(); - Native.epollCtlAdd(epollFd, eventFd, Native.EPOLLIN); + try { + Native.epollCtlAdd(epollFd, eventFd, Native.EPOLLIN); + } catch (IOException e) { + throw new IllegalStateException("Unable to add eventFd filedescriptor to epoll", e); + } success = true; } finally { if (!success) { @@ -106,7 +110,7 @@ final class EpollEventLoop extends SingleThreadEventLoop { /** * Register the given epoll with this {@link io.netty.channel.EventLoop}. */ - void add(AbstractEpollChannel ch) { + void add(AbstractEpollChannel ch) throws IOException { assert inEventLoop(); int fd = ch.fd().intValue(); Native.epollCtlAdd(epollFd, fd, ch.flags); @@ -116,15 +120,15 @@ final class EpollEventLoop extends SingleThreadEventLoop { /** * The flags of the given epoll was modified so update the registration */ - void modify(AbstractEpollChannel ch) { + void modify(AbstractEpollChannel ch) throws IOException { assert inEventLoop(); Native.epollCtlMod(epollFd, ch.fd().intValue(), ch.flags); } /** - * Deregister the given epoll from this {@link io.netty.channel.EventLoop}. + * Deregister the given epoll from this {@link EventLoop}. */ - void remove(AbstractEpollChannel ch) { + void remove(AbstractEpollChannel ch) throws IOException { assert inEventLoop(); if (ch.isOpen()) { @@ -326,7 +330,14 @@ final class EpollEventLoop extends SingleThreadEventLoop { } } else { // We received an event for an fd which we not use anymore. Remove it from the epoll_event set. - Native.epollCtlDel(epollFd, fd); + try { + Native.epollCtlDel(epollFd, fd); + } catch (IOException ignore) { + // This can happen but is nothing we need to worry about as we only try to delete + // the fd from the epoll set as we not found it in our mappings. So this call to + // epollCtlDel(...) is just to ensure we cleanup stuff and so may fail if it was + // deleted before or the file descriptor was closed before. + } } } } diff --git a/transport-native-epoll/src/main/java/io/netty/channel/epoll/Native.java b/transport-native-epoll/src/main/java/io/netty/channel/epoll/Native.java index c79d93a1a0..38c483c037 100644 --- a/transport-native-epoll/src/main/java/io/netty/channel/epoll/Native.java +++ b/transport-native-epoll/src/main/java/io/netty/channel/epoll/Native.java @@ -156,10 +156,29 @@ public final class Native { } private static native int epollWait0(int efd, long address, int len, int timeout); - public static native void epollCtlAdd(int efd, final int fd, final int flags); + public static void epollCtlAdd(int efd, final int fd, final int flags) throws IOException { + int res = epollCtlAdd0(efd, fd, flags); + if (res < 0) { + throw newIOException("epoll_ctl", res); + } + } + private static native int epollCtlAdd0(int efd, final int fd, final int flags); - public static native void epollCtlMod(int efd, final int fd, final int flags); - public static native void epollCtlDel(int efd, final int fd); + public static void epollCtlMod(int efd, final int fd, final int flags) throws IOException { + int res = epollCtlMod0(efd, fd, flags); + if (res < 0) { + throw newIOException("epoll_ctl", res); + } + } + private static native int epollCtlMod0(int efd, final int fd, final int flags); + + public static void epollCtlDel(int efd, final int fd) throws IOException { + int res = epollCtlDel0(efd, fd); + if (res < 0) { + throw newIOException("epoll_ctl", res); + } + } + private static native int epollCtlDel0(int efd, final int fd); private static native int errnoEBADF(); private static native int errnoEPIPE();