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 a2707d96a9..33adf86279 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 @@ -35,7 +35,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Queue; -import java.util.concurrent.Callable; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; @@ -44,7 +43,7 @@ import static java.lang.Math.min; /** * {@link EventLoop} which uses epoll under the covers. Only works on Linux! */ -final class EpollEventLoop extends SingleThreadEventLoop { +class EpollEventLoop extends SingleThreadEventLoop { private static final InternalLogger logger = InternalLoggerFactory.getInstance(EpollEventLoop.class); private static final AtomicIntegerFieldUpdater WAKEN_UP_UPDATER = AtomicIntegerFieldUpdater.newUpdater(EpollEventLoop.class, "wakenUp"); @@ -75,6 +74,7 @@ final class EpollEventLoop extends SingleThreadEventLoop { return epollWaitNow(); } }; + @SuppressWarnings("unused") // AtomicIntegerFieldUpdater private volatile int wakenUp; private volatile int ioRatio = 50; @@ -248,7 +248,7 @@ final class EpollEventLoop extends SingleThreadEventLoop { long totalDelay = delayNanos(System.nanoTime()); prevDeadlineNanos = curDeadlineNanos; delaySeconds = (int) min(totalDelay / 1000000000L, Integer.MAX_VALUE); - delayNanos = (int) min(totalDelay - delaySeconds * 1000000000L, Integer.MAX_VALUE); + delayNanos = (int) min(totalDelay - delaySeconds * 1000000000L, MAX_SCHEDULED_TIMERFD_NS); } return Native.epollWait(epollFd, events, timerFd, delaySeconds, delayNanos); } @@ -356,7 +356,10 @@ final class EpollEventLoop extends SingleThreadEventLoop { } } - private static void handleLoopException(Throwable t) { + /** + * Visible only for testing! + */ + void handleLoopException(Throwable t) { logger.warn("Unexpected exception in the selector loop.", t); // Prevent possible consecutive immediate failures that lead to diff --git a/transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollEventLoopTest.java b/transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollEventLoopTest.java index ebf529f732..4e51114422 100644 --- a/transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollEventLoopTest.java +++ b/transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollEventLoopTest.java @@ -15,32 +15,52 @@ */ package io.netty.channel.epoll; +import io.netty.channel.DefaultSelectStrategyFactory; import io.netty.channel.EventLoop; import io.netty.channel.EventLoopGroup; +import io.netty.util.concurrent.DefaultThreadFactory; import io.netty.util.concurrent.Future; +import io.netty.util.concurrent.RejectedExecutionHandlers; +import io.netty.util.concurrent.ThreadPerTaskExecutor; import org.junit.Test; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; public class EpollEventLoopTest { @Test public void testScheduleBigDelayNotOverflow() { - EventLoopGroup group = new EpollEventLoopGroup(1); + final AtomicReference capture = new AtomicReference(); - final EventLoop el = group.next(); - Future future = el.schedule(new Runnable() { + final EventLoopGroup group = new EpollEventLoop(null, + new ThreadPerTaskExecutor(new DefaultThreadFactory(getClass())), 0, + DefaultSelectStrategyFactory.INSTANCE.newSelectStrategy(), RejectedExecutionHandlers.reject()) { @Override - public void run() { - // NOOP + void handleLoopException(Throwable t) { + capture.set(t); + super.handleLoopException(t); } - }, Long.MAX_VALUE, TimeUnit.MILLISECONDS); + }; - assertFalse(future.awaitUninterruptibly(1000)); - assertTrue(future.cancel(true)); - group.shutdownGracefully(); + try { + final EventLoop eventLoop = group.next(); + Future future = eventLoop.schedule(new Runnable() { + @Override + public void run() { + // NOOP + } + }, Long.MAX_VALUE, TimeUnit.MILLISECONDS); + + assertFalse(future.awaitUninterruptibly(1000)); + assertTrue(future.cancel(true)); + assertNull(capture.get()); + } finally { + group.shutdownGracefully(); + } } }