Bug 542860 - Application hangs at JavaRuntime.getDefaultVMInstall()
Summary: Application hangs at JavaRuntime.getDefaultVMInstall()
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 4.6   Edit
Hardware: PC All
: P3 normal (vote)
Target Milestone: 4.11 M3   Edit
Assignee: Simeon Andreev CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2018-12-17 11:36 EST by Simeon Andreev CLA
Modified: 2019-06-23 17:24 EDT (History)
3 users (show)

See Also:
jarthana: review+


Attachments
Plug-in to reproduce the problem with. See reproduction steps in description. (3.29 KB, application/zip)
2018-12-17 11:43 EST, Simeon Andreev CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Simeon Andreev CLA 2018-12-17 11:36:23 EST
To reproduce:

1. Import plug-in from attached archive "ExamplePlugin.zip" to your developer workspace.
2. Debug Eclipse in a new workspace.
3. Create a new Java project.
4. Add an external class folder to some absolute path location. This can be done with right click on the project in Package Explorer -> Java build path -> libraries tab.
5. Close the debugged Eclipse.
6. Move the new workspace (created for step 2, move e.g. with mv on Linux).
7. Debug application "TestApplication.some_test_application" with breakpoints at:
a) org.eclipse.jdt.internal.core.ExternalFoldersManager.openExternalFoldersProject(IProject, IProgressMonitor) (first line that calls "project.open()") 
b) Line 34 of TestApplication (calls "IVMInstall defaultJVM = JavaRuntime.getDefaultVMInstall();")
c) Line 25 of Test Application (calls "System.out.println("job running");")
8. Observe breakpoints b) and c) being hit.
9. Resume the breakpoint b) (the one directly in the application code).
10. Observe the breakpoint a) being hit (the one in ExternalFoldersManager.openExternalFoldersProject()).
11. Resume the breakpoint c) (the one at the line of the WorkspaceJob defined in the application code).
12. Resume the breakpoint a).
13. Observe deadlock between main thread and the job defined in the application.

See also https://bugs.eclipse.org/bugs/show_bug.cgi?id=252571#c0, this defines the reproduction steps from 1. to 6.

The reproduction steps and example application are just for simplicity. Originally, we observed the following deadlock in one of the applications of our product:


"Worker-1: Refreshing workspace" #32 prio=5 os_prio=0 tid=0x00007ffff13f3000 nid=0x1e085 in Object.wait() [0x00007fffb2435000]
   java.lang.Thread.State: RUNNABLE
	at org.eclipse.jdt.internal.core.JavaCorePreferenceModifyListener.<init>(JavaCorePreferenceModifyListener.java:26)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
	at java.lang.Class.newInstance(Class.java:442)
	at org.eclipse.core.internal.registry.osgi.RegistryStrategyOSGI.createExecutableExtension(RegistryStrategyOSGI.java:190)
	at org.eclipse.core.internal.registry.ExtensionRegistry.createExecutableExtension(ExtensionRegistry.java:934)
	at org.eclipse.core.internal.registry.ConfigurationElement.createExecutableExtension(ConfigurationElement.java:246)
	at org.eclipse.core.internal.registry.ConfigurationElementHandle.createExecutableExtension(ConfigurationElementHandle.java:63)
	at org.eclipse.core.internal.preferences.PreferenceServiceRegistryHelper.addModifyListener(PreferenceServiceRegistryHelper.java:94)
	at org.eclipse.core.internal.preferences.PreferenceServiceRegistryHelper.getModifyListeners(PreferenceServiceRegistryHelper.java:208)
	at org.eclipse.core.internal.preferences.PreferencesService.firePreApplyEvent(PreferencesService.java:444)
	at org.eclipse.core.internal.preferences.PreferencesService.applyPreferences(PreferencesService.java:125)
	at org.eclipse.core.internal.resources.ProjectPreferences.read(ProjectPreferences.java:212)
	at org.eclipse.core.internal.resources.ProjectPreferences.updatePreferences(ProjectPreferences.java:280)
	at org.eclipse.core.internal.resources.File.updateMetadataFiles(File.java:390)
	at org.eclipse.core.internal.localstore.RefreshLocalVisitor.visit(RefreshLocalVisitor.java:306)
	at org.eclipse.core.internal.localstore.UnifiedTree.accept(UnifiedTree.java:118)
	at org.eclipse.core.internal.localstore.FileSystemResourceManager.refreshResource(FileSystemResourceManager.java:976)
	at org.eclipse.core.internal.localstore.FileSystemResourceManager.refresh(FileSystemResourceManager.java:959)
	at org.eclipse.core.internal.localstore.FileSystemResourceManager.refreshRoot(FileSystemResourceManager.java:1001)
	at org.eclipse.core.internal.localstore.FileSystemResourceManager.refresh(FileSystemResourceManager.java:952)
	at org.eclipse.core.internal.resources.Resource.refreshLocal(Resource.java:1550)
	at org.eclipse.core.internal.refresh.RefreshJob.runInWorkspace(RefreshJob.java:166)
	at org.eclipse.core.internal.resources.InternalWorkspaceJob.run(InternalWorkspaceJob.java:42)
	at org.eclipse.core.internal.jobs.Worker.run(Worker.java:63)


"main" #1 prio=5 os_prio=0 tid=0x00007ffff004e000 nid=0x1e053 in Object.wait() [0x00007ffff59bb000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	at java.lang.Object.wait(Object.java:502)
	at org.eclipse.core.internal.jobs.ThreadJob.waitForRun(ThreadJob.java:316)
	- locked <0x00000004c334f150> (a java.lang.Object)
	at org.eclipse.core.internal.jobs.ThreadJob.joinRun(ThreadJob.java:205)
	at org.eclipse.core.internal.jobs.ImplicitJobs.begin(ImplicitJobs.java:95)
	at org.eclipse.core.internal.jobs.JobManager.beginRule(JobManager.java:297)
	at org.eclipse.core.internal.resources.WorkManager.checkIn(WorkManager.java:124)
	at org.eclipse.core.internal.resources.Workspace.prepareOperation(Workspace.java:2243)
	at org.eclipse.core.internal.resources.Project.open(Project.java:1021)
	at org.eclipse.core.internal.resources.Project.open(Project.java:1110)
	at org.eclipse.jdt.internal.core.ExternalFoldersManager.openExternalFoldersProject(ExternalFoldersManager.java:385)
	at org.eclipse.jdt.internal.core.ExternalFoldersManager.getFolders(ExternalFoldersManager.java:416)
	at org.eclipse.jdt.internal.core.ExternalFoldersManager.<init>(ExternalFoldersManager.java:74)
	at org.eclipse.jdt.internal.core.ExternalFoldersManager.getExternalFoldersManager(ExternalFoldersManager.java:80)
	- locked <0x00000007b6f88f98> (a java.lang.Class for org.eclipse.jdt.internal.core.ExternalFoldersManager)
	at org.eclipse.jdt.internal.core.JavaModelManager.<init>(JavaModelManager.java:625)
	at org.eclipse.jdt.internal.core.JavaModelManager.<clinit>(JavaModelManager.java:1236)
	at org.eclipse.jdt.core.JavaCore.start(JavaCore.java:6224)
	at org.eclipse.osgi.internal.framework.BundleContextImpl$3.run(BundleContextImpl.java:782)
	at org.eclipse.osgi.internal.framework.BundleContextImpl$3.run(BundleContextImpl.java:1)
	at java.security.AccessController.doPrivileged(Native Method)
	at org.eclipse.osgi.internal.framework.BundleContextImpl.startActivator(BundleContextImpl.java:775)
	at org.eclipse.osgi.internal.framework.BundleContextImpl.start(BundleContextImpl.java:732)
	at org.eclipse.osgi.internal.framework.EquinoxBundle.startWorker0(EquinoxBundle.java:1005)
	at org.eclipse.osgi.internal.framework.EquinoxBundle$EquinoxModule.startWorker(EquinoxBundle.java:357)
	at org.eclipse.osgi.container.Module.doStart(Module.java:584)
	at org.eclipse.osgi.container.Module.start(Module.java:452)
	at org.eclipse.osgi.framework.util.SecureAction.start(SecureAction.java:471)
	at org.eclipse.osgi.internal.hooks.EclipseLazyStarter.postFindLocalClass(EclipseLazyStarter.java:117)
	at org.eclipse.osgi.internal.loader.classpath.ClasspathManager.findLocalClass(ClasspathManager.java:557)
	at org.eclipse.osgi.internal.loader.ModuleClassLoader.findLocalClass(ModuleClassLoader.java:331)
	at org.eclipse.osgi.internal.loader.BundleLoader.findLocalClass(BundleLoader.java:395)
	at org.eclipse.osgi.internal.loader.sources.SingleSourcePackage.loadClass(SingleSourcePackage.java:39)
	at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:469)
	at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:422)
	at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:414)
	at org.eclipse.osgi.internal.loader.ModuleClassLoader.loadClass(ModuleClassLoader.java:153)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
	at org.eclipse.jdt.internal.launching.LaunchingPlugin.start(LaunchingPlugin.java:581)
	at org.eclipse.osgi.internal.framework.BundleContextImpl$3.run(BundleContextImpl.java:782)
	at org.eclipse.osgi.internal.framework.BundleContextImpl$3.run(BundleContextImpl.java:1)
	at java.security.AccessController.doPrivileged(Native Method)
	at org.eclipse.osgi.internal.framework.BundleContextImpl.startActivator(BundleContextImpl.java:775)
	at org.eclipse.osgi.internal.framework.BundleContextImpl.start(BundleContextImpl.java:732)
	at org.eclipse.osgi.internal.framework.EquinoxBundle.startWorker0(EquinoxBundle.java:1005)
	at org.eclipse.osgi.internal.framework.EquinoxBundle$EquinoxModule.startWorker(EquinoxBundle.java:357)
	at org.eclipse.osgi.container.Module.doStart(Module.java:584)
	at org.eclipse.osgi.container.Module.start(Module.java:452)
	at org.eclipse.osgi.framework.util.SecureAction.start(SecureAction.java:471)
	at org.eclipse.osgi.internal.hooks.EclipseLazyStarter.postFindLocalClass(EclipseLazyStarter.java:117)
	at org.eclipse.osgi.internal.loader.classpath.ClasspathManager.findLocalClass(ClasspathManager.java:557)
	at org.eclipse.osgi.internal.loader.ModuleClassLoader.findLocalClass(ModuleClassLoader.java:331)
	at org.eclipse.osgi.internal.loader.BundleLoader.findLocalClass(BundleLoader.java:395)
	at org.eclipse.osgi.internal.loader.sources.SingleSourcePackage.loadClass(SingleSourcePackage.java:39)
	at org.eclipse.osgi.internal.loader.BundleLoader.findClassInternal(BundleLoader.java:469)
	at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:422)
	at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:414)
	at org.eclipse.osgi.internal.loader.ModuleClassLoader.loadClass(ModuleClassLoader.java:153)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
        ...

Another similar deadlock we observed had the same stack for the main thread, and an auto-build job:


"Worker-3: Building workspace" #37 prio=5 os_prio=0 tid=0x00007ffff048c800 nid=0x1016c in Object.wait() [0x00007fffafe73000]
   java.lang.Thread.State: RUNNABLE
	at org.eclipse.jdt.core.JavaCore.create(JavaCore.java:3470)
	at org.eclipse.jdt.internal.core.DynamicProjectReferences.getDependentProjects(DynamicProjectReferences.java:33)
	at org.eclipse.core.internal.resources.ProjectDescription.computeDynamicReferencesForProject(ProjectDescription.java:952)
	at org.eclipse.core.internal.resources.ProjectDescription.getAllBuildConfigReferences(ProjectDescription.java:268)
	at org.eclipse.core.internal.resources.Project.internalGetReferencedBuildConfigs(Project.java:795)
	at org.eclipse.core.internal.resources.Workspace.computeActiveBuildConfigGraph(Workspace.java:755)
	at org.eclipse.core.internal.resources.Workspace.getBuildGraph(Workspace.java:1620)
	at org.eclipse.core.internal.resources.Workspace.getBuildOrder(Workspace.java:1601)
	at org.eclipse.core.internal.events.AutoBuildJob.doBuild(AutoBuildJob.java:154)
	at org.eclipse.core.internal.events.AutoBuildJob.run(AutoBuildJob.java:244)
	at org.eclipse.core.internal.jobs.Worker.run(Worker.java:63)


One of the first lines of code in our application is: JavaRuntime.getDefaultVMInstall()

This results in opening the external folder links project, if external class folders exist in a Java project. To open the project, a project lock is required. However, the auto-build and refresh jobs hold the workspace root lock while accessing the Java model (due to preferences in the case of the refresh job). So we have a deadlock; OSGI somehow prevents the auto-build / refresh job from continuing due to the main thread.
Comment 1 Simeon Andreev CLA 2018-12-17 11:41:08 EST
Reproduction should be possible with the Eclipse IDE application. However I was not able to create a .settings/XYZ.pref file that causes preferences to be read, such that ProjectPreferences.read() is called.

Note that the situation is *very* specific. Our workaround for now is to call RefreshManager.shutdown(), since our application which hangs is a standalone compiler. This reduces the probability of hanging in a "bad" workspace (see bug 252571 comment 0) by a lot.
Comment 2 Simeon Andreev CLA 2018-12-17 11:43:33 EST
Created attachment 276945 [details]
Plug-in to reproduce the problem with. See reproduction steps in description.
Comment 3 Andrey Loskutov CLA 2018-12-17 11:49:25 EST
The essence is basically: on startup, ExternalFoldersManager should not try to acquire workspace lock (because it will always happen in the context of  JavaCore.start()): this will cause a deadlock with any thread holding the workspace lock and trying to access JDT core, because OSGI will prevent this code running until JDT bundle is activated.
Comment 4 Eclipse Genie CLA 2018-12-18 03:51:34 EST
New Gerrit change created: https://git.eclipse.org/r/134183
Comment 6 Jay Arthanareeswaran CLA 2019-01-16 09:39:38 EST
Thanks Simeon, for the patch!
Comment 7 Simeon Andreev CLA 2019-01-16 09:57:51 EST
Thanks for merging!
Comment 8 Jay Arthanareeswaran CLA 2019-02-20 00:16:03 EST
Verified for 4.11 M3 by code inspection.
Comment 9 Till Brychcy CLA 2019-05-24 14:43:21 EDT
This causes a warning in my workspace:

"Access to enclosing method getFolders() from the type ExternalFoldersManager is emulated by a synthetic accessor method"
(In ExternalFoldersManager.java, line 89)

jdt.core is usually warning-free. Am I the only one who gets this?
Comment 10 Simeon Andreev CLA 2019-05-27 03:17:50 EDT
Should we open a ticket for this?
Comment 11 Andrey Loskutov CLA 2019-05-27 03:24:47 EDT
(In reply to Simeon Andreev from comment #10)
> Should we open a ticket for this?

IMHO not needed, the change is trivial, I will just push a patch for 4.13.
Comment 12 Eclipse Genie CLA 2019-05-27 03:42:54 EDT
New Gerrit change created: https://git.eclipse.org/r/142841
Comment 13 Andrey Loskutov CLA 2019-05-27 03:45:36 EDT
(In reply to Eclipse Genie from comment #12)
> New Gerrit change created: https://git.eclipse.org/r/142841

To be merged in 4.13.