diff options
author | Hans Boehm <hboehm@google.com> | 2020-05-19 14:38:44 -0700 |
---|---|---|
committer | Hans Boehm <hboehm@google.com> | 2020-05-20 15:13:29 -0700 |
commit | e854e4f7666b2dbea90526b70dae57eaf8fab908 (patch) | |
tree | 84dff94d185f20bb13843bd3f4d2f03309d74059 /libart | |
parent | decb82134222d4eec0706b6c60f27b2a7b300079 (diff) |
Use nanoTime() in finalizer watchdog
We want to stop the clock if the processor is powered down.
Bug: 156968512
Test: art/test/testrunner/testrunner.py --host -b --64
Change-Id: Ib615851fea78df1568305b8bcf8d9bea405a8f35
(cherry picked from commit 7809156fe25b5c8aa210f61fe1234a30a27e59bb)
Diffstat (limited to 'libart')
-rw-r--r-- | libart/src/main/java/java/lang/Daemons.java | 30 |
1 files changed, 18 insertions, 12 deletions
diff --git a/libart/src/main/java/java/lang/Daemons.java b/libart/src/main/java/java/lang/Daemons.java index 568614f1c5..6e05cea805 100644 --- a/libart/src/main/java/java/lang/Daemons.java +++ b/libart/src/main/java/java/lang/Daemons.java @@ -310,7 +310,7 @@ public final class Daemons { private boolean needToWork = true; // Only accessed in synchronized methods. - private long finalizerTimeoutMs = 0; // Lazily initialized. + private long finalizerTimeoutNs = 0; // Lazily initialized. FinalizerWatchdogDaemon() { super("FinalizerWatchdogDaemon"); @@ -370,17 +370,22 @@ public final class Daemons { } /** - * Sleep for the given number of milliseconds. + * Sleep for the given number of nanoseconds, or slightly longer. * @return false if we were interrupted. */ - private boolean sleepForMillis(long durationMillis) { - long startMillis = System.currentTimeMillis(); + private boolean sleepForNanos(long durationNanos) { + // It's important to base this on nanoTime(), not currentTimeMillis(), since + // the former stops counting when the processor isn't running. + long startNanos = System.nanoTime(); while (true) { - long elapsedMillis = System.currentTimeMillis() - startMillis; - long sleepMillis = durationMillis - elapsedMillis; - if (sleepMillis <= 0) { + long elapsedNanos = System.nanoTime() - startNanos; + long sleepNanos = durationNanos - elapsedNanos; + if (sleepNanos <= 0) { return true; } + // Ensure the nano time is always rounded up to the next whole millisecond, + // ensuring the delay is >= the requested delay. + long sleepMillis = (sleepNanos + NANOS_PER_MILLI - 1) / NANOS_PER_MILLI; try { Thread.sleep(sleepMillis); } catch (InterruptedException e) { @@ -403,14 +408,15 @@ public final class Daemons { * null. Only called from a single thread. */ private Object waitForFinalization() { - if (finalizerTimeoutMs == 0) { - finalizerTimeoutMs = VMRuntime.getRuntime().getFinalizerTimeoutMs(); + if (finalizerTimeoutNs == 0) { + finalizerTimeoutNs = + NANOS_PER_MILLI * VMRuntime.getRuntime().getFinalizerTimeoutMs(); // Temporary app backward compatibility. Remove eventually. - MAX_FINALIZE_NANOS = NANOS_PER_MILLI * finalizerTimeoutMs; + MAX_FINALIZE_NANOS = finalizerTimeoutNs; } long startCount = FinalizerDaemon.INSTANCE.progressCounter.get(); // Avoid remembering object being finalized, so as not to keep it alive. - if (!sleepForMillis(finalizerTimeoutMs)) { + if (!sleepForNanos(finalizerTimeoutNs)) { // Don't report possibly spurious timeout if we are interrupted. return null; } @@ -431,7 +437,7 @@ public final class Daemons { // just finished as we were timing out, in which case we may get null or a later // one. In this last case, we are very likely to discard it below. Object finalizing = FinalizerDaemon.INSTANCE.finalizingObject; - sleepForMillis(500); + sleepForNanos(500 * NANOS_PER_MILLI); // Recheck to make it even less likely we report the wrong finalizing object in // the case which a very slow finalization just finished as we were timing out. if (getNeedToWork() |