[ https://issues.apache.org/jira/browse/NETBEANS-4696?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17189010#comment-17189010 ]
Jaroslav Tulach edited comment on NETBEANS-4696 at 9/2/20, 6:20 AM: -------------------------------------------------------------------- The general rule to fight with deadlocks in an API is [never hold a lock when calling foreign code|http://wiki.apidesign.org/wiki/Deadlock]. However in this case it is not that easy to find out who's an API and who's the client. What can help is to topologically sort and layer the modules according to their runtime dependencies - the ones below are an API, the ones above are clients. Then a callback from below to above which holds a lock would be problematic. Such a callback is happening in the deadlock: {code:java} org.netbeans.modules.html.knockout.KOHtmlExtension.isCustomTag(KOHtmlExtension.java:302) is being called by "lower" module: org.netbeans.modules.html.editor.gsf.HtmlGSFParser$1.isCustomTag(HtmlGSFParser.java:109) is being called by "lower" module: org.netbeans.modules.html.editor.lib.api.SyntaxAnalyzerResult.doParseHtml(SyntaxAnalyzerResult.java:259) is being called by "lower" module: org.netbeans.modules.csl.navigation.ElementScanningTask$1.run(ElementScanningTask.java:149) is being called by "lower" module: org.netbeans.modules.parsing.impl.TaskProcessor.callUserTask {code} Parsing API doesn't really hold a "lock", but it only runs in a single dedicated thread (which is a shared, spare resource too). Can we avoid that? Too hard, right [~tomas_zezula] & [~zezulato...@gmail.com] & [~tzezula]? This is a core of the indexing infrastructure. We don't want to touch it. Who else to blame? Let's make a rule: Whoever registers an indexer, isn't allowed to make a call to modules "above" Parsing API. With such rule, it is clear that {{KOHtmlExtension}} breaks it by calling into Project UI API . Take a look at [four deadlock conditions|http://wiki.apidesign.org/wiki/Deadlock_conditions] and select one to break the deadlock the simplest way. This would do it: {code:java} --- a/webcommon/javascript2.knockout/src/org/netbeans/modules/javascript2/knockout/index/KnockoutIndex.java +++ b/webcommon/javascript2.knockout/src/org/netbeans/modules/javascript2/knockout/index/KnockoutIndex.java @@ -27,6 +27,8 @@ import java.util.Map; import java.util.WeakHashMap; import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.logging.Logger; import org.netbeans.api.project.Project; import org.netbeans.api.project.ui.OpenProjects; @@ -57,8 +59,8 @@ if (!areProjectsOpen) { try { // just be sure that the projects are open - OpenProjects.getDefault().openProjects().get(); - } catch (InterruptedException | ExecutionException ex) { + OpenProjects.getDefault().openProjects().get(10, TimeUnit.SECONDS); + } catch (InterruptedException | ExecutionException | TimeoutException ex) { Exceptions.printStackTrace(ex); } finally { areProjectsOpen = true; {code} e.g. don't wait indefinitely. However given [Roman Svitanič's comment|https://github.com/emilianbold/netbeans-releases/commit/30092308c4fef#diff-b6844ad6d2c225bbb1c8d6c0287d6a6cR80] "just be sure that the projects are open" - I'd suggest to delete the whole {{areProjectsOpen}} check. This shouldn't be here at all. If the dependency of {{javascript2.knockout}} module on Project UI API can be removed, then even better! If you need a hotfix for 12.1, then I'd go with the 10s timeout shown above. In the long term I suggest to apply following fix... {code:java} webcommon/javascript2.knockout$ git diff . diff --git a/webcommon/javascript2.knockout/nbproject/project.xml b/webcommon/javascript2.knockout/nbproject/project.xml index 3f6fae4f8de0..47a191a3496d 100644 --- a/webcommon/javascript2.knockout/nbproject/project.xml +++ b/webcommon/javascript2.knockout/nbproject/project.xml @@ -96,15 +96,6 @@ <specification-version>1.61</specification-version> </run-dependency> </dependency> - <dependency> - <code-name-base>org.netbeans.modules.projectuiapi.base</code-name-base> - <build-prerequisite/> - <compile-dependency/> - <run-dependency> - <release-version>1</release-version> - <specification-version>1.78</specification-version> - </run-dependency> - </dependency> <dependency> <code-name-base>org.openide.filesystems</code-name-base> <build-prerequisite/> diff --git a/webcommon/javascript2.knockout/src/org/netbeans/modules/javascript2/knockout/index/KnockoutIndex.java b/webcommon/javascript2.knockout/src/org/netbeans/modules/javascript2/knockout/index/KnockoutIndex.java index eec45ef5b673..42676c1e14d4 100644 --- a/webcommon/javascript2.knockout/src/org/netbeans/modules/javascript2/knockout/index/KnockoutIndex.java +++ b/webcommon/javascript2.knockout/src/org/netbeans/modules/javascript2/knockout/index/KnockoutIndex.java @@ -26,10 +26,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.WeakHashMap; :...skipping... diff --git a/webcommon/javascript2.knockout/nbproject/project.xml b/webcommon/javascript2.knockout/nbproject/project.xml index 3f6fae4f8de0..47a191a3496d 100644 --- a/webcommon/javascript2.knockout/nbproject/project.xml +++ b/webcommon/javascript2.knockout/nbproject/project.xml @@ -96,15 +96,6 @@ <specification-version>1.61</specification-version> </run-dependency> </dependency> - <dependency> - <code-name-base>org.netbeans.modules.projectuiapi.base</code-name-base> - <build-prerequisite/> - <compile-dependency/> - <run-dependency> - <release-version>1</release-version> - <specification-version>1.78</specification-version> - </run-dependency> - </dependency> <dependency> <code-name-base>org.openide.filesystems</code-name-base> <build-prerequisite/> diff --git a/webcommon/javascript2.knockout/src/org/netbeans/modules/javascript2/knockout/index/KnockoutIndex.java b/webcommon/javascript2.knockout/src/org/netbeans/modules/javascript2/knockout/index/KnockoutIndex.java index eec45ef5b673..42676c1e14d4 100644 --- a/webcommon/javascript2.knockout/src/org/netbeans/modules/javascript2/knockout/index/KnockoutIndex.java +++ b/webcommon/javascript2.knockout/src/org/netbeans/modules/javascript2/knockout/index/KnockoutIndex.java @@ -26,10 +26,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.WeakHashMap; -import java.util.concurrent.ExecutionException; -import java.util.logging.Logger; import org.netbeans.api.project.Project; -import org.netbeans.api.project.ui.OpenProjects; import org.netbeans.modules.parsing.spi.indexing.support.IndexResult; import org.netbeans.modules.parsing.spi.indexing.support.QuerySupport; import org.openide.filesystems.FileObject; @@ -40,12 +37,8 @@ import org.openide.util.Exceptions; * @author Roman Svitanic */ public class KnockoutIndex { - - private static final Logger LOGGER = Logger.getLogger(KnockoutIndex.class.getSimpleName()); - private static final Map<Project, KnockoutIndex> INDEXES = new WeakHashMap<>(); private final QuerySupport querySupport; - private static boolean areProjectsOpen = false; public static KnockoutIndex get(Project project) throws IOException { if (project == null) { @@ -54,16 +47,6 @@ public class KnockoutIndex { synchronized (INDEXES) { KnockoutIndex index = INDEXES.get(project); if (index == null) { - if (!areProjectsOpen) { - try { - // just be sure that the projects are open - OpenProjects.getDefault().openProjects().get(); - } catch (InterruptedException | ExecutionException ex) { - Exceptions.printStackTrace(ex); - } finally { - areProjectsOpen = true; - } - } Collection<FileObject> sourceRoots = QuerySupport.findRoots(project, null /* all source roots */, Collections.<String>emptyList(), {code} ...and wait to see what kind of problems it causes. Chances are (in my opinion) high that (except failing unittests) nobody complains. was (Author: jtulach): The general rule to fight with deadlocks in an API is [never hold a lock when calling foreign code|http://wiki.apidesign.org/wiki/Deadlock]. However in this case it is not that easy to find out who's an API and who's the client. What can help is to topologically sort and layer the modules according to their runtime dependencies - the ones below are an API, the ones above are clients. Then a callback from below to above which holds a lock would be problematic. Such a callback is happening in the deadlock: {code:java} org.netbeans.modules.html.knockout.KOHtmlExtension.isCustomTag(KOHtmlExtension.java:302) is being called by "lower" module: org.netbeans.modules.html.editor.gsf.HtmlGSFParser$1.isCustomTag(HtmlGSFParser.java:109) is being called by "lower" module: org.netbeans.modules.html.editor.lib.api.SyntaxAnalyzerResult.doParseHtml(SyntaxAnalyzerResult.java:259) is being called by "lower" module: org.netbeans.modules.csl.navigation.ElementScanningTask$1.run(ElementScanningTask.java:149) is being called by "lower" module: org.netbeans.modules.parsing.impl.TaskProcessor.callUserTask {code} Parsing API doesn't really hold a "lock", but it only runs in a single dedicated thread (which is a shared, spare resource too). Can we avoid that? Too hard, right [~tomas_zezula] & [~zezulato...@gmail.com] & [~tzezula]? This is a core of the indexing infrastructure. We don't want to touch it. Who else to blame? Let's make a rule: Whoever registers an indexer, isn't allowed to make a call to modules "above" Parsing API. With such rule, it is clear that {{KOHtmlExtension}} breaks it by calling into Project UI API . Take a look at [four deadlock conditions|http://wiki.apidesign.org/wiki/Deadlock_conditions] and select one to break the deadlock the simplest way. This would do it: {code:java} --- a/webcommon/javascript2.knockout/src/org/netbeans/modules/javascript2/knockout/index/KnockoutIndex.java +++ b/webcommon/javascript2.knockout/src/org/netbeans/modules/javascript2/knockout/index/KnockoutIndex.java @@ -27,6 +27,8 @@ import java.util.Map; import java.util.WeakHashMap; import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.logging.Logger; import org.netbeans.api.project.Project; import org.netbeans.api.project.ui.OpenProjects; @@ -57,8 +59,8 @@ if (!areProjectsOpen) { try { // just be sure that the projects are open - OpenProjects.getDefault().openProjects().get(); - } catch (InterruptedException | ExecutionException ex) { + OpenProjects.getDefault().openProjects().get(10, TimeUnit.SECONDS); + } catch (InterruptedException | ExecutionException | TimeoutException ex) { Exceptions.printStackTrace(ex); } finally { areProjectsOpen = true; {code} e.g. don't wait indefinitely. However given [Roman Svitanič's comment|https://github.com/emilianbold/netbeans-releases/commit/30092308c4fef#diff-b6844ad6d2c225bbb1c8d6c0287d6a6cR80] "just be sure that the projects are open" - I'd suggest to delete the whole {{areProjectsOpen}} check. This shouldn't be here at all. If the dependency of {{javascript2.knockout}} module on Project UI API can be removed, then even better! If you need a hotfix for 12.1, then I'd go with the 10s timeout shown above. In the long term I suggest to apply following fix: {code:java} webcommon/javascript2.knockout$ git diff . diff --git a/webcommon/javascript2.knockout/nbproject/project.xml b/webcommon/javascript2.knockout/nbproject/project.xml index 3f6fae4f8de0..47a191a3496d 100644 --- a/webcommon/javascript2.knockout/nbproject/project.xml +++ b/webcommon/javascript2.knockout/nbproject/project.xml @@ -96,15 +96,6 @@ <specification-version>1.61</specification-version> </run-dependency> </dependency> - <dependency> - <code-name-base>org.netbeans.modules.projectuiapi.base</code-name-base> - <build-prerequisite/> - <compile-dependency/> - <run-dependency> - <release-version>1</release-version> - <specification-version>1.78</specification-version> - </run-dependency> - </dependency> <dependency> <code-name-base>org.openide.filesystems</code-name-base> <build-prerequisite/> diff --git a/webcommon/javascript2.knockout/src/org/netbeans/modules/javascript2/knockout/index/KnockoutIndex.java b/webcommon/javascript2.knockout/src/org/netbeans/modules/javascript2/knockout/index/KnockoutIndex.java index eec45ef5b673..42676c1e14d4 100644 --- a/webcommon/javascript2.knockout/src/org/netbeans/modules/javascript2/knockout/index/KnockoutIndex.java +++ b/webcommon/javascript2.knockout/src/org/netbeans/modules/javascript2/knockout/index/KnockoutIndex.java @@ -26,10 +26,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.WeakHashMap; :...skipping... diff --git a/webcommon/javascript2.knockout/nbproject/project.xml b/webcommon/javascript2.knockout/nbproject/project.xml index 3f6fae4f8de0..47a191a3496d 100644 --- a/webcommon/javascript2.knockout/nbproject/project.xml +++ b/webcommon/javascript2.knockout/nbproject/project.xml @@ -96,15 +96,6 @@ <specification-version>1.61</specification-version> </run-dependency> </dependency> - <dependency> - <code-name-base>org.netbeans.modules.projectuiapi.base</code-name-base> - <build-prerequisite/> - <compile-dependency/> - <run-dependency> - <release-version>1</release-version> - <specification-version>1.78</specification-version> - </run-dependency> - </dependency> <dependency> <code-name-base>org.openide.filesystems</code-name-base> <build-prerequisite/> diff --git a/webcommon/javascript2.knockout/src/org/netbeans/modules/javascript2/knockout/index/KnockoutIndex.java b/webcommon/javascript2.knockout/src/org/netbeans/modules/javascript2/knockout/index/KnockoutIndex.java index eec45ef5b673..42676c1e14d4 100644 --- a/webcommon/javascript2.knockout/src/org/netbeans/modules/javascript2/knockout/index/KnockoutIndex.java +++ b/webcommon/javascript2.knockout/src/org/netbeans/modules/javascript2/knockout/index/KnockoutIndex.java @@ -26,10 +26,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.WeakHashMap; -import java.util.concurrent.ExecutionException; -import java.util.logging.Logger; import org.netbeans.api.project.Project; -import org.netbeans.api.project.ui.OpenProjects; import org.netbeans.modules.parsing.spi.indexing.support.IndexResult; import org.netbeans.modules.parsing.spi.indexing.support.QuerySupport; import org.openide.filesystems.FileObject; @@ -40,12 +37,8 @@ import org.openide.util.Exceptions; * @author Roman Svitanic */ public class KnockoutIndex { - - private static final Logger LOGGER = Logger.getLogger(KnockoutIndex.class.getSimpleName()); - private static final Map<Project, KnockoutIndex> INDEXES = new WeakHashMap<>(); private final QuerySupport querySupport; - private static boolean areProjectsOpen = false; public static KnockoutIndex get(Project project) throws IOException { if (project == null) { @@ -54,16 +47,6 @@ public class KnockoutIndex { synchronized (INDEXES) { KnockoutIndex index = INDEXES.get(project); if (index == null) { - if (!areProjectsOpen) { - try { - // just be sure that the projects are open - OpenProjects.getDefault().openProjects().get(); - } catch (InterruptedException | ExecutionException ex) { - Exceptions.printStackTrace(ex); - } finally { - areProjectsOpen = true; - } - } Collection<FileObject> sourceRoots = QuerySupport.findRoots(project, null /* all source roots */, Collections.<String>emptyList(), {code} > NetBeans 12.1-beta1 sometimes hangs on open > ------------------------------------------- > > Key: NETBEANS-4696 > URL: https://issues.apache.org/jira/browse/NETBEANS-4696 > Project: NetBeans > Issue Type: Bug > Components: ide - Performance > Affects Versions: 12.1 > Environment: Linux (Debian "Buster") > OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.7+10) > Reporter: Glenn Holmer > Priority: Major > Attachments: 12.1-vc1-thread-dump-orac.txt, > nb12.1-beta1-thread-dump.png, nb12.1-beta1-thread-dump.txt, > netbeans-12.1-thread-dump.txt > > > > NetBeans sometimes hangs on startup; the symptom is a stalled "Opening > Projects" progress bar. I haven't been able to find a repro case, but I'm > attaching a thread dump (from VisualVM) and screen shot. -- This message was sent by Atlassian Jira (v8.3.4#803005) --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@netbeans.apache.org For additional commands, e-mail: commits-h...@netbeans.apache.org For further information about the NetBeans mailing lists, visit: https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists