|
61 | 61 | import com.oracle.graal.python.builtins.objects.PythonAbstractObject;
|
62 | 62 | import com.oracle.graal.python.builtins.objects.cext.PythonNativeClass;
|
63 | 63 | import com.oracle.graal.python.builtins.objects.cext.capi.CApiContext;
|
| 64 | +import com.oracle.graal.python.builtins.objects.cext.capi.PThreadState; |
| 65 | +import com.oracle.graal.python.builtins.objects.cext.capi.PyTruffleObjectFree.ReleaseHandleNode; |
| 66 | +import com.oracle.graal.python.builtins.objects.cext.capi.PyTruffleObjectFreeFactory.ReleaseHandleNodeGen; |
64 | 67 | import com.oracle.graal.python.builtins.objects.cext.capi.PythonNativeWrapper;
|
65 | 68 | import com.oracle.graal.python.builtins.objects.cext.hpy.GraalHPyContext;
|
66 | 69 | import com.oracle.graal.python.builtins.objects.common.HashingStorage;
|
@@ -139,6 +142,14 @@ public static final class PythonThreadState {
|
139 | 142 | /* corresponds to 'PyThreadState.dict' */
|
140 | 143 | PDict dict;
|
141 | 144 |
|
| 145 | + /* |
| 146 | + * This is the native wrapper object if we need to expose the thread state as PyThreadState |
| 147 | + * object. We need to store it here because the wrapper may receive 'toNative' in which case |
| 148 | + * a handle is allocated. In order to avoid leaks, the handle needs to be free'd when the |
| 149 | + * owning thread (or the whole context) is disposed. |
| 150 | + */ |
| 151 | + PThreadState nativeWrapper; |
| 152 | + |
142 | 153 | /*
|
143 | 154 | * The constructor needs to have this particular signature such that we can use it for
|
144 | 155 | * ContextThreadLocal.
|
@@ -191,6 +202,26 @@ public PDict getDict() {
|
191 | 202 | public void setDict(PDict dict) {
|
192 | 203 | this.dict = dict;
|
193 | 204 | }
|
| 205 | + |
| 206 | + public PThreadState getNativeWrapper() { |
| 207 | + return nativeWrapper; |
| 208 | + } |
| 209 | + |
| 210 | + public void setNativeWrapper(PThreadState nativeWrapper) { |
| 211 | + this.nativeWrapper = nativeWrapper; |
| 212 | + } |
| 213 | + |
| 214 | + public void dispose() { |
| 215 | + ReleaseHandleNode releaseHandleNode = ReleaseHandleNodeGen.getUncached(); |
| 216 | + if (dict != null && dict.getNativeWrapper() != null) { |
| 217 | + releaseHandleNode.execute(dict.getNativeWrapper()); |
| 218 | + } |
| 219 | + dict = null; |
| 220 | + if (nativeWrapper != null) { |
| 221 | + releaseHandleNode.execute(nativeWrapper); |
| 222 | + nativeWrapper = null; |
| 223 | + } |
| 224 | + } |
194 | 225 | }
|
195 | 226 |
|
196 | 227 | private static final class AtExitHook {
|
@@ -245,8 +276,8 @@ private static final class AtExitHook {
|
245 | 276 | */
|
246 | 277 | private final PythonThreadState buildThreadState;
|
247 | 278 |
|
248 |
| - /* map of thread IDs to indices for array 'threadStates' */ |
249 |
| - private Map<Thread, PythonThreadState> threadStateMapping = Collections.synchronizedMap(new WeakHashMap<>()); |
| 279 | + /* map of thread IDs to the corresponding 'threadStates' */ |
| 280 | + private final Map<Thread, PythonThreadState> threadStateMapping = Collections.synchronizedMap(new WeakHashMap<>()); |
250 | 281 |
|
251 | 282 | private final ReentrantLock importLock = new ReentrantLock();
|
252 | 283 | @CompilationFinal private boolean isInitialized = false;
|
@@ -860,6 +891,16 @@ public void runShutdownHooks() {
|
860 | 891 | for (ShutdownHook h : shutdownHooks) {
|
861 | 892 | h.call(this);
|
862 | 893 | }
|
| 894 | + assert threadStateMapping != null; |
| 895 | + for (PythonThreadState threadState : threadStateMapping.values()) { |
| 896 | + threadState.dispose(); |
| 897 | + } |
| 898 | + ReleaseHandleNode releaseHandleNode = ReleaseHandleNodeGen.getUncached(); |
| 899 | + for (PythonNativeWrapper singletonNativeWrapper : singletonNativePtrs) { |
| 900 | + if (singletonNativeWrapper != null) { |
| 901 | + releaseHandleNode.execute(singletonNativeWrapper); |
| 902 | + } |
| 903 | + } |
863 | 904 | }
|
864 | 905 |
|
865 | 906 | @TruffleBoundary
|
@@ -1166,6 +1207,7 @@ public synchronized void disposeThread(Thread thread) {
|
1166 | 1207 | }
|
1167 | 1208 | ts.shutdown();
|
1168 | 1209 | threadStateMapping.remove(thread);
|
| 1210 | + ts.dispose(); |
1169 | 1211 | releaseSentinelLock(ts.sentinelLock);
|
1170 | 1212 | }
|
1171 | 1213 |
|
|
0 commit comments