140
140
import com .oracle .truffle .api .nodes .Node ;
141
141
import com .oracle .truffle .api .source .Source ;
142
142
import com .oracle .truffle .api .utilities .CyclicAssumption ;
143
+ import com .oracle .truffle .api .utilities .TruffleWeakReference ;
143
144
import com .oracle .truffle .llvm .api .Toolchain ;
144
145
145
146
public final class PythonContext extends Python3Core {
@@ -538,12 +539,16 @@ public Map<String, Object> getCodecErrorRegistry() {
538
539
public static final class ChildContextData {
539
540
private int exitCode = 0 ;
540
541
private boolean signaled ;
541
- @ CompilationFinal private TruffleContext ctx ;
542
- @ CompilationFinal private PythonContext parentCtx ;
542
+ private final PythonContext parentCtx ;
543
+ private TruffleWeakReference < TruffleContext > ctx ;
543
544
544
545
private final AtomicBoolean exiting = new AtomicBoolean (false );
545
546
private final CountDownLatch running = new CountDownLatch (1 );
546
547
548
+ public ChildContextData (PythonContext parentCtx ) {
549
+ this .parentCtx = parentCtx ;
550
+ }
551
+
547
552
public void setExitCode (int exitCode ) {
548
553
this .exitCode = exitCode ;
549
554
}
@@ -563,16 +568,12 @@ public boolean wasSignaled() {
563
568
564
569
private void setTruffleContext (TruffleContext ctx ) {
565
570
assert this .ctx == null ;
566
- this .ctx = ctx ;
571
+ assert ctx != null ;
572
+ this .ctx = new TruffleWeakReference <>(ctx );
567
573
}
568
574
569
575
public TruffleContext getTruffleContext () {
570
- return ctx ;
571
- }
572
-
573
- private void setParentContext (PythonContext parentCtx ) {
574
- assert this .parentCtx == null ;
575
- this .parentCtx = parentCtx ;
576
+ return ctx .get ();
576
577
}
577
578
578
579
public void awaitRunning () throws InterruptedException {
@@ -786,9 +787,15 @@ public Semaphore removeNamedSemaphore(String name) {
786
787
return namedSemaphores .remove (name );
787
788
}
788
789
789
- private final Map <Long , Thread > childContextThreads = new ConcurrentHashMap <>();
790
+ private final ConcurrentHashMap <Long , Thread > childContextThreads = new ConcurrentHashMap <>();
790
791
791
- private final Map <Long , ChildContextData > childContextData = new ConcurrentHashMap <>();
792
+ /**
793
+ * {@code ChildContextData} outlives its own context, because the parent needs to be able to
794
+ * access the exit code even after the child context was closed and thread disposed. We
795
+ * dispose the mapping to {@code ChildContextData} when the Python code (our internal Python
796
+ * code) asks for the exit code for the first time after the child exited.
797
+ */
798
+ private final ConcurrentHashMap <Long , ChildContextData > childContextData = new ConcurrentHashMap <>();
792
799
793
800
@ TruffleBoundary
794
801
public Thread getChildContextThread (long tid ) {
@@ -810,6 +817,11 @@ public ChildContextData getChildContextData(long tid) {
810
817
return childContextData .get (tid );
811
818
}
812
819
820
+ @ TruffleBoundary
821
+ public void removeChildContextData (long tid ) {
822
+ childContextData .remove (tid );
823
+ }
824
+
813
825
@ TruffleBoundary
814
826
public void putChildContextData (long id , ChildContextData data ) {
815
827
childContextData .put (id , data );
@@ -853,12 +865,7 @@ public SharedMultiprocessingData getSharedMultiprocessingData() {
853
865
}
854
866
855
867
public long spawnTruffleContext (int fd , int sentinel , int [] fdsToKeep ) {
856
- ChildContextData data = new ChildContextData ();
857
- if (!isChildContext ()) {
858
- data .setParentContext (this );
859
- } else {
860
- data .setParentContext (childContextData .parentCtx );
861
- }
868
+ ChildContextData data = new ChildContextData (isChildContext () ? childContextData .parentCtx : this );
862
869
863
870
Builder builder = data .parentCtx .env .newContextBuilder ().config (PythonContext .CHILD_CONTEXT_DATA , data );
864
871
Thread thread = data .parentCtx .env .createThread (new ChildContextThread (fd , sentinel , data , builder ));
0 commit comments