Skip to content

Commit

Permalink
[GR-18163] Share a Fiber as soon as it's created and sharing is enabled
Browse files Browse the repository at this point in the history
PullRequest: truffleruby/4379
  • Loading branch information
eregon committed Oct 18, 2024
2 parents a589693 + bf03c32 commit 9b191b0
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 12 deletions.
12 changes: 12 additions & 0 deletions spec/truffle/thread_safe_objects_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,18 @@ def wb; @wb; end
end.join
end

it "Fiber which refers to an Array via instance variables" do
a = [Object.new]
f = Fiber.new { 42 }
shared?(f).should == true

f.instance_variable_set(:@a, a)
shared?(a).should == true
shared?(a[0]).should == true

f.resume.should == 42
end

it "Thread local variables which share the value (probably they should not)" do
thread = Thread.current
shared?(thread).should == true
Expand Down
15 changes: 4 additions & 11 deletions src/main/java/org/truffleruby/core/fiber/FiberManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.source.SourceSection;
import org.truffleruby.language.objects.shared.SharedObjects;

/** Helps managing Ruby {@code Fiber} objects. Only one per {@link RubyContext}. */
Expand All @@ -58,14 +57,6 @@ public FiberManager(RubyLanguage language, RubyContext context) {
this.context = context;
}

public void initialize(RubyFiber fiber, boolean blocking, RubyProc block, Node currentNode) {
final SourceSection sourceSection = block.getSharedMethodInfo().getSourceSection();
fiber.sourceLocation = context.fileLine(sourceSection);
fiber.body = block;
fiber.initializeNode = currentNode;
fiber.blocking = blocking;
}

private void createThreadToReceiveFirstMessage(RubyFiber fiber, Node currentNode) {
assert fiber.thread == null;
RubyProc block = Objects.requireNonNull(fiber.body);
Expand Down Expand Up @@ -347,8 +338,10 @@ public void start(RubyFiber fiber, Thread javaThread) {

final RubyThread rubyThread = fiber.rubyThread;

// share RubyFiber as its fiberLocals might be accessed by other threads with Thread#[]
SharedObjects.propagate(language, rubyThread, fiber);
// The RubyFiber has been shared in RubyFiber#initialize,
// or by ThreadManager#startSharing for the root Fiber of a RubyThread.
assert !SharedObjects.isShared(rubyThread) || SharedObjects.isShared(fiber);

rubyThread.runningFibers.add(fiber);
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/truffleruby/core/fiber/FiberNodes.java
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ Object initialize(RubyFiber fiber, boolean blocking, RubyProc block) {
coreExceptions().securityError("fibers not allowed with allowCreateThread(false)", this));
}

getContext().fiberManager.initialize(fiber, blocking, block, this);
fiber.initialize(getLanguage(), getContext(), blocking, block, this);
return nil;
}

Expand Down
14 changes: 14 additions & 0 deletions src/main/java/org/truffleruby/core/fiber/RubyFiber.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.exception.AbstractTruffleException;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.source.SourceSection;
import org.truffleruby.RubyContext;
import org.truffleruby.RubyLanguage;
import org.truffleruby.cext.ValueWrapperManager;
Expand All @@ -36,6 +37,7 @@

import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.object.Shape;
import org.truffleruby.language.objects.shared.SharedObjects;

import static org.truffleruby.language.RubyBaseNode.nil;

Expand Down Expand Up @@ -131,6 +133,18 @@ public RubyFiber(
handleData = new ValueWrapperManager.HandleBlockHolder();
}

public void initialize(RubyLanguage language, RubyContext context, boolean blocking, RubyProc block,
Node currentNode) {
final SourceSection sourceSection = block.getSharedMethodInfo().getSourceSection();
this.sourceLocation = context.fileLine(sourceSection);
this.body = block;
this.initializeNode = currentNode;
this.blocking = blocking;

// share RubyFiber as its fiberLocals might be accessed by other threads with Thread#[]
SharedObjects.propagate(language, this.rubyThread, this);
}

public boolean isRootFiber() {
return rubyThread.getRootFiber() == this;
}
Expand Down
1 change: 1 addition & 0 deletions src/main/java/org/truffleruby/core/thread/RubyThread.java
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ public void getAdjacentObjects(Set<Object> reachable) {
ObjectGraph.addProperty(reachable, threadLocalVariables);
ObjectGraph.addProperty(reachable, name);
// share fibers of a thread as its fiberLocals might be accessed by other threads with Thread#[]
reachable.add(rootFiber);
reachable.addAll(runningFibers);
}

Expand Down

0 comments on commit 9b191b0

Please sign in to comment.