Skip to content

Commit 294a391

Browse files
committed
Delete now useless system threads interrupts in finalizeContext
1 parent f22d8c8 commit 294a391

File tree

6 files changed

+33
-74
lines changed

6 files changed

+33
-74
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CApiContext.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -775,8 +775,6 @@ void runBackgroundGCTask(PythonContext context) {
775775
return;
776776
}
777777
backgroundGCTaskThread = context.createSystemThread(gcTask);
778-
backgroundGCTaskThread.setDaemon(true);
779-
backgroundGCTaskThread.setName("python-gc-task");
780778
backgroundGCTaskThread.start();
781779
}
782780

@@ -916,7 +914,8 @@ private void addNativeFinalizer(PythonContext context, Object finalizingPointerO
916914
long finalizingPointer = lib.asPointer(finalizingPointerObj);
917915
// We are writing off heap memory and registering a VM shutdown hook, there is no
918916
// point in creating this thread via Truffle sandbox at this point
919-
nativeFinalizerShutdownHook = new Thread(() -> unsafe.putInt(finalizingPointer, 1));
917+
nativeFinalizerRunnable = () -> unsafe.putInt(finalizingPointer, 1);
918+
nativeFinalizerShutdownHook = new Thread(nativeFinalizerRunnable);
920919
Runtime.getRuntime().addShutdownHook(nativeFinalizerShutdownHook);
921920
} catch (UnsupportedMessageException e) {
922921
throw new RuntimeException(e);
@@ -957,14 +956,16 @@ public void exitCApiContext() {
957956
@SuppressWarnings("try")
958957
public void finalizeCApi() {
959958
CompilerAsserts.neverPartOfCompilation();
960-
HandleContext handleContext = getContext().nativeContext;
959+
PythonContext context = getContext();
960+
HandleContext handleContext = context.nativeContext;
961961
if (backgroundGCTaskThread != null && backgroundGCTaskThread.isAlive()) {
962+
context.killSystemThread(backgroundGCTaskThread);
962963
try {
963-
backgroundGCTaskThread.interrupt();
964-
backgroundGCTaskThread.join();
964+
backgroundGCTaskThread.join(10);
965965
} catch (InterruptedException e) {
966-
Thread.currentThread().interrupt();
966+
LOGGER.finest("got interrupt while joining GC thread before cleaning up C API state");
967967
}
968+
backgroundGCTaskThread = null;
968969
}
969970

970971
/*

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/hpy/GraalHPyContext.java

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,6 @@ public enum LLVMType {
421421
public final AtomicReference<GraalHPyHandleReference> references = new AtomicReference<>(null);
422422
private ReferenceQueue<Object> nativeSpaceReferenceQueue;
423423
@CompilationFinal private RootCallTarget referenceCleanerCallTarget;
424-
private Thread hpyReferenceCleanerThread;
425424

426425
private long nativeSpacePointers;
427426

@@ -1141,9 +1140,7 @@ private ReferenceQueue<Object> createReferenceQueue() {
11411140
PythonContext context = getContext();
11421141
Env env = context.getEnv();
11431142
if (env.isCreateThreadAllowed()) {
1144-
Thread thread = context.createSystemThread(new GraalHPyReferenceCleanerRunnable(referenceQueue));
1145-
thread.start();
1146-
hpyReferenceCleanerThread = thread;
1143+
context.createSystemThread(new GraalHPyReferenceCleanerRunnable(referenceQueue)).start();
11471144
} else {
11481145
context.registerAsyncAction(() -> {
11491146
Reference<?> reference = null;
@@ -1196,17 +1193,6 @@ public Object getNativeNull() {
11961193
* Join the reference cleaner thread.
11971194
*/
11981195
public void finalizeContext() {
1199-
Thread thread = this.hpyReferenceCleanerThread;
1200-
if (thread != null) {
1201-
if (thread.isAlive() && !thread.isInterrupted()) {
1202-
thread.interrupt();
1203-
}
1204-
try {
1205-
thread.join();
1206-
} catch (InterruptedException e) {
1207-
// ignore
1208-
}
1209-
}
12101196
backend.finalizeNativeContext();
12111197
if (nativeArgumentsStack != 0) {
12121198
UNSAFE.freeMemory(nativeArgumentsStack);

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/NativeBufferContext.java

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,6 @@ public class NativeBufferContext {
6767
// Storing references here to keep them alive
6868
private ConcurrentHashMap<NativePrimitiveReference, NativePrimitiveReference> phantomReferences;
6969

70-
private Thread nativeBufferReferenceCleanerThread;
71-
7270
@TruffleBoundary
7371
public void initReferenceQueue() {
7472
var context = PythonContext.get(null);
@@ -77,9 +75,7 @@ public void initReferenceQueue() {
7775
TruffleLanguage.Env env = context.getEnv();
7876
if (env.isCreateThreadAllowed()) {
7977
var runnable = new NativeBufferDeallocatorRunnable(referenceQueue, this.phantomReferences);
80-
Thread thread = context.createSystemThread(runnable);
81-
thread.start();
82-
this.nativeBufferReferenceCleanerThread = thread;
78+
context.createSystemThread(runnable).start();
8379
}
8480
}
8581

@@ -92,20 +88,6 @@ public NativeIntSequenceStorage createNativeIntStorage(NativeBuffer valueBuffer,
9288
return storage;
9389
}
9490

95-
public void finalizeContext() {
96-
Thread thread = this.nativeBufferReferenceCleanerThread;
97-
if (thread != null) {
98-
if (thread.isAlive() && !thread.isInterrupted()) {
99-
thread.interrupt();
100-
}
101-
try {
102-
thread.join();
103-
} catch (InterruptedException e) {
104-
// ignore
105-
}
106-
}
107-
}
108-
10991
public NativeIntSequenceStorage toNativeIntStorage(int[] arr) {
11092
long sizeInBytes = (long) arr.length * (long) Integer.BYTES;
11193
NativeBuffer nativeBuffer = NativeBuffer.allocateNew(sizeInBytes);

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonContext.java

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2089,7 +2089,6 @@ public void finalizeContext() {
20892089
// interrupt and join or kill system threads
20902090
joinSystemThreads();
20912091
cleanupHPyResources();
2092-
nativeBufferContext.finalizeContext();
20932092
for (int fd : getChildContextFDs()) {
20942093
if (!getSharedMultiprocessingData().decrementFDRefCount(fd)) {
20952094
getSharedMultiprocessingData().closePipe(fd);
@@ -2305,13 +2304,7 @@ private void joinSystemThreads() {
23052304
LOGGER.finest("joining thread " + thread);
23062305
int tries = 100;
23072306
for (int i = 0; i < tries && thread.isAlive(); i++) {
2308-
env.submitThreadLocal(new Thread[]{thread}, new ThreadLocalAction(true, false) {
2309-
@Override
2310-
protected void perform(ThreadLocalAction.Access access) {
2311-
throw new PythonThreadKillException();
2312-
}
2313-
});
2314-
thread.interrupt();
2307+
killSystemThread(thread);
23152308
try {
23162309
thread.join(tries - i);
23172310
} catch (InterruptedException e) {
@@ -2343,6 +2336,16 @@ public Thread createSystemThread(PythonSystemThreadTask task) {
23432336
return thread;
23442337
}
23452338

2339+
public void killSystemThread(Thread thread) {
2340+
env.submitThreadLocal(new Thread[]{thread}, new ThreadLocalAction(true, false) {
2341+
@Override
2342+
protected void perform(ThreadLocalAction.Access access) {
2343+
throw new PythonThreadKillException();
2344+
}
2345+
});
2346+
thread.interrupt();
2347+
}
2348+
23462349
public void initializeMainModule(TruffleString path) {
23472350
if (path != null) {
23482351
mainModule.setAttribute(T___FILE__, path);

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/exception/PythonThreadKillException.java

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242

4343
import com.oracle.truffle.api.TruffleSafepoint.Interruptible;
4444
import com.oracle.truffle.api.nodes.Node;
45-
import org.graalvm.polyglot.PolyglotException;
4645

4746
/**
4847
* This exception kills a Python thread.
@@ -93,18 +92,4 @@ public PythonThreadKillException() {
9392
public final Throwable fillInStackTrace() {
9493
return this;
9594
}
96-
97-
/**
98-
* Helper method for threads that do not run Python code and should gracefully terminate on
99-
* catching {@link PythonThreadKillException} and some types of Polyglot exception thrown from
100-
* Thread Location Actions run in Truffle Sefepoint.
101-
*/
102-
public static boolean shouldKillThread(Throwable ex) {
103-
if (ex instanceof PythonThreadKillException) {
104-
return true;
105-
} else if (ex instanceof PolyglotException pex) {
106-
return pex.isCancelled() || pex.isInterrupted();
107-
}
108-
return false;
109-
}
11095
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/util/PythonSystemThreadTask.java

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,11 @@
4040
*/
4141
package com.oracle.graal.python.util;
4242

43+
import java.util.logging.Level;
44+
4345
import com.oracle.graal.python.runtime.exception.PythonThreadKillException;
4446
import com.oracle.truffle.api.TruffleLogger;
4547

46-
import java.util.logging.Level;
47-
4848
/**
4949
* Base class for runnables of "system" threads that handle some internal aspects of the Python
5050
* runtime. The thread should be created using
@@ -55,8 +55,9 @@
5555
* shutdown is through sending Java interrupt and submitting a Thread Local Action (TLA) that throws
5656
* {@link PythonThreadKillException}. The Java interrupt should interrupt any blocking operation,
5757
* which should then poll a safepoint. This wrapper takes care of handling
58-
* {@link PythonThreadKillException} gracefully as well as other exception types that Truffle itself
59-
* may submit through TLA to shut down the thread.
58+
* {@link PythonThreadKillException} gracefully. Note that Truffle may also shut down this thread
59+
* via TLA that throws its own internal cancellation exception, which is handled in Truffle internal
60+
* code that wraps this Runnable.
6061
*/
6162
public abstract class PythonSystemThreadTask implements Runnable {
6263
private final String name;
@@ -75,14 +76,15 @@ public String getName() {
7576
public final void run() {
7677
try {
7778
doRun();
79+
logger.fine(() -> String.format("'%s' finished", name));
80+
} catch (PythonThreadKillException ex) {
81+
logger.fine(() -> String.format("%s killed with exception '%s'", name, PythonThreadKillException.class.getSimpleName()));
7882
} catch (Throwable ex) {
79-
if (PythonThreadKillException.shouldKillThread(ex)) {
80-
logger.fine(() -> String.format("%s killed with exception %s", name, ex));
81-
} else {
82-
logger.log(Level.WARNING, ex, () -> String.format("Unhandled exception %s in %s", ex.getClass().getSimpleName(), name));
83-
}
83+
// Note: Truffle wraps this Runnable in its own Runnable that handles Truffle's own
84+
// internal cancellation exception that is submitted via TLA
85+
logger.log(Level.FINE, String.format("Unhandled exception %s in thread '%s'", ex.getClass().getSimpleName(), name), ex);
86+
throw ex;
8487
}
85-
logger.fine(() -> String.format("%s finished", name));
8688
}
8789

8890
protected abstract void doRun();

0 commit comments

Comments
 (0)