Repository: quarkusio/quarkus
Issue: 100% CPU in epoll_wait

**Describe the bug**
In some environments, using native image, all threads reading I/O can spend 100% CPU time polling `epoll_wait(..., timeout=0)`. Turns out this is an effect of `static final io.netty.util.concurrent.ScheduledFutureTask.START_TIME` being set to system-dependent `System.nanoTime()` during compilation and the NioEventLoop behaving in an unexpected way.

Note that this behaviour cannot be reproduced when compiling and running on the same machine, due to the nature of `System.nanoTime()` base value.

Changed files:
extensions/netty/deployment/src/main/java/io/quarkus/netty/deployment/NettyProcessor.java
extensions/netty/runtime/src/main/java/io/quarkus/netty/runtime/graal/NettySubstitutions.java

diff --git a/extensions/netty/deployment/src/main/java/io/quarkus/netty/deployment/NettyProcessor.java b/extensions/netty/deployment/src/main/java/io/quarkus/netty/deployment/NettyProcessor.java
index bcea7cd2864..eb190661974 100644
--- a/extensions/netty/deployment/src/main/java/io/quarkus/netty/deployment/NettyProcessor.java
+++ b/extensions/netty/deployment/src/main/java/io/quarkus/netty/deployment/NettyProcessor.java
@@ -18,6 +18,7 @@
 import io.quarkus.deployment.builditem.JniBuildItem;
 import io.quarkus.deployment.builditem.SystemPropertyBuildItem;
 import io.quarkus.deployment.builditem.substrate.ReflectiveClassBuildItem;
+import io.quarkus.deployment.builditem.substrate.RuntimeReinitializedClassBuildItem;
 import io.quarkus.deployment.builditem.substrate.SubstrateConfigBuildItem;
 import io.quarkus.deployment.builditem.substrate.SubstrateSystemPropertyBuildItem;
 import io.quarkus.netty.BossEventLoopGroup;
@@ -162,4 +163,10 @@ void createExecutors(BuildProducer<RuntimeBeanBuildItem> runtimeBeanBuildItemBui
                 .build());
     }
 
+    @BuildStep
+    public RuntimeReinitializedClassBuildItem reinitScheduledFutureTask() {
+        return new RuntimeReinitializedClassBuildItem(
+                "io.quarkus.netty.runtime.graal.Holder_io_netty_util_concurrent_ScheduledFutureTask");
+    }
+
 }
diff --git a/extensions/netty/runtime/src/main/java/io/quarkus/netty/runtime/graal/NettySubstitutions.java b/extensions/netty/runtime/src/main/java/io/quarkus/netty/runtime/graal/NettySubstitutions.java
index da0521e7f6e..27b179bb9a7 100644
--- a/extensions/netty/runtime/src/main/java/io/quarkus/netty/runtime/graal/NettySubstitutions.java
+++ b/extensions/netty/runtime/src/main/java/io/quarkus/netty/runtime/graal/NettySubstitutions.java
@@ -12,6 +12,7 @@
 import javax.net.ssl.TrustManagerFactory;
 
 import com.oracle.svm.core.annotate.Alias;
+import com.oracle.svm.core.annotate.Delete;
 import com.oracle.svm.core.annotate.RecomputeFieldValue;
 import com.oracle.svm.core.annotate.Substitute;
 import com.oracle.svm.core.annotate.TargetClass;
@@ -333,6 +334,33 @@ final class Target_io_netty_util_AbstractReferenceCounted {
     private static long REFCNT_FIELD_OFFSET;
 }
 
+// This class is runtime-initialized by NettyProcessor
+final class Holder_io_netty_util_concurrent_ScheduledFutureTask {
+    static final long START_TIME = System.nanoTime();
+}
+
+@TargetClass(className = "io.netty.util.concurrent.ScheduledFutureTask")
+final class Target_io_netty_util_concurrent_ScheduledFutureTask {
+    @Delete
+    public static long START_TIME = 0;
+
+    @Substitute
+    static long nanoTime() {
+        return System.nanoTime() - Holder_io_netty_util_concurrent_ScheduledFutureTask.START_TIME;
+    }
+
+    @Alias
+    public long deadlineNanos() {
+        return 0;
+    }
+
+    @Substitute
+    public long delayNanos(long currentTimeNanos) {
+        return Math.max(0,
+                deadlineNanos() - (currentTimeNanos - Holder_io_netty_util_concurrent_ScheduledFutureTask.START_TIME));
+    }
+}
+
 class NettySubstitutions {
 
 }