Community
Participate
Working Groups
Hi, we implement an IDE for a proprietary language and source code versioning system, on top of Eclipse. During the "early startup" of one of our plugins, we need to create a synthetic project. This project is intented to wrap a directory on disk where source code from our proprietary versioning system is funelled through. This normally works fine, except that sometimes after removing the runtime-workspace (or when starting from new), we are seeing a deadlock happen in the Eclipse code that created "projects". More specificly (defaultProject is our synthetic project): . . . . . . . . . . . . . . . . . . . . . . if (!defaultProject.exists()) { // try to create a new project try { // create a project description and give it a builder... log("creating the project wrapper..."); IProjectDescription desc = getWorkspace().newProjectDescription(DFLT_PROJECT); desc.setLocation(null); log("Setting builder specification..."); ICommand buildCmd = desc.newCommand(); buildCmd.setBuilderName("CustomBuilderId"); String[] natureIds = {"customNature"}; ICommand[] buildCmds = new ICommand[1]; buildCmds[0]=buildCmd; desc.setBuildSpec(buildCmds); log("Default Project now has a builder command."); // ok, now actually create the project! // // !! NOTE !! I've noticed that sometimes on startup, this call to // create the default project causes Eclipse to deadlock and the GUI // will freeze. The only fix I've found so far far is to comment it out, // start Eclipse and then shutdown Eclipse. Remove the comments, // and the start again. After that the hangups disappear. I think we may // eventually need to avoid creating projects at startup. // defaultProject.create(desc, null); defaultProject.open(null); . . . . . . . . . . . . . . . . . . . . . . Basicly when the early start method of our plugin is called, it falls through to calling defaultProject.create(desc,null); and somewhere inside the Eclipse code for creating a project, it just locks up. Is there a way I can get around this? Is it illegal to be creating project during plugin initialzation? If so, are there some rules we can follow about accessing logical/physical resources during plugin initialization? When we are developing the code, we can work around this issue by commenting in/out that "create" call, but once we deliver this to our internal customers, we won't have that luxury, it will need to work reliably all the time. Let me know if you need a stack trace, or if you have any suggestion on how to rework or avoid the problem. Thanks!
A stack trace illustrating the deadlock would be greatly appreciated. On linux this can generally be achieved by sending kill -3 to the java process. Attach the file to the bug report
When I launch a workbench in the debugger with our plugins loaded, I just do a "suspend" in the debugger to see where the threads are blocked. I think "Thread 1" is the problem, since its the thread were our plugin (PLSPlugin) runs: System Thread [Finalizer] (Suspended) Object.wait(long) line: not available [native method] ReferenceQueue.remove(long) line: 111 ReferenceQueue.remove() line: 127 Finalizer$FinalizerThread.run() line: 159 System Thread [Reference Handler] (Suspended) Object.wait(long) line: not available [native method] Reference$Lock(Object).wait() line: 426 Reference$ReferenceHandler.run() line: 113 Thread [main] (Suspended) Class.getDeclaredConstructors0(boolean) line: not available [native method] Class.privateGetDeclaredConstructors(boolean) line: 1590 Class.getConstructor0(Class[], int) line: 1762 Class.newInstance0() line: 276 Class.newInstance() line: 259 PluginDescriptor.createExecutableExtension(String, Object, IConfigurationElement, String) line: 138 PluginDescriptor.createExecutableExtension(String, String, Object, IConfigurationElement, String) line: 167 ConfigurationElement.createExecutableExtension(String) line: 103 WorkbenchPlugin.createExtension(IConfigurationElement, String) line: 151 WWinPluginAction(PluginAction).createDelegate() line: 103 WWinPluginAction.refreshActionList() line: 148 Workbench.refreshPluginActions(String) line: 1668 AbstractUIPlugin$3.run() line: 746 RunnableLock.run() line: 35 UISynchronizer(Synchronizer).runAsyncMessages() line: 98 Display.runAsyncMessages() line: 1936 Display.readAndDispatch() line: 1727 Workbench.runEventLoop(Window$IExceptionHandler) line: 1402 Workbench.run(Object) line: 1385 InternalBootLoader.run(String, URL, String, String[], Runnable) line: 858 BootLoader.run(String, URL, String, String[], Runnable) line: 461 NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method] NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39 DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25 Method.invoke(Object, Object[]) line: 324 Main.basicRun(String[]) line: 291 Main.run(String[]) line: 747 Main.main(String[]) line: 583 System Thread [Signal Dispatcher] (Suspended) Thread [Thread-1] (Suspended) Object.wait(long) line: not available [native method] Semaphore(Object).wait() line: 426 Semaphore.acquire() line: 26 UISynchronizer.syncExec(Runnable) line: 40 Display.syncExec(Runnable) line: 2317 WorkbenchContentProvider.resourceChanged(IResourceChangeEvent) line: 198 NotificationManager$1.run() line: 137 InternalPlatform.run(ISafeRunnable) line: 1006 Platform.run(ISafeRunnable) line: 413 NotificationManager.notify(ResourceChangeListenerList$ListenerEntry[], IResourceChangeEvent, boolean) line: 152 NotificationManager.broadcastChanges(ElementTree, int, boolean, boolean) line: 67 Workspace.broadcastChanges(ElementTree, int, boolean, boolean, IProgressMonitor) line: 161 Workspace.endOperation(boolean, IProgressMonitor) line: 892 Project.create(IProjectDescription, IProgressMonitor) line: 259 PLSPlugin.earlyStartup() line: 383 PLSPlugin.<init>(IPluginDescriptor) line: 115 NativeConstructorAccessorImpl.newInstance0(Constructor, Object[]) line: not available [native method] NativeConstructorAccessorImpl.newInstance(Object[]) line: 39 DelegatingConstructorAccessorImpl.newInstance(Object[]) line: 27 Constructor.newInstance(Object[]) line: 274 PluginDescriptor.internalDoPluginActivation() line: 722 PluginDescriptor.doPluginActivation() line: 188 PluginClassLoader.activatePlugin(String) line: 112 PluginClassLoader.internalFindClassParentsSelf(String, boolean, DelegatingURLClassLoader, boolean) line: 185 PluginClassLoader(DelegatingURLClassLoader).findClassParentsSelf (String, boolean, DelegatingURLClassLoader, boolean) line: 485 PluginClassLoader(DelegatingURLClassLoader).loadClass(String, boolean, DelegatingURLClassLoader, Vector, boolean) line: 882 DelegatingURLClassLoader.access$0(DelegatingURLClassLoader, String, boolean, DelegatingURLClassLoader, Vector, boolean) line: 876 DelegatingURLClassLoader$DelegateLoader.loadClass(String, DelegatingURLClassLoader, DelegatingURLClassLoader, Vector) line: 90 PluginClassLoader(DelegatingURLClassLoader).findClassPrerequisites (String, DelegatingURLClassLoader, Vector) line: 554 PluginClassLoader(DelegatingURLClassLoader).loadClass(String, boolean, DelegatingURLClassLoader, Vector, boolean) line: 890 PluginClassLoader(DelegatingURLClassLoader).loadClass(String, boolean) line: 862 PluginClassLoader(ClassLoader).loadClass(String) line: 255 PluginClassLoader(ClassLoader).loadClassInternal(String) line: 315 ProtelEditorPlugin.earlyStartup() line: 359 Workbench$15.run() line: 1327 InternalPlatform.run(ISafeRunnable) line: 1006 Platform.run(ISafeRunnable) line: 413 Workbench$14.run() line: 1334 Thread.run() line: 536 In the early setup of our plugin (Thread 1) you can see that its falling though to a semaphore somewhere inside Eclipse. This makes me suspect that its bad idea to create projects during plugin initialization? NOTE: I can reproduce this problem very reliably by just moving my existing runtime-workspace out of the way. Its only when we make this call to create a project that the deadlock happens.
I just noticed through Thread 1, that our editor plgin's early startup code is wrapping the early startup code for our other plugin (the one that tries to create the project). Is it possible that the editor plugin as a "lock" on the workspace and that is causing the deadlock?
This is what is happening. PLSPlugin.earlyStartup is being called from within the scope of a class loader. This means Thread1 has a lock on the class loader instance. It then tries to do a syncExec (as a side-effect of project creation), which requires synchronizing with the UI thread. The UI thread is currently trying to load a class in the same plugin, so it is blocked on the class loader lock. Unfortunately this is a well known problem with plugin startup (See "Note 3" in the javadoc for Plugin.startup). Doing anything that requires locks is going to be risky. I recommend minimizing the work done from within the startup method. In the worst case, you can try forking a thread at the end of your startup method that does more complex startup work. *** This bug has been marked as a duplicate of 12827 ***