Skip to content

Commit

Permalink
Check and interrupt the common pool better to prevent malfunction
Browse files Browse the repository at this point in the history
Common pool workers have a fixed name, and therefore, we can identify
them based on their names. The old approach using the thread groups was
faulty because the thread group depends on whether the common pool was
started with SecruityManager. Since this differs for IDEs and Build
Tools or even test execution, we cannot rely on the thread group and
just use the name instead.
In addition to that, we switch to interrupting only common pool threads
that are executing non-whitelisted code to avoid interrupting common
pool workers that are already idle.
  • Loading branch information
MaisiKoleni committed Dec 7, 2021
1 parent 7a5569d commit 72877c6
Showing 1 changed file with 17 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,9 @@ public final class ArtemisSecurityManager extends SecurityManager {
private static final Pattern RECURSIVE_FILE_PERMISSION = Pattern.compile("[/\\\\][-*]$"); //$NON-NLS-1$
private static final String LOCALHOST = "localhost"; //$NON-NLS-1$
private static final Predicate<StackFrame> IGNORE_ACCESS_PRIVILEGED = stackframe -> true;
private static final Set<String> THREAD_NAME_BLACKLIST = Set.of("ForkJoinPool.commonPool", "Finalizer", //$NON-NLS-1$ //$NON-NLS-2$
"InnocuousThread"); //$NON-NLS-1$
private static final String COMMON_POOL_THREAD_NAME = "ForkJoinPool.commonPool"; //$NON-NLS-1$
private static final Set<String> THREAD_NAME_BLACKLIST = Set.of(COMMON_POOL_THREAD_NAME, "Finalizer", //$NON-NLS-1$
"InnocuousThread", "Common-Cleaner"); //$NON-NLS-1$ //$NON-NLS-2$
private static final MessageDigest SHA256;
static {
try {
Expand Down Expand Up @@ -647,18 +648,22 @@ private void checkCommonThreadPool() {
LOG.debug("Common pool is active: {} with number {} workers", !commonPool.isQuiescent(), //$NON-NLS-1$
commonPool.getActiveThreadCount());
var rootThreadGroup = getRootThreadGroup(); // NOSONAR
var allThreadGroups = new ThreadGroup[rootThreadGroup.activeGroupCount() + 5];
rootThreadGroup.enumerate(allThreadGroups, true);
ThreadGroup commong = Stream.of(allThreadGroups)
.filter(tg -> "InnocuousForkJoinWorkerThreadGroup".equals(tg.getName())) //$NON-NLS-1$
.findFirst().orElseThrow(IllegalStateException::new); // was created indirectly in the static
// initializer
var threads = new Thread[commong.activeCount() + 5];
commong.enumerate(threads);
// have some buffer in case the count changes
// (does not need to be massive due to blockThreadCreation being true)
var allThreads = new Thread[rootThreadGroup.activeCount() + 32];
rootThreadGroup.enumerate(allThreads, true);
var threads = Stream.of(allThreads).filter(Objects::nonNull)
.filter(t -> t.getName().contains(COMMON_POOL_THREAD_NAME)).toArray(Thread[]::new);

LOG.info("Try interrupt common pool"); //$NON-NLS-1$
for (Thread thread : threads) {
if (thread != null && thread.isAlive()) { // $NON-NLS-1$
thread.interrupt();
if (thread.isAlive()) { // $NON-NLS-1$
// We look which workers might be executing student code
var notIdle = Stream.of(thread.getStackTrace()).anyMatch(this::isStackFrameNotWhitelisted);
if (notIdle) {
LOG.info("Interrupting non-whitelsited code executing common pool worker: {}", thread); //$NON-NLS-1$
thread.interrupt();
}
}
}
try {
Expand Down

0 comments on commit 72877c6

Please sign in to comment.