|
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