forked from oracle/graal
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Break the initialization cycle in NIO/cgroups code
First, we use a separate accessor for page-alignedness as it doesn't need the more sophisticated initialization of the directMemory field. Next, ensure PhysicalMemory initialization is serialized and when it is, set directMemory to a static value so that the container code can finish initialization without introducing a cyle. The final directMemory value based on the heap size is then published to JDK code by setting the VM init level to 1. Therefore, application code would use the non-static value as the upper bound. Closes: oracle#556
- Loading branch information
Showing
2 changed files
with
128 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,6 +24,9 @@ | |
*/ | ||
package com.oracle.svm.core.heap; | ||
|
||
import java.util.concurrent.CountDownLatch; | ||
import java.util.concurrent.TimeUnit; | ||
|
||
import org.graalvm.nativeimage.ImageSingletons; | ||
import org.graalvm.word.UnsignedWord; | ||
import org.graalvm.word.WordFactory; | ||
|
@@ -54,12 +57,21 @@ default boolean hasSize() { | |
UnsignedWord size(); | ||
} | ||
|
||
private static final CountDownLatch CACHED_SIZE_AVAIL_LATCH = new CountDownLatch(1); | ||
private static final AtomicInteger INITIALIZING = new AtomicInteger(0); | ||
private static final UnsignedWord UNSET_SENTINEL = UnsignedUtils.MAX_VALUE; | ||
private static UnsignedWord cachedSize = UNSET_SENTINEL; | ||
|
||
public static boolean isInitialized() { | ||
return cachedSize != UNSET_SENTINEL; | ||
return INITIALIZING.get() > 1; | ||
} | ||
|
||
/** | ||
* | ||
* @return {@code true} when PhycialMemory.size() is still initializing | ||
*/ | ||
private static boolean isInitializing() { | ||
return INITIALIZING.get() == 1; | ||
} | ||
|
||
/** | ||
|
@@ -78,24 +90,42 @@ public static UnsignedWord size() { | |
throw VMError.shouldNotReachHere("Accessing the physical memory size may require allocation and synchronization"); | ||
} | ||
|
||
if (!isInitialized()) { | ||
/* | ||
* Multiple threads can race to initialize the cache. This is OK because all of them | ||
* will (most-likely) compute the same value. | ||
*/ | ||
INITIALIZING.incrementAndGet(); | ||
try { | ||
long memoryLimit = SubstrateOptions.MaxRAM.getValue(); | ||
if (memoryLimit > 0) { | ||
cachedSize = WordFactory.unsigned(memoryLimit); | ||
} else { | ||
memoryLimit = Containers.memoryLimitInBytes(); | ||
cachedSize = memoryLimit > 0 | ||
? WordFactory.unsigned(memoryLimit) | ||
: ImageSingletons.lookup(PhysicalMemorySupport.class).size(); | ||
synchronized (INITIALIZING) { | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
jerboaa
Author
Owner
|
||
if (!isInitialized()) { | ||
VMError.guarantee(INITIALIZING.get() <= 1, "Must not initialize twice"); | ||
if (isInitializing()) { | ||
/* | ||
* Recursive initializations need to wait for the one initializing thread to | ||
* finish so as to get correct reads of the cachedSize value. | ||
*/ | ||
try { | ||
boolean expired = !CACHED_SIZE_AVAIL_LATCH.await(1L, TimeUnit.SECONDS); | ||
if (expired) { | ||
throw new InternalError("expired latch!"); | ||
} | ||
VMError.guarantee(cachedSize != UNSET_SENTINEL, "Expected chached size to be set"); | ||
return cachedSize; | ||
} catch (InterruptedException e) { | ||
throw VMError.shouldNotReachHere("Interrupt on countdown latch!"); | ||
} | ||
} | ||
INITIALIZING.incrementAndGet(); | ||
try { | ||
long memoryLimit = SubstrateOptions.MaxRAM.getValue(); | ||
if (memoryLimit > 0) { | ||
cachedSize = WordFactory.unsigned(memoryLimit); | ||
} else { | ||
memoryLimit = Containers.memoryLimitInBytes(); | ||
cachedSize = memoryLimit > 0 | ||
? WordFactory.unsigned(memoryLimit) | ||
: ImageSingletons.lookup(PhysicalMemorySupport.class).size(); | ||
} | ||
// Now that we have set the cachedSize let other threads know it's | ||
// available to use. | ||
CACHED_SIZE_AVAIL_LATCH.countDown(); | ||
} finally { | ||
INITIALIZING.incrementAndGet(); | ||
} | ||
} finally { | ||
INITIALIZING.decrementAndGet(); | ||
} | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Synchronizing on an atomic integer is a bit counter-intuitive. Is this really necessary?