Skip to content

Commit 12d9947

Browse files
committed
Lazily fetch PyThreadState pointer on other threads; reset TL-var on dispose
1 parent 5a969c2 commit 12d9947

File tree

5 files changed

+62
-32
lines changed

5 files changed

+62
-32
lines changed

graalpython/com.oracle.graal.python.cext/src/capi.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ THREAD_LOCAL PyThreadState *tstate_current = NULL;
264264
static void initialize_globals() {
265265
#ifndef GRAALVM_PYTHON_LLVM_MANAGED
266266
// store the thread state into a thread local variable
267-
tstate_current = GraalPyTruffleThreadState_Get();
267+
tstate_current = GraalPyTruffleThreadState_Get(&tstate_current);
268268
#endif /* GRAALVM_PYTHON_LLVM_MANAGED */
269269
_Py_NoneStructReference = GraalPyTruffle_None();
270270
_Py_NotImplementedStructReference = GraalPyTruffle_NotImplemented();

graalpython/com.oracle.graal.python.cext/src/pystate.c

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -44,26 +44,28 @@
4444

4545
extern TruffleContext* TRUFFLE_CONTEXT;
4646

47-
PyThreadState *
48-
PyThreadState_Get() {
47+
static inline PyThreadState *
48+
_get_thread_state() {
4949
#ifndef GRAALVM_PYTHON_LLVM_MANAGED
5050
PyThreadState *ts = tstate_current;
51-
if (ts) {
52-
return ts;
51+
if (UNLIKELY(ts == NULL)) {
52+
ts = GraalPyTruffleThreadState_Get(&tstate_current);
53+
tstate_current = ts;
5354
}
55+
return ts;
56+
#else /* GRAALVM_PYTHON_LLVM_MANAGED */
57+
return GraalPyTruffleThreadState_Get(NULL);
5458
#endif /* GRAALVM_PYTHON_LLVM_MANAGED */
55-
return GraalPyTruffleThreadState_Get();
59+
}
60+
61+
PyThreadState *
62+
PyThreadState_Get() {
63+
return _get_thread_state();
5664
}
5765

5866
PyThreadState *
5967
_PyThreadState_UncheckedGet(void) {
60-
#ifndef GRAALVM_PYTHON_LLVM_MANAGED
61-
PyThreadState *ts = tstate_current;
62-
if (ts) {
63-
return ts;
64-
}
65-
#endif /* GRAALVM_PYTHON_LLVM_MANAGED */
66-
return GraalPyTruffleThreadState_Get();
68+
return _get_thread_state();
6769
}
6870

6971
void PyThreadState_Clear(PyThreadState *tstate) {
@@ -88,13 +90,7 @@ PyInterpreterState* PyInterpreterState_Main()
8890
}
8991

9092
PyThreadState* PyGILState_GetThisThreadState(void) {
91-
#ifndef GRAALVM_PYTHON_LLVM_MANAGED
92-
PyThreadState *ts = tstate_current;
93-
if (ts) {
94-
return ts;
95-
}
96-
#endif /* GRAALVM_PYTHON_LLVM_MANAGED */
97-
return GraalPyTruffleThreadState_Get();
93+
return _get_thread_state();
9894
}
9995

10096
PyObject* PyState_FindModule(struct PyModuleDef* module) {
@@ -147,10 +143,10 @@ int PyState_RemoveModule(struct PyModuleDef* def) {
147143
PyAPI_FUNC(PyGILState_STATE) PyGILState_Ensure() {
148144
int result = 0;
149145
if (TRUFFLE_CONTEXT) {
150-
if ((*TRUFFLE_CONTEXT)->getTruffleEnv(TRUFFLE_CONTEXT) == NULL) {
151-
(*TRUFFLE_CONTEXT)->attachCurrentThread(TRUFFLE_CONTEXT);
152-
result |= _PYGILSTATE_ATTACHED;
153-
}
146+
if ((*TRUFFLE_CONTEXT)->getTruffleEnv(TRUFFLE_CONTEXT) == NULL) {
147+
(*TRUFFLE_CONTEXT)->attachCurrentThread(TRUFFLE_CONTEXT);
148+
result |= _PYGILSTATE_ATTACHED;
149+
}
154150
}
155151
int locked = GraalPyTruffleGILState_Ensure();
156152
if (locked) {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextPyStateBuiltins.java

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import static com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiCallPath.Direct;
4444
import static com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiCallPath.Ignored;
4545
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.Int;
46+
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.Pointer;
4647
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PyObjectBorrowed;
4748
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PyThreadState;
4849
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.Py_ssize_t;
@@ -64,6 +65,8 @@
6465
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
6566
import com.oracle.truffle.api.dsl.Cached;
6667
import com.oracle.truffle.api.dsl.Specialization;
68+
import com.oracle.truffle.api.interop.InteropLibrary;
69+
import com.oracle.truffle.api.library.CachedLibrary;
6770

6871
public final class PythonCextPyStateBuiltins {
6972

@@ -97,12 +100,17 @@ static Object restore(
97100
}
98101
}
99102

100-
@CApiBuiltin(ret = PyThreadState, args = {}, call = Ignored)
101-
abstract static class PyTruffleThreadState_Get extends CApiNullaryBuiltinNode {
103+
@CApiBuiltin(ret = PyThreadState, args = {Pointer}, call = Ignored)
104+
abstract static class PyTruffleThreadState_Get extends CApiUnaryBuiltinNode {
102105

103-
@Specialization
104-
Object get() {
105-
return PThreadState.getThreadState(getLanguage(), getContext());
106+
@Specialization(limit = "1")
107+
Object get(Object tstateCurrentPtr,
108+
@CachedLibrary("tstateCurrentPtr") InteropLibrary lib) {
109+
PythonThreadState pythonThreadState = getContext().getThreadState(getLanguage());
110+
if (!lib.isNull(tstateCurrentPtr)) {
111+
pythonThreadState.setNativeThreadLocalVarPointer(tstateCurrentPtr);
112+
}
113+
return PThreadState.getThreadState(pythonThreadState);
106114
}
107115
}
108116

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/structs/CStructAccess.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,6 +1152,10 @@ public static void writeUncached(Object pointer, CFields field, Object value) {
11521152
WritePointerNodeGen.getUncached().write(pointer, field, value);
11531153
}
11541154

1155+
public static void writeUncached(Object pointer, long offset, Object value) {
1156+
WritePointerNodeGen.getUncached().execute(pointer, offset, value);
1157+
}
1158+
11551159
abstract void execute(Object pointer, long offset, Object value);
11561160

11571161
public final void write(Object pointer, CFields field, Object value) {

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

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@
121121
import com.oracle.graal.python.builtins.objects.cext.capi.transitions.CApiTransitions.HandleContext;
122122
import com.oracle.graal.python.builtins.objects.cext.common.LoadCExtException.ApiInitException;
123123
import com.oracle.graal.python.builtins.objects.cext.hpy.GraalHPyContext;
124+
import com.oracle.graal.python.builtins.objects.cext.structs.CStructAccess;
124125
import com.oracle.graal.python.builtins.objects.common.HashingStorage;
125126
import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.HashingStorageGetItem;
126127
import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.HashingStorageGetIterator;
@@ -309,6 +310,12 @@ public static final class PythonThreadState {
309310
*/
310311
PThreadState nativeWrapper;
311312

313+
/*
314+
* Pointer to the native thread-local variable used to store the native PyThreadState struct
315+
* for this thread.
316+
*/
317+
Object nativeThreadLocalVarPointer;
318+
312319
/* The global tracing function, set by sys.settrace and returned by sys.gettrace. */
313320
Object traceFun;
314321

@@ -487,7 +494,7 @@ public void setContextVarsContext(PContextVarsContext contextVarsContext) {
487494
this.contextVarsContext = contextVarsContext;
488495
}
489496

490-
public void dispose() {
497+
public void dispose(PythonContext context) {
491498
// This method may be called twice on the same object.
492499

493500
/*
@@ -506,6 +513,14 @@ public void dispose() {
506513
PyTruffleObjectFree.releaseNativeWrapperUncached(nativeWrapper);
507514
nativeWrapper = null;
508515
}
516+
/*
517+
* Write 'NULL' to the native thread-local variable used to store the PyThreadState
518+
* struct such that it cannot accidentally be reused.
519+
*/
520+
if (nativeThreadLocalVarPointer != null) {
521+
CStructAccess.WritePointerNode.writeUncached(nativeThreadLocalVarPointer, 0, context.getNativeNull());
522+
nativeThreadLocalVarPointer = null;
523+
}
509524
}
510525

511526
public Object getTraceFun() {
@@ -572,6 +587,13 @@ public Object getAsyncgenFirstIter() {
572587
public void setAsyncgenFirstIter(Object asyncgenFirstIter) {
573588
this.asyncgenFirstIter = asyncgenFirstIter;
574589
}
590+
591+
public void setNativeThreadLocalVarPointer(Object ptr) {
592+
// either unset or same
593+
assert nativeThreadLocalVarPointer == null || nativeThreadLocalVarPointer == ptr ||
594+
InteropLibrary.getUncached().isIdentical(nativeThreadLocalVarPointer, ptr, InteropLibrary.getUncached());
595+
this.nativeThreadLocalVarPointer = ptr;
596+
}
575597
}
576598

577599
private static final class AtExitHook {
@@ -2064,7 +2086,7 @@ public void runShutdownHooks() {
20642086
@TruffleBoundary
20652087
private void disposeThreadStates() {
20662088
for (PythonThreadState ts : threadStateMapping.values()) {
2067-
ts.dispose();
2089+
ts.dispose(this);
20682090
}
20692091
threadStateMapping.clear();
20702092
}
@@ -2491,7 +2513,7 @@ public synchronized void disposeThread(Thread thread) {
24912513
}
24922514
ts.shutdown();
24932515
threadStateMapping.remove(thread);
2494-
ts.dispose();
2516+
ts.dispose(this);
24952517
releaseSentinelLock(ts.sentinelLock);
24962518
getSharedMultiprocessingData().removeChildContextThread(PThread.getThreadId(thread));
24972519
}

0 commit comments

Comments
 (0)