Implementation of a watchdog to monitor entryDepth and take corrective action.
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10613 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/core/client/impl/Impl.java b/user/src/com/google/gwt/core/client/impl/Impl.java
index 8a90a7f..bdd4e00 100644
--- a/user/src/com/google/gwt/core/client/impl/Impl.java
+++ b/user/src/com/google/gwt/core/client/impl/Impl.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.core.client.impl;
+import com.google.gwt.core.client.Duration;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;
@@ -24,6 +25,8 @@
*/
public final class Impl {
+ private static final int WATCHDOG_ENTRY_DEPTH_CHECK_INTERVAL_MS = 2000;
+
/**
* Used by {@link #entry0(Object, Object)} to handle reentrancy.
*/
@@ -31,6 +34,16 @@
private static int sNextHashId = 0;
/**
+ * TimeStamp indicating last scheduling of the entry depth watchdog.
+ */
+ private static double watchdogEntryDepthLastScheduled;
+
+ /**
+ * Timer id of the entry depth watchdog. -1 if not scheduled.
+ */
+ private static int watchdogEntryDepthTimerId = -1;
+
+ /**
* This method should be used whenever GWT code is entered from a JS context
* and there is no GWT code in the same module on the call stack. Examples
* include event handlers, exported methods, and module initialization.
@@ -182,6 +195,14 @@
private static boolean enter() {
assert entryDepth >= 0 : "Negative entryDepth value at entry " + entryDepth;
+ if (entryDepth != 0) {
+ double now = Duration.currentTimeMillis();
+ if (now - watchdogEntryDepthLastScheduled > WATCHDOG_ENTRY_DEPTH_CHECK_INTERVAL_MS) {
+ watchdogEntryDepthLastScheduled = now;
+ watchdogEntryDepthTimerId = watchdogEntryDepthSchedule();
+ }
+ }
+
// We want to disable some actions in the reentrant case
if (entryDepth++ == 0) {
SchedulerImpl.INSTANCE.flushEntryCommands();
@@ -242,6 +263,10 @@
assert entryDepth >= 0 : "Negative entryDepth value at exit " + entryDepth;
if (initialEntry) {
assert entryDepth == 0 : "Depth not 0" + entryDepth;
+ if (watchdogEntryDepthTimerId != -1) {
+ watchdogEntryDepthCancel(watchdogEntryDepthTimerId);
+ watchdogEntryDepthTimerId = -1;
+ }
}
}
@@ -259,4 +284,29 @@
// Intentionally not returning a value
return;
}-*/;
+
+ private static native void watchdogEntryDepthCancel(int timerId) /*-{
+ $wnd.clearTimeout(timerId);
+ }-*/;
+
+ private static void watchdogEntryDepthRun() {
+ // Note: this must NEVER be called nested in a $entry() call.
+ // This method is call from a "setTimeout": entryDepth should be set to 0.
+ if (entryDepth != 0) {
+ int oldDepth = entryDepth;
+ entryDepth = 0;
+ if (GWT.getUncaughtExceptionHandler() != null) {
+ // Report the problem.
+ GWT.getUncaughtExceptionHandler().onUncaughtException(
+ new IllegalStateException("Invalid entryDepth value " + oldDepth));
+ }
+ }
+ watchdogEntryDepthTimerId = -1; // Timer has run.
+ }
+
+ private static native int watchdogEntryDepthSchedule() /*-{
+ return $wnd.setTimeout(function() {
+ @com.google.gwt.core.client.impl.Impl::watchdogEntryDepthRun()();
+ }, 10);
+ }-*/;
}