Skip to content

Commit 94550a7

Browse files
committed
[GR-47965] Migrate to TruffleThreadBuilder API.
PullRequest: graalpython/2918
2 parents 56cdff2 + 766b326 commit 94550a7

File tree

5 files changed

+29
-20
lines changed

5 files changed

+29
-20
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/ThreadModuleBuiltins.java

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@
8585
import com.oracle.graal.python.runtime.object.PythonObjectFactory;
8686
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
8787
import com.oracle.truffle.api.TruffleLanguage;
88+
import com.oracle.truffle.api.TruffleThreadBuilder;
8889
import com.oracle.truffle.api.dsl.Bind;
8990
import com.oracle.truffle.api.dsl.Cached;
9091
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
@@ -228,15 +229,15 @@ long start(VirtualFrame frame, Object cls, Object callable, Object args, Object
228229

229230
// TODO: python thread stack size != java thread stack size
230231
// ignore setting the stack size for the moment
231-
Thread thread = env.createThread(() -> {
232-
try (GilNode.UncachedAcquire gil = GilNode.uncachedAcquire()) {
233-
232+
TruffleThreadBuilder threadBuilder = env.newTruffleThreadBuilder(() -> {
233+
GilNode.UncachedAcquire gil = GilNode.uncachedAcquire();
234+
try {
234235
// the increment is protected by the gil
235236
int curCount = (int) HiddenAttr.ReadNode.executeUncached(threadModule, THREAD_COUNT, 0);
236237
HiddenAttr.WriteNode.executeUncached(threadModule, THREAD_COUNT, curCount + 1);
237238
try {
238239
// n.b.: It is important to pass 'null' frame here because each thread has
239-
// it's own stack and if we would pass the current frame, this would be
240+
// its own stack and if we would pass the current frame, this would be
240241
// connected as a caller which is incorrect. However, the thread-local
241242
// 'topframeref' is initialized with EMPTY which will be picked up.
242243
callNode.execute(null, callable, arguments, keywords);
@@ -246,14 +247,17 @@ long start(VirtualFrame frame, Object cls, Object callable, Object args, Object
246247
if (!IsBuiltinObjectProfile.profileObjectUncached(e.getUnreifiedException(), PythonBuiltinClassType.SystemExit)) {
247248
WriteUnraisableNode.getUncached().execute(e.getUnreifiedException(), IN_THREAD_STARTED_BY, callable);
248249
}
250+
// SystemExit is silently ignored (see _threadmodule.c: thread_run)
249251
} finally {
250252
curCount = (int) HiddenAttr.ReadNode.executeUncached(threadModule, THREAD_COUNT, 1);
251253
HiddenAttr.WriteNode.executeUncached(threadModule, THREAD_COUNT, curCount - 1);
252254
}
255+
} finally {
256+
gil.close();
253257
}
254-
}, env.getContext(), context.getThreadGroup());
258+
}).context(env.getContext()).threadGroup(context.getThreadGroup());
255259

256-
PThread pThread = factory.createPythonThread(cls, thread);
260+
PThread pThread = factory.createPythonThread(cls, threadBuilder.build());
257261
pThread.start();
258262
return pThread.getId();
259263
}
@@ -296,9 +300,9 @@ protected ArgumentClinicProvider getArgumentClinic() {
296300
@Builtin(name = J_EXIT)
297301
@Builtin(name = "exit_thread")
298302
@GenerateNodeFactory
299-
abstract static class ExitNode extends PythonBuiltinNode {
303+
abstract static class ExitThreadNode extends PythonBuiltinNode {
300304
@Specialization
301-
Object exit(
305+
static Object exit(
302306
@Cached PRaiseNode raiseNode) {
303307
throw raiseNode.raiseSystemExit(PNone.NONE);
304308
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/hpy/GraalHPyContext.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@
105105
import com.oracle.truffle.api.RootCallTarget;
106106
import com.oracle.truffle.api.TruffleLanguage.Env;
107107
import com.oracle.truffle.api.TruffleLogger;
108+
import com.oracle.truffle.api.TruffleThreadBuilder;
108109
import com.oracle.truffle.api.dsl.GenerateInline;
109110
import com.oracle.truffle.api.dsl.GenerateUncached;
110111
import com.oracle.truffle.api.dsl.ImportStatic;
@@ -1153,7 +1154,8 @@ private ReferenceQueue<Object> createReferenceQueue() {
11531154
// lazily register the runnable that concurrently collects the queued references
11541155
Env env = getContext().getEnv();
11551156
if (env.isCreateThreadAllowed()) {
1156-
Thread thread = env.createThread(new GraalHPyReferenceCleanerRunnable(referenceQueue), null, getContext().getThreadGroup());
1157+
TruffleThreadBuilder truffleThreadBuilder = env.newTruffleThreadBuilder(new GraalHPyReferenceCleanerRunnable(referenceQueue)).threadGroup(getContext().getThreadGroup());
1158+
Thread thread = truffleThreadBuilder.build();
11571159
// Make the cleaner thread a daemon; it should not prevent JVM shutdown.
11581160
thread.setDaemon(true);
11591161
thread.start();

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/object/BuiltinClassProfiles.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,10 @@ public static boolean profileObjectUncached(Object obj, PythonBuiltinClassType t
240240
return getUncached().profileObject(null, obj, type);
241241
}
242242

243+
public static boolean profileExceptionUncached(PException obj, PythonBuiltinClassType type) {
244+
return IsBuiltinObjectProfileNodeGen.getUncached().profileException(null, obj, type);
245+
}
246+
243247
public static IsBuiltinObjectExactProfile getUncached() {
244248
return IsBuiltinObjectExactProfileNodeGen.getUncached();
245249
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonContext.java

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1236,7 +1236,7 @@ public SharedMultiprocessingData getSharedMultiprocessingData() {
12361236

12371237
public long spawnTruffleContext(int fd, int sentinel, int[] fdsToKeep) {
12381238
ChildContextData data = new ChildContextData(isChildContext() ? childContextData.parentCtx : this);
1239-
Builder builder = data.parentCtx.env.newInnerContextBuilder().//
1239+
Builder childContextBuilder = data.parentCtx.env.newInnerContextBuilder().//
12401240
forceSharing(getOption(PythonOptions.ForceSharingForInnerContexts)).//
12411241
inheritAllAccess(true).//
12421242
initializeCreatorContext(true).//
@@ -1245,7 +1245,11 @@ public long spawnTruffleContext(int fd, int sentinel, int[] fdsToKeep) {
12451245
// with that. Gives "OSError: [Errno 9] Bad file number"
12461246
// option("python.PosixModuleBackend", "java").//
12471247
config(PythonContext.CHILD_CONTEXT_DATA, data);
1248-
Thread thread = data.parentCtx.env.createThread(new ChildContextThread(fd, sentinel, data, builder));
1248+
1249+
TruffleContext childContext = childContextBuilder.build();
1250+
data.setTruffleContext(childContext);
1251+
ChildContextThread childContextRunnable = new ChildContextThread(fd, sentinel, data);
1252+
Thread thread = data.parentCtx.env.newTruffleThreadBuilder(childContextRunnable).context(childContext).threadGroup(threadGroup).build();
12491253
long tid = PThread.getThreadId(thread);
12501254
getSharedMultiprocessingData().putChildContextThread(tid, thread);
12511255
getSharedMultiprocessingData().putChildContextData(tid, data);
@@ -1270,42 +1274,35 @@ public synchronized List<Integer> getChildContextFDs() {
12701274
return childContextFDs;
12711275
}
12721276

1273-
private static class ChildContextThread implements Runnable {
1277+
private static final class ChildContextThread implements Runnable {
12741278
private static final TruffleLogger MULTIPROCESSING_LOGGER = PythonLanguage.getLogger(ChildContextThread.class);
12751279
private static final Source MULTIPROCESSING_SOURCE = Source.newBuilder(PythonLanguage.ID,
12761280
"from multiprocessing.popen_truffleprocess import spawn_truffleprocess; spawn_truffleprocess(fd, sentinel)",
12771281
"<spawned-child-context>").internal(true).build();
12781282

12791283
private final int fd;
12801284
private final ChildContextData data;
1281-
private final Builder builder;
12821285
private final int sentinel;
12831286

1284-
public ChildContextThread(int fd, int sentinel, ChildContextData data, Builder builder) {
1287+
public ChildContextThread(int fd, int sentinel, ChildContextData data) {
12851288
this.fd = fd;
12861289
this.data = data;
1287-
this.builder = builder;
12881290
this.sentinel = sentinel;
12891291
}
12901292

12911293
@Override
12921294
public void run() {
12931295
try {
12941296
MULTIPROCESSING_LOGGER.fine("starting spawned child context");
1295-
TruffleContext ctx = builder.build();
1296-
data.setTruffleContext(ctx);
1297-
Object parent = ctx.enter(null);
12981297
CallTarget ct = PythonContext.get(null).getEnv().parsePublic(MULTIPROCESSING_SOURCE, "fd", "sentinel");
12991298
try {
13001299
data.running.countDown();
13011300
Object res = ct.call(fd, sentinel);
13021301
int exitCode = CastToJavaIntLossyNode.executeUncached(res);
13031302
data.setExitCode(exitCode);
13041303
} finally {
1305-
ctx.leave(null, parent);
13061304
if (data.compareAndSetExiting(false, true)) {
13071305
try {
1308-
ctx.close();
13091306
MULTIPROCESSING_LOGGER.log(Level.FINE, "closed spawned child context");
13101307
} catch (Throwable t) {
13111308
MULTIPROCESSING_LOGGER.log(Level.FINE, "exception while closing spawned child context", t);

graalpython/lib-python/3/test/_test_multiprocessing.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,7 @@ def test_close(self):
708708

709709
close_queue(q)
710710

711+
@support.impl_detail("timing", graalpy=False)
711712
@support.requires_resource('walltime')
712713
def test_many_processes(self):
713714
if self.TYPE == 'threads':
@@ -999,6 +1000,7 @@ def _test_sys_exit(cls, reason, testfn):
9991000
sys.stderr = open(fd, 'w', encoding="utf-8", closefd=False)
10001001
sys.exit(reason)
10011002

1003+
@support.impl_detail("timeout", graalpy=False)
10021004
def test_sys_exit(self):
10031005
# See Issue 13854
10041006
if self.TYPE == 'threads':

0 commit comments

Comments
 (0)