Skip to content

Commit ff7a2b2

Browse files
author
Nicolas Laurent
committed
[GR-29137] Add a timeout to Primitive.gc_force & further try to avoid infinite loop
PullRequest: truffleruby/2390
2 parents b7a61ac + 8427656 commit ff7a2b2

File tree

1 file changed

+25
-5
lines changed

1 file changed

+25
-5
lines changed

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

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import java.lang.management.GarbageCollectorMXBean;
1313
import java.lang.management.ManagementFactory;
14+
import java.time.Duration;
1415

1516
import org.truffleruby.SuppressFBWarnings;
1617
import org.truffleruby.builtins.CoreMethod;
@@ -23,6 +24,7 @@
2324
import org.truffleruby.builtins.PrimitiveArrayArgumentsNode;
2425
import org.truffleruby.collections.WeakValueCache;
2526
import org.truffleruby.language.SafepointManager;
27+
import org.truffleruby.language.control.RaiseException;
2628

2729
@CoreModule("GC")
2830
public abstract class GCNodes {
@@ -52,27 +54,45 @@ protected Object vmGCStart() {
5254
@Primitive(name = "gc_force")
5355
public static abstract class GCForce extends PrimitiveArrayArgumentsNode {
5456

55-
@SuppressFBWarnings("DLS")
5657
@TruffleBoundary
5758
@Specialization
5859
protected Object force() {
5960
getContext().getMarkingService().queueMarking();
60-
Object key = new Object();
61-
Object value = new Object();
6261

6362
// NOTE(norswap, 16 Apr 20): We could have used a WeakReference here, but the hope is that the extra
6463
// indirection will prevent the compiler to optimize this method away (assuming JIT compilation, and
6564
// the fact that such an optimizaton is permitted and possible, both of which are unlikely).
6665
WeakValueCache<Object, Object> cache = new WeakValueCache<>();
66+
Object key = new Object();
67+
68+
// NOTE(norswap, 02 Feb 21): The split into two methods here is another way to try to outwit optimizations
69+
// by making sure the method that allocates the weak value is exited before we run the GC loop;
70+
initCache(cache, key);
71+
gcLoop(cache, key);
72+
return nil;
73+
}
74+
75+
@SuppressFBWarnings("DLS")
76+
private void initCache(WeakValueCache<Object, Object> cache, Object key) {
77+
Object value = new Object();
6778
cache.put(key, value);
6879
value = null;
80+
}
6981

82+
private void gcLoop(WeakValueCache<Object, Object> cache, Object key) {
83+
final long duration = Duration.ofSeconds(60).toNanos();
84+
final long start = System.nanoTime();
7085
do {
86+
if (System.nanoTime() - start > duration) {
87+
throw new RaiseException(
88+
getContext(),
89+
getContext().getCoreExceptions().runtimeError(
90+
"gc_force exceeded its 60 seconds timeout",
91+
this));
92+
}
7193
System.gc();
7294
SafepointManager.poll(getLanguage(), this);
7395
} while (cache.get(key) != null);
74-
75-
return nil;
7696
}
7797
}
7898

0 commit comments

Comments
 (0)