Community
Participate
Working Groups
I have code which does the following: try { getRunnableContext().run(false, true, getRunnable()); } catch (InvocationTargetException e) { } catch (InterruptedException e) { } where the runnable context is the active workbench window. This is done during a resource change notification. The problem is that the status line does not update when my runnable sets messages on the IProgressMonitor. I saw that eclipse handles this using org.eclipse.ui.internal.dialogs.EventLoopProgressMonitor to wrap the monitor passed in using a wrapping runnable. For example, I used: protected IRunnableWithProgress getRunnable() { final IRunnableWithProgress wrappable = xxx; return new IRunnableWithProgress() { public void run(IProgressMonitor monitor) throws InterruptedException, InvocationTargetException { IProgressMonitor monitorWrap = new EventLoopProgressMonitor(monitor); wrappable.run(monitorWrap); } }; } and so that I don't have to use an internal class, I made a copy of EventLoopProgressMonitor. The issues: 1) It would be nice if the workbench window as runnble context would take care of this automatically. 2) If not, it would be nice if the EventLoopProgressMonitor was not internal, so that I don't have to copy it, or to have some exposed api which works. 3) Is my workaround safe? Thanks -Ritchie
Yes, unfortunately this workaround is required to keep the UI responsive. We are investigating better approaches to progress monitoring. The currently recommended approach is to use fork=true and then do a Display.syncExec whenever you need to talk to the UI thread. Have you tried this? If this doesn't work for you, it would be helpful to know why not.
I didn't try the sync exec for progress monitor updates, but I did try fork=true, and the system deadlocked and I had to kill it. As I mentioned, this is during a resource change notification on type POST_AUTO_BUILD. My code has grown more complex; this is to cover me whether the notification is coming from the display thread or not. This seems to work for the test cases I've tried - adding from the repo, deleting projects, and saving from editors. protected void runxxx() { final IRunnableWithProgress runnableWithProg = xxx; final IRunnableContext context = getRunnableContext(); final Display display = Display.getCurrent() == null ? Display.getDefault() : Display.getCurrent(); Runnable simpleRunnable = new Runnable() { public void run() { try { if (context != null && display != null) context.run(false, true, runnableWithProg); else runnableWithProg.run(new NullProgressMonitor()); } catch (InvocationTargetException e) { } catch (InterruptedException e) {} } }; if (display == null) simpleRunnable.run(); else display.syncExec(simpleRunnable); }
How is the autobuild being triggered when you encounter deadlocks? What kind of work are you doing in response to the autobuild? Are you making further modifications to the workspace? An autobuild can occur due to any workspace change, including a file save, which also reports progress in the status line. So if you also want to use the status line, it will be reporting progress twice, which will look funny. If you are encountering deadlocks, one way to track down what's happening is to run eclipse from a command line window with -vm c:\jre\bin\java.exe (instead of javaw.exe). When the deadlock is hit, use ctrl+break in the command line window to get a dump of all threads. You might want to try queuing all your post-auto-build work within an asyncExec (not syncExec). That way it will run after the autobuild notification unwinds (releasing the workspace lock), and after the UI is processing events again. This may help avoid the deadlock.
I don't remember which resource change scenario it was that caused the deadlock (add, remove, or save). Note that autobuild may or may not have been on; this is just the notification I listen for because that is when the tree is unlocked and I can make further modifications. My listener will not modify resources, but may modify the markers in the task list. I thought about queueing it in an asyncexec, but then there might be a gap between operations when the UI might become "enabled" and then it will mysteriously go "disabled" again while my operation runs, as opposed to a continuous pause during the resource change. On slow machines, or the first time classes in the plugin are loaded, this could be a noticable delay. I agree it might look funny when I hijack the status line, but the alternative is not to report status at all, or async it with the possibility of a delay.
The delay should not be noticeable. It's worth a try.
Ok, I'll give it a try, but it might be a couple days before I can revisit it. Will provide an update. Thanks.
Using a forked operation and asyncExec for posting updates in the UI is the correct approach. Also see the IProgressService added in 3.0 that has various options for running a modal context (busyCursorWhile being the principle one).