Skip to content

Commit 0ad6f3e

Browse files
committed
PyThreadState_SetAsyncExc: fix arg descriptor, handle NULL
1 parent 4c647d4 commit 0ad6f3e

File tree

2 files changed

+23
-6
lines changed

2 files changed

+23
-6
lines changed

graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_pystate.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def test_PyThreadState_GetFrame(self):
7171

7272
# This seems to get the native extensions into some inconsistent state on GraalPy, giving:
7373
# refcnt below zero during managed adjustment for 0000aaae18fca780 (9 0000000000000009 - 10)
74-
def ignored_test_SetAsyncExc(self):
74+
def test_SetAsyncExc(self):
7575
SetAsyncExcCaller = CPyExtType(
7676
"SetAsyncExcCaller",
7777
"""

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

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.Int;
4646
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.Pointer;
4747
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PyFrameObjectTransfer;
48+
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PyObject;
4849
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PyObjectBorrowed;
4950
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PyThreadState;
5051
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.Py_ssize_t;
@@ -62,6 +63,7 @@
6263
import com.oracle.graal.python.builtins.objects.frame.PFrame;
6364
import com.oracle.graal.python.builtins.objects.ints.PInt;
6465
import com.oracle.graal.python.builtins.objects.thread.PThread;
66+
import com.oracle.graal.python.nodes.PGuards;
6567
import com.oracle.graal.python.nodes.PRaiseNode;
6668
import com.oracle.graal.python.nodes.PRootNode;
6769
import com.oracle.graal.python.nodes.frame.GetCurrentFrameRef;
@@ -146,31 +148,46 @@ PDict get(@Cached PythonObjectFactory factory) {
146148
}
147149
}
148150

149-
@CApiBuiltin(ret = Int, args = {ArgDescriptor.UNSIGNED_LONG, ArgDescriptor.PyObjectTransfer}, call = Direct)
151+
@CApiBuiltin(ret = Int, args = {ArgDescriptor.UNSIGNED_LONG, PyObject}, call = Direct)
150152
abstract static class PyThreadState_SetAsyncExc extends CApiBinaryBuiltinNode {
151153
public static final TruffleLogger LOGGER = CApiContext.getLogger(PyThreadState_SetAsyncExc.class);
152154

153155
@Specialization
154156
@TruffleBoundary
155157
int doIt(long id, Object exceptionObject) {
156-
LOGGER.warning("The application uses PyThreadState_SetAsyncExc, which is not reliably supported by GraalPy");
157158
for (Thread thread : getContext().getThreads()) {
158159
if (PThread.getThreadId(thread) == id) {
159-
// We do not want to raise in some internal code, it could corrupt internal data
160-
// structures.
160+
if (PGuards.isNoValue(exceptionObject)) {
161+
LOGGER.warning("The application used PyThreadState_SetAsyncExc to clear an exception on another thread. " +
162+
"This is not supported and ignored by GraalPy.");
163+
return 1;
164+
}
161165
ThreadLocalAction action = new ThreadLocalAction(true, false) {
166+
static final int MAX_MISSED_COUNT = 20;
162167
int missedCount = 0;
163168

164169
@Override
165170
protected void perform(Access access) {
171+
if (missedCount == MAX_MISSED_COUNT) {
172+
throw PRaiseNode.raiseExceptionObject(null, exceptionObject);
173+
}
174+
// If possible, we do not want to raise in some internal code, it could
175+
// corrupt internal data structures.
166176
Node location = access.getLocation();
167177
if (location != null) {
168178
RootNode rootNode = location.getRootNode();
169179
if (rootNode instanceof PRootNode && !rootNode.isInternal()) {
170180
throw PRaiseNode.raiseExceptionObject(null, exceptionObject);
171181
}
172182
}
173-
if (missedCount++ < 20) {
183+
// Heuristic fabricated out of thin air:
184+
if (missedCount++ < MAX_MISSED_COUNT) {
185+
if (missedCount % 2 == 0) {
186+
try {
187+
Thread.sleep(1);
188+
} catch (InterruptedException ignored) {
189+
}
190+
}
174191
getContext().getEnv().submitThreadLocal(new Thread[]{thread}, this);
175192
}
176193
}

0 commit comments

Comments
 (0)