Skip to content

Commit f3d19d7

Browse files
committed
Add correct handling of cexts mutex for data holder finalization.
1 parent 1c1fdfc commit f3d19d7

File tree

1 file changed

+34
-9
lines changed

1 file changed

+34
-9
lines changed

src/main/java/org/truffleruby/core/DataObjectFinalizationService.java

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@
1010
package org.truffleruby.core;
1111

1212
import java.lang.ref.ReferenceQueue;
13+
import java.util.concurrent.locks.ReentrantLock;
1314

1415
import org.truffleruby.RubyContext;
1516
import org.truffleruby.RubyLanguage;
1617
import org.truffleruby.cext.DataHolder;
1718
import org.truffleruby.core.MarkingService.ExtensionCallStack;
19+
import org.truffleruby.core.mutex.MutexOperations;
1820
import org.truffleruby.language.Nil;
1921
import org.truffleruby.language.RubyBaseRootNode;
2022
import org.truffleruby.language.backtrace.InternalRootNode;
@@ -26,6 +28,7 @@
2628
import com.oracle.truffle.api.interop.InteropLibrary;
2729
import com.oracle.truffle.api.interop.UnsupportedMessageException;
2830
import com.oracle.truffle.api.interop.UnsupportedTypeException;
31+
import com.oracle.truffle.api.profiles.ConditionProfile;
2932
import com.oracle.truffle.api.frame.VirtualFrame;
3033

3134
/** Finalizers are implemented with phantom references and reference queues, and are run in a dedicated Ruby thread. */
@@ -36,6 +39,7 @@ public static class DataObjectFinalizerRootNode extends RubyBaseRootNode impleme
3639

3740
@Child private InteropLibrary nullNode;
3841
@Child private InteropLibrary callNode;
42+
private final ConditionProfile ownedProfile = ConditionProfile.create();
3943

4044
public DataObjectFinalizerRootNode(
4145
RubyLanguage language) {
@@ -51,17 +55,44 @@ public Object execute(VirtualFrame frame) {
5155
}
5256

5357
public Object execute(DataObjectFinalizerReference ref) {
58+
if (getContext().getOptions().CEXT_LOCK) {
59+
final ReentrantLock lock = getContext().getCExtensionsLock();
60+
boolean owned = ownedProfile.profile(lock.isHeldByCurrentThread());
61+
62+
if (!owned) {
63+
MutexOperations.lockInternal(getContext(), lock, this);
64+
}
65+
try {
66+
runFinalizer(ref);
67+
} finally {
68+
if (!owned) {
69+
MutexOperations.unlockInternal(lock);
70+
}
71+
}
72+
} else {
73+
runFinalizer(ref);
74+
}
75+
return Nil.INSTANCE;
76+
}
77+
78+
private void runFinalizer(DataObjectFinalizerReference ref) throws Error {
5479
try {
5580
if (!getContext().isFinalizing()) {
5681
Object data = ref.dataHolder.getAddress();
5782
if (!nullNode.isNull(data)) {
58-
callNode.execute(ref.callable, data);
83+
final ExtensionCallStack stack = getLanguage().getCurrentThread()
84+
.getCurrentFiber().extensionCallStack;
85+
stack.push(false, stack.getSpecialVariables(), stack.getBlock());
86+
try {
87+
callNode.execute(ref.callable, data);
88+
} finally {
89+
stack.pop();
90+
}
5991
}
6092
}
6193
} catch (UnsupportedTypeException | ArityException | UnsupportedMessageException e) {
6294
throw CompilerDirectives.shouldNotReachHere("Data holder finalization on invalid object");
6395
}
64-
return Nil.INSTANCE;
6596
}
6697
}
6798

@@ -106,12 +137,6 @@ protected void processReference(RubyContext context, RubyLanguage language,
106137
@TruffleBoundary
107138
protected void processReferenceInternal(RubyContext context, RubyLanguage language,
108139
DataObjectFinalizerReference ref) {
109-
final ExtensionCallStack stack = language.getCurrentThread().getCurrentFiber().extensionCallStack;
110-
stack.push(false, stack.getSpecialVariables(), stack.getBlock());
111-
try {
112-
callTarget.call(new Object[]{ ref });
113-
} finally {
114-
stack.pop();
115-
}
140+
callTarget.call(new Object[]{ ref });
116141
}
117142
}

0 commit comments

Comments
 (0)