Skip to content

Commit d47c6e1

Browse files
[GR-69306] Fix rare race conditions.
PullRequest: graal/22033
2 parents d8ab154 + 21d1a67 commit d47c6e1

File tree

2 files changed

+19
-39
lines changed

2 files changed

+19
-39
lines changed

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/SystemPropertiesSupport.java

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
package com.oracle.svm.core.jdk;
2626

2727
import static jdk.graal.compiler.core.common.LibGraalSupport.LIBGRAAL_SETTING_PROPERTY_PREFIX;
28-
import static jdk.graal.compiler.nodes.extended.MembarNode.FenceKind.STORE_STORE;
2928

3029
import java.util.ArrayList;
3130
import java.util.Collections;
@@ -45,14 +44,12 @@
4544

4645
import com.oracle.svm.core.FutureDefaultsOptions;
4746
import com.oracle.svm.core.SubstrateOptions;
48-
import com.oracle.svm.core.SubstrateUtil;
4947
import com.oracle.svm.core.VM;
5048
import com.oracle.svm.core.c.locale.LocaleSupport;
5149
import com.oracle.svm.core.config.ConfigurationValues;
5250
import com.oracle.svm.core.util.VMError;
5351

5452
import jdk.graal.compiler.api.replacements.Fold;
55-
import jdk.graal.compiler.nodes.extended.MembarNode;
5653

5754
/**
5855
* This class maintains the system properties at run time.
@@ -294,8 +291,8 @@ private synchronized void initializeAllProperties() {
294291
}
295292

296293
/*
297-
* No memory barrier is needed because the loop above already emits one STORE_STORE barrier
298-
* per initialized system property.
294+
* No memory barrier is needed here (same reasoning as for
295+
* LazySystemProperty.markAsInitialized()).
299296
*/
300297
allPropertiesInitialized = true;
301298
}
@@ -318,13 +315,7 @@ private void ensurePropertyInitialized(String key) {
318315
}
319316

320317
LazySystemProperty property = lazySystemProperties.get(key);
321-
if (property != null) {
322-
ensureInitialized(property);
323-
}
324-
}
325-
326-
private void ensureInitialized(LazySystemProperty property) {
327-
if (!property.isInitialized()) {
318+
if (property != null && !property.isInitialized()) {
328319
initializeProperty(property);
329320
}
330321
}
@@ -385,11 +376,12 @@ public String computeValue() {
385376
return supplier.get();
386377
}
387378

379+
/**
380+
* No memory barrier is needed here because the involved maps ({@link #initialProperties}
381+
* and {@link #currentProperties}) already use acquire/release semantics when a value is
382+
* added or accessed.
383+
*/
388384
public void markAsInitialized() {
389-
if (!SubstrateUtil.HOSTED) {
390-
/* Ensure that other threads see consistent values once 'initialized' is true. */
391-
MembarNode.memoryBarrier(STORE_STORE);
392-
}
393385
initialized = true;
394386
}
395387
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_jdk_internal_misc_VM.java

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@
3737
import com.oracle.svm.core.annotate.TargetClass;
3838
import com.oracle.svm.core.snippets.KnownIntrinsics;
3939

40-
import jdk.internal.misc.Unsafe;
41-
4240
@TargetClass(className = "jdk.internal.misc.VM")
4341
public final class Target_jdk_internal_misc_VM {
4442
/** Ensure that we do not leak the full set of properties from the image generator. */
@@ -72,11 +70,14 @@ public static ClassLoader latestUserDefinedLoader0() {
7270
}
7371

7472
final class DirectMemoryAccessors {
75-
/*
76-
* Not volatile to avoid a memory barrier when reading the values. Instead, an explicit barrier
77-
* is inserted when writing the values.
73+
/**
74+
* This field needs to be volatile to ensure that reads emit a LOAD-LOAD barrier. Without this
75+
* barrier, subsequent reads could be reordered before the read of {@link #initialized},
76+
* allowing threads to observe an uninitialized value for {@link #directMemory}. We could
77+
* directly emit a LOAD-LOAD barrier instead, but it doesn't make any difference in terms of the
78+
* used instructions on any of the relevant CPU architectures.
7879
*/
79-
private static boolean initialized;
80+
private static volatile boolean initialized;
8081
private static long directMemory;
8182

8283
static long getDirectMemory() {
@@ -102,27 +103,16 @@ private static long tryInitialize() {
102103
newDirectMemory = Runtime.getRuntime().maxMemory();
103104
}
104105

105-
/*
106-
* The initialization is not synchronized, so multiple threads can race. Usually this will
107-
* lead to the same value, unless the runtime options are modified concurrently - which is
108-
* possible but not a case we care about.
109-
*/
110106
directMemory = newDirectMemory;
111-
112-
/* Ensure values are published to other threads before marking fields as initialized. */
113-
Unsafe.getUnsafe().storeFence();
107+
/* STORE_STORE barrier is executed as part of the volatile write. */
114108
initialized = true;
115-
116109
return newDirectMemory;
117110
}
118111
}
119112

120113
final class PageAlignDirectMemoryAccessors {
121-
/*
122-
* Not volatile to avoid a memory barrier when reading the values. Instead, an explicit barrier
123-
* is inserted when writing the values.
124-
*/
125-
private static boolean initialized;
114+
/** See {@link DirectMemoryAccessors#initialized} on why this needs to be volatile. */
115+
private static volatile boolean initialized;
126116
private static boolean pageAlignDirectMemory;
127117

128118
static Boolean getPageAlignDirectMemory() {
@@ -134,9 +124,7 @@ static Boolean getPageAlignDirectMemory() {
134124

135125
private static void initialize() {
136126
pageAlignDirectMemory = Boolean.getBoolean("sun.nio.PageAlignDirectMemory");
137-
138-
/* Ensure values are published to other threads before marking fields as initialized. */
139-
Unsafe.getUnsafe().storeFence();
127+
/* STORE_STORE barrier is executed as part of the volatile write. */
140128
initialized = true;
141129
}
142130
}

0 commit comments

Comments
 (0)