|
45 | 45 | import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.Int;
|
46 | 46 | import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.Pointer;
|
47 | 47 | 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; |
48 | 49 | import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PyObjectBorrowed;
|
49 | 50 | import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PyThreadState;
|
50 | 51 | import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.Py_ssize_t;
|
|
62 | 63 | import com.oracle.graal.python.builtins.objects.frame.PFrame;
|
63 | 64 | import com.oracle.graal.python.builtins.objects.ints.PInt;
|
64 | 65 | import com.oracle.graal.python.builtins.objects.thread.PThread;
|
| 66 | +import com.oracle.graal.python.nodes.PGuards; |
65 | 67 | import com.oracle.graal.python.nodes.PRaiseNode;
|
66 | 68 | import com.oracle.graal.python.nodes.PRootNode;
|
67 | 69 | import com.oracle.graal.python.nodes.frame.GetCurrentFrameRef;
|
@@ -146,31 +148,46 @@ PDict get(@Cached PythonObjectFactory factory) {
|
146 | 148 | }
|
147 | 149 | }
|
148 | 150 |
|
149 |
| - @CApiBuiltin(ret = Int, args = {ArgDescriptor.UNSIGNED_LONG, ArgDescriptor.PyObjectTransfer}, call = Direct) |
| 151 | + @CApiBuiltin(ret = Int, args = {ArgDescriptor.UNSIGNED_LONG, PyObject}, call = Direct) |
150 | 152 | abstract static class PyThreadState_SetAsyncExc extends CApiBinaryBuiltinNode {
|
151 | 153 | public static final TruffleLogger LOGGER = CApiContext.getLogger(PyThreadState_SetAsyncExc.class);
|
152 | 154 |
|
153 | 155 | @Specialization
|
154 | 156 | @TruffleBoundary
|
155 | 157 | int doIt(long id, Object exceptionObject) {
|
156 |
| - LOGGER.warning("The application uses PyThreadState_SetAsyncExc, which is not reliably supported by GraalPy"); |
157 | 158 | for (Thread thread : getContext().getThreads()) {
|
158 | 159 | 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 | + } |
161 | 165 | ThreadLocalAction action = new ThreadLocalAction(true, false) {
|
| 166 | + static final int MAX_MISSED_COUNT = 20; |
162 | 167 | int missedCount = 0;
|
163 | 168 |
|
164 | 169 | @Override
|
165 | 170 | 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. |
166 | 176 | Node location = access.getLocation();
|
167 | 177 | if (location != null) {
|
168 | 178 | RootNode rootNode = location.getRootNode();
|
169 | 179 | if (rootNode instanceof PRootNode && !rootNode.isInternal()) {
|
170 | 180 | throw PRaiseNode.raiseExceptionObject(null, exceptionObject);
|
171 | 181 | }
|
172 | 182 | }
|
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 | + } |
174 | 191 | getContext().getEnv().submitThreadLocal(new Thread[]{thread}, this);
|
175 | 192 | }
|
176 | 193 | }
|
|
0 commit comments