58
58
import com .oracle .graal .python .parser .PythonParserImpl ;
59
59
import com .oracle .graal .python .runtime .GilNode ;
60
60
import com .oracle .graal .python .runtime .PythonContext ;
61
- import com .oracle .graal .python .runtime .PythonContext .ChildContextData ;
62
61
import com .oracle .graal .python .runtime .PythonContext .PythonThreadState ;
63
62
import com .oracle .graal .python .runtime .PythonOptions ;
64
63
import com .oracle .graal .python .runtime .PythonParser .ParserMode ;
100
99
import com .oracle .truffle .api .object .Shape ;
101
100
import com .oracle .truffle .api .source .Source ;
102
101
import com .oracle .truffle .api .source .Source .SourceBuilder ;
103
- import java .util .Map ;
104
102
105
103
@ TruffleLanguage .Registration (id = PythonLanguage .ID , //
106
104
name = PythonLanguage .NAME , //
@@ -158,6 +156,9 @@ public final class PythonLanguage extends TruffleLanguage<PythonContext> {
158
156
159
157
public final Assumption singleContextAssumption = Truffle .getRuntime ().createAssumption ("Only a single context is active" );
160
158
159
+ @ CompilationFinal public boolean singleContext = true ;
160
+ private boolean firstContextInitialized ;
161
+
161
162
/**
162
163
* This assumption will be valid if all contexts are single-threaded. Hence, it will be
163
164
* invalidated as soon as at least one context has been initialized for multi-threading.
@@ -198,6 +199,12 @@ public final class PythonLanguage extends TruffleLanguage<PythonContext> {
198
199
* system is shut down, unless explicitly removed. We interpret this as meaning they all exist
199
200
* globally per language instance, that is, they are shared between different Contexts in the
200
201
* same engine.
202
+ *
203
+ * Top level contexts use this map to initialize their shared multiprocessing data. Inner
204
+ * children contexts created for the multiprocessing module ignore this map in
205
+ * {@link PythonLanguage} and instead inherit it in the shared multiprocessing data from their
206
+ * parent context. This way, the child inner contexts do not have to run in the same engine
207
+ * (have the same language instance), but can still share the named semaphores.
201
208
*/
202
209
public final ConcurrentHashMap <String , Semaphore > namedSemaphores = new ConcurrentHashMap <>();
203
210
@@ -218,35 +225,6 @@ public final class PythonLanguage extends TruffleLanguage<PythonContext> {
218
225
219
226
private final MroShape mroShapeRoot = MroShape .createRoot ();
220
227
221
- private final Map <Long , Thread > childContextThreads = new ConcurrentHashMap <>();
222
-
223
- private final Map <Long , ChildContextData > childContextData = new ConcurrentHashMap <>();
224
-
225
- @ TruffleBoundary
226
- public Thread getChildContextThread (long tid ) {
227
- return childContextThreads .get (tid );
228
- }
229
-
230
- @ TruffleBoundary
231
- public void putChildContextThread (long id , Thread thread ) {
232
- childContextThreads .put (id , thread );
233
- }
234
-
235
- @ TruffleBoundary
236
- public void removeChildContextThread (long id ) {
237
- childContextThreads .remove (id );
238
- }
239
-
240
- @ TruffleBoundary
241
- public ChildContextData getChildContextData (long tid ) {
242
- return childContextData .get (tid );
243
- }
244
-
245
- @ TruffleBoundary
246
- public void putChildContextData (long id , ChildContextData data ) {
247
- childContextData .put (id , data );
248
- }
249
-
250
228
public static PythonLanguage get (Node node ) {
251
229
return REFERENCE .get (node );
252
230
}
@@ -293,12 +271,16 @@ protected void finalizeContext(PythonContext context) {
293
271
294
272
@ Override
295
273
protected boolean areOptionsCompatible (OptionValues firstOptions , OptionValues newOptions ) {
274
+ if (singleContext ) {
275
+ return false ;
276
+ }
296
277
return PythonOptions .areOptionsCompatible (firstOptions , newOptions );
297
278
}
298
279
299
280
@ Override
300
281
protected boolean patchContext (PythonContext context , Env newEnv ) {
301
- if (!areOptionsCompatible (context .getEnv ().getOptions (), newEnv .getOptions ())) {
282
+ // We intentionally bypass the singleContext check in PythonLanguage#areOptionsCompatible
283
+ if (!PythonOptions .areOptionsCompatible (context .getEnv ().getOptions (), newEnv .getOptions ())) {
302
284
Python3Core .writeInfo ("Cannot use preinitialized context." );
303
285
return false ;
304
286
}
@@ -327,6 +309,7 @@ protected PythonContext createContext(Env env) {
327
309
} else {
328
310
assert areOptionsCompatible (options , PythonOptions .createEngineOptions (env )) : "invalid engine options" ;
329
311
}
312
+ firstContextInitialized = true ;
330
313
return context ;
331
314
}
332
315
@@ -738,6 +721,14 @@ private static Source newSource(PythonContext ctxt, SourceBuilder srcBuilder) th
738
721
@ Override
739
722
protected void initializeMultipleContexts () {
740
723
super .initializeMultipleContexts ();
724
+ // We want to make sure that initializeMultipleContexts is always called before the first
725
+ // context is created.
726
+ // This would not be the case with inner contexts, but we achieve that by returning false
727
+ // from areOptionsCompatible when it is invoked for the first inner context, then Truffle
728
+ // creates a new PythonLanguage instance, calls initializeMultipleContexts on it, and only
729
+ // then uses it to create the inner contexts.
730
+ assert !firstContextInitialized ;
731
+ singleContext = false ;
741
732
singleContextAssumption .invalidate ();
742
733
}
743
734
0 commit comments