diff options
author | Jiri Vanek <[email protected]> | 2013-05-20 15:13:32 +0200 |
---|---|---|
committer | Jiri Vanek <[email protected]> | 2013-05-20 15:13:32 +0200 |
commit | 0807c9fc6f5b44323c53413341eb4026de919ff6 (patch) | |
tree | dfa69866aa2110ee8b883d4c64549a01e173ac94 | |
parent | 60193e3eb63eb578d6e5da3d43830013d1b21211 (diff) |
Fixed possible deadlock for applet->js->applet call with testcase
5 files changed, 278 insertions, 12 deletions
@@ -1,3 +1,19 @@ +2013-05-20 Jiri Vanek <[email protected]> + + Fixed possible deadlock for applet->js->applet call + * plugin/icedteanp/java/sun/applet/PluginAppletViewer.java: + (REQUEST_TIMEOUT) new constant, 60s, to define timeout of applet->js call + (waitForRequestCompletion) new method waiting to request to be done with + timeout of REQUEST_TIMEOUT. + (javascriptToString) using the waitForRequestCompletion instead of plain + wait() + * tests/reproducers/simple/AppletJsAppletDeadlock/resources/AppletJsAppletDeadlock.html + and + * tests/reproducers/simple/AppletJsAppletDeadlock/srcs/AppletJsAppletDeadlock.java + reproducer + * tests/reproducers/simple/AppletJsAppletDeadlock/testcases/AppletJsAppletDeadlockTest.java + testcase + 2013-05-17 Adam Domurad <[email protected]> Fix PR854: Resizing an applet several times causes 100% CPU load diff --git a/plugin/icedteanp/java/sun/applet/PluginAppletViewer.java b/plugin/icedteanp/java/sun/applet/PluginAppletViewer.java index 3feedd6..8aab9ac 100644 --- a/plugin/icedteanp/java/sun/applet/PluginAppletViewer.java +++ b/plugin/icedteanp/java/sun/applet/PluginAppletViewer.java @@ -181,7 +181,23 @@ public class PluginAppletViewer extends XEmbeddedFrame private SplashPanel splashPanel; - + + private static long REQUEST_TIMEOUT=60000;//60s + + private static void waitForRequestCompletion(PluginCallRequest request) { + try { + if (!request.isDone()) { + request.wait(REQUEST_TIMEOUT); + } + if (!request.isDone()) { + // Do not wait indefinitely to avoid the potential of deadlock + throw new RuntimeException("Possible deadlock, releasing"); + } + } catch (InterruptedException ex) { + throw new RuntimeException("Interrupted waiting for call request.", ex); + } + } + /** * Null constructor to allow instantiation via newInstance() */ @@ -1290,18 +1306,13 @@ public class PluginAppletViewer extends XEmbeddedFrame streamhandler.postCallRequest(request); streamhandler.write(request.getMessage()); - try { - PluginDebug.debug("wait ToString request 1"); - synchronized (request) { - PluginDebug.debug("wait ToString request 2"); - while (request.isDone() == false) - request.wait(); - PluginDebug.debug("wait ToString request 3"); - } - } catch (InterruptedException e) { - throw new RuntimeException("Interrupted waiting for call request.", - e); + PluginDebug.debug("wait ToString request 1"); + synchronized (request) { + PluginDebug.debug("wait ToString request 2"); + waitForRequestCompletion(request); + PluginDebug.debug("wait ToString request 3"); } + PluginDebug.debug(" ToString DONE"); return (String) request.getObject(); } diff --git a/tests/reproducers/simple/AppletJsAppletDeadlock/resources/AppletJsAppletDeadlock.html b/tests/reproducers/simple/AppletJsAppletDeadlock/resources/AppletJsAppletDeadlock.html new file mode 100644 index 0000000..f5e4af4 --- /dev/null +++ b/tests/reproducers/simple/AppletJsAppletDeadlock/resources/AppletJsAppletDeadlock.html @@ -0,0 +1,55 @@ +<!-- + +This file is part of IcedTea. + +IcedTea is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +IcedTea is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with IcedTea; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. + +--> +<html><script> + function callApplet_real() { + document.getElementById('theApplet').jsCallback(document.location); + } + + function callApplet_wrap() { + setTimeout(callApplet_real, 1000); + } + + function callApplet() { + callApplet_real(); + //callApplet_wrap(); + } + </script><body> + <p><applet id="theApplet" type="application/x-java-applet" + codebase="." archive="AppletJsAppletDeadlock.jar" code="AppletJsAppletDeadlock.class" width="800" height="250"> + </applet></p> +</body></html> diff --git a/tests/reproducers/simple/AppletJsAppletDeadlock/srcs/AppletJsAppletDeadlock.java b/tests/reproducers/simple/AppletJsAppletDeadlock/srcs/AppletJsAppletDeadlock.java new file mode 100644 index 0000000..459ea7d --- /dev/null +++ b/tests/reproducers/simple/AppletJsAppletDeadlock/srcs/AppletJsAppletDeadlock.java @@ -0,0 +1,89 @@ +/* + Copyright (C) 2012 Red Hat, Inc. + + This file is part of IcedTea. + + IcedTea is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as published by + the Free Software Foundation, version 2. + + IcedTea is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with IcedTea; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. + */ + +import java.awt.TextArea; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.URL; +import java.net.URLConnection; +import netscape.javascript.JSObject; + +public class AppletJsAppletDeadlock extends java.applet.Applet { + + private TextArea outputText = null; + + public void printOutput(String msg) { + System.out.println(msg); + outputText.setText(outputText.getText() + msg + "\n"); + } + + public void jsCallback(String location) { + printOutput("Callback function called"); + + // try requesting the page + try { + URL url = new URL(location); + URLConnection con = url.openConnection(); + BufferedReader br = new BufferedReader(new InputStreamReader( + con.getInputStream())); + + String line; + while ((line = br.readLine()) != null) { + System.err.println(line); + } + + printOutput("Succesfully connected to " + location); + } catch (Exception e) { + printOutput("Failed to connect to '" + location + "': " + e.getMessage()); + } + + } + + @Override + public void start() { +// public void init() { + outputText = new TextArea("", 12, 95); + this.add(outputText); + + printOutput("AppletJsAppletDeadlock started"); + + JSObject win = JSObject.getWindow(this); + win.eval("callApplet();"); + + printOutput("JS call finished"); + } +} diff --git a/tests/reproducers/simple/AppletJsAppletDeadlock/testcases/AppletJsAppletDeadlockTest.java b/tests/reproducers/simple/AppletJsAppletDeadlock/testcases/AppletJsAppletDeadlockTest.java new file mode 100644 index 0000000..ce4fa5b --- /dev/null +++ b/tests/reproducers/simple/AppletJsAppletDeadlock/testcases/AppletJsAppletDeadlockTest.java @@ -0,0 +1,95 @@ +/* + Copyright (C) 2012 Red Hat, Inc. + + This file is part of IcedTea. + + IcedTea is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as published by + the Free Software Foundation, version 2. + + IcedTea is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with IcedTea; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. + */ + +import net.sourceforge.jnlp.ProcessResult; +import net.sourceforge.jnlp.ServerAccess; +import net.sourceforge.jnlp.annotations.KnownToFail; +import net.sourceforge.jnlp.annotations.NeedsDisplay; +import net.sourceforge.jnlp.annotations.TestInBrowsers; +import net.sourceforge.jnlp.browsertesting.BrowserTest; +import net.sourceforge.jnlp.browsertesting.Browsers; +import net.sourceforge.jnlp.closinglisteners.RulesFolowingClosingListener; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +public class AppletJsAppletDeadlockTest extends BrowserTest { + + private static final String called = "Callback function called"; + private static final String started = "AppletJsAppletDeadlock started"; + private static final String finished = "JS call finished"; + private static final RulesFolowingClosingListener.ContainsRule calledRule = new RulesFolowingClosingListener.ContainsRule(called); + private static final RulesFolowingClosingListener.ContainsRule startedRule = new RulesFolowingClosingListener.ContainsRule(started); + private static final RulesFolowingClosingListener.ContainsRule finishedRule = new RulesFolowingClosingListener.ContainsRule(finished); + private static final long defaultTimeout = ServerAccess.PROCESS_TIMEOUT; + + @BeforeClass + public static void setTimeout() { + //the timeout is js call is 60s + //see sun.applet.PluginAppletViewer.REQUEST_TIMEOUT + //so wee need to have little longer timooute here + ServerAccess.PROCESS_TIMEOUT = 120000;//120 s + } + + @AfterClass + public static void resetTimeout() { + ServerAccess.PROCESS_TIMEOUT = defaultTimeout; + } + + @Test + @NeedsDisplay + @TestInBrowsers(testIn = Browsers.one) + public void callAppletJsAppletNotDeadlock() throws Exception { + ProcessResult processResult = server.executeBrowser("AppletJsAppletDeadlock.html", new RulesFolowingClosingListener(finishedRule), null); + Assert.assertTrue(startedRule.toPassingString(), startedRule.evaluate(processResult.stdout)); + Assert.assertTrue(finishedRule.toPassingString(), finishedRule.evaluate(processResult.stdout)); + //this is representing another error, not sure now it is worthy to be fixed + //Assert.assertTrue(calledRule.toPassingString(), calledRule.evaluate(processResult.stdout)); + } + + @Test + @NeedsDisplay + @TestInBrowsers(testIn = Browsers.one) + @KnownToFail + public void callAppletJsAppletSuccessfullyEvaluated() throws Exception { + ProcessResult processResult = server.executeBrowser("AppletJsAppletDeadlock.html", new RulesFolowingClosingListener(finishedRule), null); + Assert.assertTrue(startedRule.toPassingString(), startedRule.evaluate(processResult.stdout)); + Assert.assertTrue(finishedRule.toPassingString(), finishedRule.evaluate(processResult.stdout)); + Assert.assertTrue(calledRule.toPassingString(), calledRule.evaluate(processResult.stdout)); + } +} |