Skip to content

Commit

Permalink
Use custom thread factory for NIO
Browse files Browse the repository at this point in the history
NIO async IO uses a custom thread pool, this allows us to update the
TCCL in dev mode.

Fixes quarkusio#20973
  • Loading branch information
stuartwdouglas committed Oct 26, 2021
1 parent 834ed9d commit 6c708fe
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,9 @@ public void close() {
//the main entry point, but loaded inside the augmentation class loader
@Override
public void accept(CuratedApplication o, Map<String, Object> params) {
//setup the dev mode thread pool for NIO
System.setProperty("java.nio.channels.DefaultThreadPool.threadFactory",
"io.quarkus.dev.io.NioThreadPoolThreadFactory");
Timing.staticInitStarted(o.getBaseRuntimeClassLoader(), false);
//https://github.com/quarkusio/quarkus/issues/9748
//if you have an app with all daemon threads then the app thread
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ public void close() {
//the main entry point, but loaded inside the augmentation class loader
@Override
public void accept(CuratedApplication o, Map<String, Object> params) {
System.setProperty("java.nio.channels.DefaultThreadPool.threadFactory",
"io.quarkus.dev.io.NioThreadPoolThreadFactory");
Timing.staticInitStarted(o.getBaseRuntimeClassLoader(), false);
try {
curatedApplication = o;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package io.quarkus.deployment.dev.io;

import io.quarkus.deployment.IsNormal;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.annotations.ExecutionTime;
import io.quarkus.deployment.annotations.Produce;
import io.quarkus.deployment.annotations.Record;
import io.quarkus.deployment.builditem.ShutdownContextBuildItem;
import io.quarkus.deployment.dev.testing.TestSetupBuildItem;
import io.quarkus.runtime.dev.io.NioThreadPoolRecorder;

public class NioThreadPoolDevModeProcessor {

@Produce(TestSetupBuildItem.class)
@BuildStep(onlyIfNot = IsNormal.class)
@Record(ExecutionTime.STATIC_INIT)
void setupTCCL(NioThreadPoolRecorder recorder, ShutdownContextBuildItem shutdownContextBuildItem) {
recorder.updateTccl(shutdownContextBuildItem);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package io.quarkus.dev.io;

import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicReference;

/**
* We need to be able to update the TCCL of the NIO default thread pool in dev/test mode
* <p>
* This class lets us to that.
*/
public class NioThreadPoolThreadFactory implements ThreadFactory {

private static final CopyOnWriteArrayList<Thread> allThreads = new CopyOnWriteArrayList<>();
private static volatile ClassLoader currentCl = Thread.currentThread().getContextClassLoader();

@Override
public Thread newThread(Runnable r) {
AtomicReference<Thread> t = new AtomicReference<>();
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
r.run();
} finally {
allThreads.remove(t.get());
}
}
}, "NIO IO Thread (created by Quarkus)");
t.set(thread);
thread.setDaemon(true);
allThreads.add(thread);
thread.setContextClassLoader(currentCl);
return thread;
}

public static ClassLoader updateTccl(ClassLoader cl) {
ClassLoader old = currentCl;
currentCl = cl;
for (Thread i : allThreads) {
i.setContextClassLoader(cl);
}
return old;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package io.quarkus.runtime.dev.io;

import io.quarkus.dev.io.NioThreadPoolThreadFactory;
import io.quarkus.runtime.ShutdownContext;
import io.quarkus.runtime.annotations.Recorder;

@Recorder
public class NioThreadPoolRecorder {

public void updateTccl(ShutdownContext context) {
ClassLoader old = NioThreadPoolThreadFactory.updateTccl(Thread.currentThread().getContextClassLoader());
context.addLastShutdownTask(new Runnable() {
@Override
public void run() {
NioThreadPoolThreadFactory.updateTccl(old);
}
});
}
}

0 comments on commit 6c708fe

Please sign in to comment.