Skip to content

Commit a571ee9

Browse files
committed
Change the logic for rb_thread_call_without_gvl() so no Ruby lambdas are created
* The unblocking action should not execute any Ruby code.
1 parent 2cb0520 commit a571ee9

File tree

2 files changed

+33
-32
lines changed

2 files changed

+33
-32
lines changed

lib/truffle/truffle/cext.rb

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1595,16 +1595,9 @@ def rb_thread_call_with_gvl(function, data)
15951595
end
15961596

15971597
def rb_thread_call_without_gvl(function, data1, unblock, data2)
1598-
if unblock
1599-
unblocker = -> {
1600-
Truffle::Interop.execute_without_conversion(unblock, data2)
1601-
}
1602-
end
1603-
1604-
Primitive.call_without_c_mutex(
1605-
-> { Thread.current.unblock(
1606-
unblocker,
1607-
-> { function.call(data1) }) }, [])
1598+
Primitive.call_without_c_mutex(-> {
1599+
Primitive.call_with_unblocking_function(Thread.current, function, data1, unblock, data2)
1600+
}, [])
16081601
end
16091602

16101603
def rb_iterate(iteration, iterated_object, callback, callback_arg)

src/main/java/org/truffleruby/core/thread/ThreadNodes.java

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@
7676
import org.truffleruby.core.symbol.RubySymbol;
7777
import org.truffleruby.core.thread.ThreadManager.UnblockingAction;
7878
import org.truffleruby.core.thread.ThreadManager.UnblockingActionHolder;
79+
import org.truffleruby.interop.InteropNodes;
80+
import org.truffleruby.interop.TranslateInteropExceptionNode;
7981
import org.truffleruby.language.Nil;
8082
import org.truffleruby.language.NotProvided;
8183
import org.truffleruby.language.SafepointAction;
@@ -88,11 +90,14 @@
8890
import org.truffleruby.language.objects.shared.SharedObjects;
8991
import org.truffleruby.language.yield.YieldNode;
9092

93+
import com.oracle.truffle.api.CompilerDirectives;
9194
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
9295
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
9396
import com.oracle.truffle.api.dsl.Cached;
9497
import com.oracle.truffle.api.dsl.ImportStatic;
9598
import com.oracle.truffle.api.dsl.Specialization;
99+
import com.oracle.truffle.api.interop.InteropException;
100+
import com.oracle.truffle.api.interop.InteropLibrary;
96101
import com.oracle.truffle.api.library.CachedLibrary;
97102
import com.oracle.truffle.api.nodes.Node;
98103
import com.oracle.truffle.api.object.Shape;
@@ -503,46 +508,49 @@ protected RubyThread wakeup(RubyThread rubyThread) {
503508
}
504509

505510
@NonStandard
506-
@CoreMethod(names = "unblock", required = 2)
507-
public abstract static class UnblockNode extends YieldingCoreMethodNode {
511+
@Primitive(name = "call_with_unblocking_function")
512+
public abstract static class CallWithUnblockingFunctionNode extends PrimitiveArrayArgumentsNode {
508513

509-
@Specialization
510-
protected Object unblock(RubyThread thread, Object unblocker, RubyProc runner,
511-
@Cached("createCountingProfile()") LoopConditionProfile loopProfile) {
514+
@Specialization(limit = "getCacheLimit()")
515+
protected Object call(RubyThread thread, Object function, Object arg, Object unblocker, Object unblockerArg,
516+
@CachedLibrary("function") InteropLibrary receivers,
517+
@Cached TranslateInteropExceptionNode translateInteropExceptionNode) {
512518
final ThreadManager threadManager = getContext().getThreadManager();
513519
final UnblockingAction unblockingAction;
514520
if (unblocker == nil) {
515521
unblockingAction = threadManager.getNativeCallUnblockingAction();
516522
} else {
517-
unblockingAction = makeUnblockingAction((RubyProc) unblocker);
523+
unblockingAction = makeUnblockingAction(unblocker, unblockerArg);
518524
}
519-
final UnblockingActionHolder actionHolder = threadManager.getActionHolder(Thread.currentThread());
520525

526+
final UnblockingActionHolder actionHolder = threadManager.getActionHolder(Thread.currentThread());
521527
final UnblockingAction oldAction = actionHolder.changeTo(unblockingAction);
528+
final ThreadStatus status = thread.status;
529+
thread.status = ThreadStatus.SLEEP;
522530
try {
523-
Object result;
524-
do {
525-
final ThreadStatus status = thread.status;
526-
thread.status = ThreadStatus.SLEEP;
527-
528-
try {
529-
result = yield(runner);
530-
} finally {
531-
thread.status = status;
532-
}
533-
} while (loopProfile.profile(result == null));
534-
535-
return result;
531+
return InteropNodes.execute(function, new Object[]{ arg }, receivers, translateInteropExceptionNode);
536532
} finally {
533+
thread.status = status;
537534
actionHolder.restore(oldAction);
535+
538536
}
539537
}
540538

541539
@TruffleBoundary
542-
private UnblockingAction makeUnblockingAction(RubyProc unblocker) {
543-
return () -> yield(unblocker);
540+
private UnblockingAction makeUnblockingAction(Object function, Object argument) {
541+
assert InteropLibrary.getUncached().isExecutable(function);
542+
return () -> {
543+
try {
544+
InteropLibrary.getUncached().execute(function, argument);
545+
} catch (InteropException e) {
546+
throw CompilerDirectives.shouldNotReachHere(e);
547+
}
548+
};
544549
}
545550

551+
protected int getCacheLimit() {
552+
return getContext().getOptions().DISPATCH_CACHE;
553+
}
546554
}
547555

548556
@CoreMethod(names = "list", onSingleton = true)

0 commit comments

Comments
 (0)