Skip to content

Commit

Permalink
Introduce a custom QuarkusForkJoinWorkerThread to controll the classl…
Browse files Browse the repository at this point in the history
…oader in the Fork/Join common pool
  • Loading branch information
Sanne committed Oct 7, 2021
1 parent 8f312f5 commit 5b25046
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.quarkus.deployment;

import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.builditem.SystemPropertyBuildItem;

public final class ForkJoinPoolProcessor {

@BuildStep
SystemPropertyBuildItem setProperty() {
return new SystemPropertyBuildItem("java.util.concurrent.ForkJoinPool.common.threadFactory",
"io.quarkus.bootstrap.forkjoin.QuarkusForkJoinWorkerThreadFactory");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ public void accept(BuildChainBuilder builder) {
resultMap.put("files", result);
final List<String> javaargs = new ArrayList<>();
javaargs.add("-Djava.util.logging.manager=org.jboss.logmanager.LogManager");
javaargs.add(
"-Djava.util.concurrent.ForkJoinPool.common.threadFactory=io.quarkus.bootstrap.forkjoin.QuarkusForkJoinWorkerThreadFactory");
resultMap.put("java-args", javaargs);
resultMap.put("main-class", buildResult.consume(MainClassBuildItem.class).getClassName());
if (nativeRequested) {
Expand Down
5 changes: 3 additions & 2 deletions core/runtime/src/main/java/io/quarkus/runtime/Quarkus.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import java.util.function.BiConsumer;

import org.jboss.logging.Logger;
import org.jboss.logmanager.LogManager;

import io.quarkus.launcher.QuarkusLauncher;

Expand Down Expand Up @@ -57,7 +56,9 @@ public static void run(Class<? extends QuarkusApplication> quarkusApplication, S
public static void run(Class<? extends QuarkusApplication> quarkusApplication, BiConsumer<Integer, Throwable> exitHandler,
String... args) {
try {
System.setProperty("java.util.logging.manager", LogManager.class.getName());
System.setProperty("java.util.logging.manager", "org.jboss.logmanager.LogManager");
System.setProperty("java.util.concurrent.ForkJoinPool.common.threadFactory",
"io.quarkus.bootstrap.forkjoin.QuarkusForkJoinWorkerThreadFactory");
//production and common dev mode path
//we already have an application, run it directly
Class<? extends Application> appClass = (Class<? extends Application>) Class.forName(Application.APP_CLASS_NAME,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package io.quarkus.bootstrap.forkjoin;

import io.quarkus.bootstrap.runner.RunnerClassLoader;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinWorkerThread;

public class QuarkusForkJoinWorkerThread extends ForkJoinWorkerThread {

private static volatile ClassLoader qClassloader;

protected QuarkusForkJoinWorkerThread(ForkJoinPool pool) {
super(pool);
}

public static synchronized void setQuarkusAppClassloader(RunnerClassLoader runnerClassLoader) {
if (qClassloader != null) {
throw new IllegalStateException("Attempting to set the Quarkus root classloader while it was already set");
}
if (runnerClassLoader == null) {
throw new IllegalStateException("Attempting to set the Quarkus root classloader to null");
}
qClassloader = runnerClassLoader;
}

protected void onStart() {
super.onStart();
if (qClassloader == null) {
throw new IllegalStateException(
"Fork Join pool initialization has been triggered before the application classloader has been initialized. "
+
"Use this stacktrace to figure out what triggered it, and avoid using the Fork Join pool this early during the boot process.");
} else {
super.setContextClassLoader(qClassloader);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package io.quarkus.bootstrap.forkjoin;

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinWorkerThread;

/**
* This implementation of JDK's ForkJoinPool.ForkJoinWorkerThreadFactory
* needs to be enabled by setting system property {@code java.util.concurrent.ForkJoinPool.common.threadFactory}
* to this class name, so to allow Quarkus to set the contextual classloader to the correct
* runtime classloader for each thread being started by the common pool.
* Otherwise the system classloader will be set, which is unable to load all application resources.
*/
public final class QuarkusForkJoinWorkerThreadFactory implements ForkJoinPool.ForkJoinWorkerThreadFactory {

public QuarkusForkJoinWorkerThreadFactory() {
}

@Override
public ForkJoinWorkerThread newThread(ForkJoinPool pool) {
return new QuarkusForkJoinWorkerThread(pool);
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.quarkus.bootstrap.runner;

import io.quarkus.bootstrap.forkjoin.QuarkusForkJoinWorkerThread;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
Expand All @@ -21,6 +22,8 @@ public class QuarkusEntryPoint {

public static void main(String... args) throws Throwable {
System.setProperty("java.util.logging.manager", org.jboss.logmanager.LogManager.class.getName());
System.setProperty("java.util.concurrent.ForkJoinPool.common.threadFactory",
"io.quarkus.bootstrap.forkjoin.QuarkusForkJoinWorkerThreadFactory");
Timing.staticInitStarted(false);
doRun(args);
}
Expand All @@ -44,6 +47,7 @@ private static void doRun(Object args) throws IOException, ClassNotFoundExceptio
}
try {
Thread.currentThread().setContextClassLoader(app.getRunnerClassLoader());
QuarkusForkJoinWorkerThread.setQuarkusAppClassloader(app.getRunnerClassLoader());
Class<?> mainClass = app.getRunnerClassLoader().loadClass(app.getMainClass());
mainClass.getMethod("main", String[].class).invoke(null, args);
} finally {
Expand Down

0 comments on commit 5b25046

Please sign in to comment.