From fd8e1f6d0601cd025f7f9e4c605a396bbafe2a60 Mon Sep 17 00:00:00 2001 From: Mathieu Chartier Date: Thu, 18 Sep 2014 18:31:52 -0700 Subject: Change FinalizerWatchdogDaemon to not hold objects live Previously, waitForFinalization would hold whatever object was being finalized live for MAX_FINALIZE_NANOS even though the finalizer on this object was run much earlier. This caused a test to be flaky since it was assuming that the JNI weak global reference of a recently finalized object wouldn't be held live. Bug: 17305633 (cherry picked from commit 6ba680664fa14a547543a8c63708543ea8072680) Change-Id: Ide60db55190a3764c16e4919a7c71a113cbf3968 --- libart/src/main/java/java/lang/Daemons.java | 33 +++++++++++++++++++---------- 1 file changed, 22 insertions(+), 11 deletions(-) (limited to 'libart') diff --git a/libart/src/main/java/java/lang/Daemons.java b/libart/src/main/java/java/lang/Daemons.java index 1422c13..71a8d86 100644 --- a/libart/src/main/java/java/lang/Daemons.java +++ b/libart/src/main/java/java/lang/Daemons.java @@ -192,6 +192,7 @@ public final class Daemons { // The RI silently swallows these, but Android has always logged. System.logE("Uncaught exception thrown by finalizer", ex); } finally { + // Done finalizing, stop holding the object as live. finalizingObject = null; } } @@ -207,24 +208,29 @@ public final class Daemons { @Override public void run() { while (isRunning()) { - Object object = waitForObject(); - if (object == null) { + boolean waitSuccessful = waitForObject(); + if (waitSuccessful == false) { // We have been interrupted, need to see if this daemon has been stopped. continue; } - boolean finalized = waitForFinalization(object); + boolean finalized = waitForFinalization(); if (!finalized && !VMRuntime.getRuntime().isDebuggerActive()) { - finalizerTimedOut(object); - break; + Object finalizedObject = FinalizerDaemon.INSTANCE.finalizingObject; + // At this point we probably timed out, look at the object in case the finalize + // just finished. + if (finalizedObject != null) { + finalizerTimedOut(finalizedObject); + break; + } } } } - private Object waitForObject() { + private boolean waitForObject() { while (true) { Object object = FinalizerDaemon.INSTANCE.finalizingObject; if (object != null) { - return object; + return true; } synchronized (this) { // wait until something is ready to be finalized @@ -233,7 +239,7 @@ public final class Daemons { wait(); } catch (InterruptedException e) { // Daemon.stop may have interrupted us. - return null; + return false; } } } @@ -257,9 +263,14 @@ public final class Daemons { } } - private boolean waitForFinalization(Object object) { - sleepFor(FinalizerDaemon.INSTANCE.finalizingStartedNanos, MAX_FINALIZE_NANOS); - return object != FinalizerDaemon.INSTANCE.finalizingObject; + private boolean waitForFinalization() { + long startTime = FinalizerDaemon.INSTANCE.finalizingStartedNanos; + sleepFor(startTime, MAX_FINALIZE_NANOS); + // If we are finalizing an object and the start time is the same, it must be that we + // timed out finalizing something. It may not be the same object that we started out + // with but this doesn't matter. + return FinalizerDaemon.INSTANCE.finalizingObject == null || + FinalizerDaemon.INSTANCE.finalizingStartedNanos != startTime; } private static void finalizerTimedOut(Object object) { -- cgit v1.1