Skip to content

Commit 34d72e4

Browse files
committed
Initialize native thread state before downcall
1 parent 0a0ec5e commit 34d72e4

4 files changed

Lines changed: 21 additions & 40 deletions

File tree

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

Lines changed: 5 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,7 @@
6262
import java.util.List;
6363
import java.util.Objects;
6464
import java.util.Set;
65-
import java.util.concurrent.CancellationException;
6665
import java.util.concurrent.ConcurrentHashMap;
67-
import java.util.concurrent.ExecutionException;
68-
import java.util.concurrent.Future;
69-
import java.util.concurrent.TimeUnit;
70-
import java.util.concurrent.TimeoutException;
7166
import java.util.concurrent.atomic.AtomicInteger;
7267
import java.util.concurrent.atomic.AtomicLong;
7368
import java.util.concurrent.locks.ReentrantLock;
@@ -830,7 +825,7 @@ public static CApiContext ensureCapiWasLoaded(Node node, PythonContext context,
830825
try {
831826
CApiContext cApiContext = loadCApi(node, context, name, path, reason);
832827
assert context.getCApiState() == PythonContext.CApiState.INITIALIZING;
833-
initializeThreadStateCurrentForAttachedThreads(node, context);
828+
initializeThreadStateCurrentForAttachedThreads(context);
834829
CApiTransitions.initializeReferenceQueuePolling(context.nativeContext);
835830
context.runCApiHooks();
836831
context.setCApiState(PythonContext.CApiState.INITIALIZED); // volatile write
@@ -853,8 +848,7 @@ public static CApiContext ensureCapiWasLoaded(Node node, PythonContext context,
853848
return context.getCApiContext();
854849
}
855850

856-
@SuppressWarnings("try")
857-
private static void initializeThreadStateCurrentForAttachedThreads(Node node, PythonContext context) throws ApiInitException {
851+
private static void initializeThreadStateCurrentForAttachedThreads(PythonContext context) {
858852
Thread[] threads = getOtherAliveAttachedThreads(context);
859853
if (threads.length == 0) {
860854
return;
@@ -865,7 +859,7 @@ protected void perform(ThreadLocalAction.Access access) {
865859
context.initializeNativeThreadState();
866860
}
867861
};
868-
waitForThreadLocalActions(node, context, submitThreadLocalActions(context, threads, action));
862+
submitThreadLocalActions(context, threads, action);
869863
}
870864

871865
private static Thread[] getOtherAliveAttachedThreads(PythonContext context) {
@@ -879,38 +873,9 @@ private static Thread[] getOtherAliveAttachedThreads(PythonContext context) {
879873
return threads.toArray(Thread[]::new);
880874
}
881875

882-
private static ArrayList<Future<Void>> submitThreadLocalActions(PythonContext context, Thread[] threads, ThreadLocalAction action) {
883-
ArrayList<Future<Void>> futures = new ArrayList<>(threads.length);
876+
private static void submitThreadLocalActions(PythonContext context, Thread[] threads, ThreadLocalAction action) {
884877
for (Thread thread : threads) {
885-
futures.add(context.getEnv().submitThreadLocal(new Thread[]{thread}, action));
886-
}
887-
return futures;
888-
}
889-
890-
@SuppressWarnings("try")
891-
private static void waitForThreadLocalActions(Node node, PythonContext context, ArrayList<Future<Void>> futures) throws ApiInitException {
892-
Node waitLocation = node != null ? node : context.getLanguage().unavailableSafepointLocation;
893-
try (GilNode.UncachedRelease ignored = GilNode.uncachedRelease()) {
894-
for (Future<Void> future : futures) {
895-
TruffleSafepoint.setBlockedThreadInterruptible(waitLocation, voidFuture -> {
896-
try {
897-
voidFuture.get(10, TimeUnit.SECONDS);
898-
} catch (InterruptedException e) {
899-
Thread.currentThread().interrupt();
900-
throw new RuntimeException(e);
901-
} catch (TimeoutException | ExecutionException e) {
902-
throw new RuntimeException(e);
903-
} catch (CancellationException e) {
904-
// Ignore threads that went away while initialization was in progress.
905-
}
906-
}, future);
907-
}
908-
} catch (RuntimeException e) {
909-
Throwable cause = e.getCause();
910-
if (cause instanceof TimeoutException) {
911-
throw new ApiInitException(toTruffleStringUncached("Timed out while initializing native thread state on an attached thread."));
912-
}
913-
throw e;
878+
context.getEnv().submitThreadLocal(new Thread[]{thread}, action);
914879
}
915880
}
916881

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,15 @@ static Object doWithoutContext(NativeCAPISymbol symbol, Object[] args,
853853
if (capiState != PythonContext.CApiState.INITIALIZING && capiState != PythonContext.CApiState.INITIALIZED) {
854854
CompilerDirectives.transferToInterpreterAndInvalidate();
855855
CApiContext.ensureCapiWasLoaded("call internal native GraalPy function");
856+
capiState = pythonContext.getCApiState();
857+
}
858+
if (capiState == PythonContext.CApiState.INITIALIZED) {
859+
PythonContext.PythonThreadState threadState = pythonContext.getThreadState(pythonContext.getLanguage(inliningTarget));
860+
// Native thread-state bootstrap may itself call internal C API helpers before
861+
// 'tstate_current' has been published for this thread.
862+
if (!threadState.isNativeThreadStateInitializationInProgress()) {
863+
pythonContext.ensureNativeThreadStateInitialized(threadState);
864+
}
856865
}
857866
// TODO review EnsureTruffleStringNode with GR-37896
858867
Object callable = CApiContext.getNativeSymbol(inliningTarget, symbol);

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -804,6 +804,7 @@ private static Object invoke(VirtualFrame frame, PythonContext ctx, CApiTiming t
804804
CheckFunctionResultNode checkResultNode, CExtToJavaNode convertReturnValue, PForeignToPTypeNode fromForeign, GetThreadStateNode getThreadStateNode,
805805
ExternalFunctionInvokeNode invokeNode) {
806806
PythonThreadState threadState = getThreadStateNode.execute(inliningTarget, ctx);
807+
ctx.ensureNativeThreadStateInitialized(threadState);
807808
Object result = invokeNode.execute(frame, inliningTarget, threadState, timing, name, callable, cArguments);
808809
result = checkResultNode.execute(threadState, name, result);
809810
if (convertReturnValue != null) {

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2607,6 +2607,12 @@ public void initializeNativeThreadState() {
26072607
initializeNativeThreadState(getThreadState(getLanguage()));
26082608
}
26092609

2610+
public void ensureNativeThreadStateInitialized(PythonThreadState pythonThreadState) {
2611+
if (getCApiState() == CApiState.INITIALIZED && !pythonThreadState.isNativeThreadStateInitialized()) {
2612+
initializeNativeThreadState(pythonThreadState);
2613+
}
2614+
}
2615+
26102616
@SuppressWarnings("try")
26112617
public void initializeNativeThreadState(PythonThreadState pythonThreadState) {
26122618
CompilerAsserts.neverPartOfCompilation();

0 commit comments

Comments
 (0)