Bug 79913 - Concurrency support
diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/core/DebugPlugin.java b/org.eclipse.debug.core/core/org/eclipse/debug/core/DebugPlugin.java index e7a2b11..d44ca2d 100644 --- a/org.eclipse.debug.core/core/org/eclipse/debug/core/DebugPlugin.java +++ b/org.eclipse.debug.core/core/org/eclipse/debug/core/DebugPlugin.java
@@ -31,6 +31,7 @@ import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtensionPoint; import org.eclipse.core.runtime.IProgressMonitor; @@ -42,7 +43,6 @@ import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.ISchedulingRule; import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.debug.core.model.IDebugElement; import org.eclipse.debug.core.model.IProcess; import org.eclipse.debug.core.model.IValue; import org.eclipse.debug.core.model.RuntimeProcess; @@ -290,9 +290,28 @@ private static final int NOTIFY_FILTERS = 0; private static final int NOTIFY_EVENTS = 1; + /** + * An lock object used to indicate no locking was required. + * @since 3.1 + */ + private static Object NULL_LOCK = new Object(); + + /** + * Queue of debug events to fire to listeners. + * @since 3.1 + */ private List fEventQueue = new ArrayList(); + + /** + * Job to fire events to listeners. + * @since 3.1 + */ private EventDispatchJob fEventDispatchJob = new EventDispatchJob(); + /** + * Event dispatch job + * @since 3.1 + */ class EventDispatchJob extends Job { /** @@ -1283,30 +1302,101 @@ } /** + * Returns a scheduling rule that can be used to schedule a job + * that performs an access operation on the given debug artifact, + * or <code>null</code> if none. * - * @param element - * @return + * @param element debug artifact + * @return a scheduling rule for an access job, or <code>null</code> * @since 3.1 */ - public static ISchedulingRule accessRule(IDebugElement element) { - IDebugRuleFactory factory = (IDebugRuleFactory) element.getAdapter(IDebugRuleFactory.class); - if (factory != null) { - return factory.accessRule(element); - } + public static ISchedulingRule accessRule(Object element) { + if (element instanceof IAdaptable) { + IAdaptable adaptable = (IAdaptable) element; + IDebugRuleFactory factory = (IDebugRuleFactory) adaptable.getAdapter(IDebugRuleFactory.class); + if (factory != null) { + return factory.accessRule(element); + } + } + return null; } /** - * - * @param element - * @return + * Obtains and returns a lock on the given debug artifact for an + * access operation. This method blocks until the lock is available. + * The lock must be released by the caller via <code>releaseLock(Object)</code>. + * + * @param element debug artifact for which an access lock is required + * @return access lock that must be subsequently released * @since 3.1 */ - public static ISchedulingRule modificationRule(IDebugElement element) { - IDebugRuleFactory factory = (IDebugRuleFactory) element.getAdapter(IDebugRuleFactory.class); - if (factory != null) { - return factory.modificationRule(element); - } + public static Object getAccessLock(Object element) { + return getLock(accessRule(element)); + } + + /** + * Obtains and returns a lock on the given debug artifact for an + * modify operation. This method blocks until the lock is available. + * The lock must be released by the caller via <code>releaseLock(Object)</code>. + * + * @param element debug artifact for which a modification lock is required + * @return access lock that must be subsequently released + * @since 3.1 + */ + public static Object getModificationLock(Object element) { + return getLock(modificationRule(element)); + } + + /** + * Obtains a lock based on the given scheduling rule, in the + * job manager, and returns an object representing a lock + * that must be subsequently released. If the lock is + * <code>null</code>, no lock is obtained, but a dummy + * lock object is still returned. + * + * @param rule scheduling rule or <code>null</code> + * @return returns a lock that must be subsequently released + * @since 3.1 + */ + private static Object getLock(ISchedulingRule rule) { + if (rule == null) { + return NULL_LOCK; + } + Platform.getJobManager().beginRule(rule, null); + return rule; + } + + /** + * Releases the given lock. Must be called pairwise with + * <code>getAccessLock(Object)</code> or <code>getModificationLock(Object)</code>. + * + * @param lock lock to release + * @since 3.1 + */ + public static void releaseLock(Object lock) { + if (lock instanceof ISchedulingRule) { + Platform.getJobManager().endRule((ISchedulingRule)lock); + } + } + + /** + * Returns a scheduling rule that can be used to schedule a job + * that performs a modification operation on the given debug artifact, + * or <code>null</code> if none. + * + * @param element debug artifact + * @return a scheduling rule for a modification job, or <code>null</code> + * @since 3.1 + */ + public static ISchedulingRule modificationRule(Object element) { + if (element instanceof IAdaptable) { + IAdaptable adaptable = (IAdaptable) element; + IDebugRuleFactory factory = (IDebugRuleFactory) adaptable.getAdapter(IDebugRuleFactory.class); + if (factory != null) { + return factory.modificationRule(element); + } + } return null; }
diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/DefaultDebugRuleFactory.java b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/DefaultDebugRuleFactory.java index 7f1a6a7..080d791 100644 --- a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/DefaultDebugRuleFactory.java +++ b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/DefaultDebugRuleFactory.java
@@ -75,17 +75,23 @@ } /* (non-Javadoc) - * @see org.eclipse.debug.internal.core.IDebugRuleFactory#accessRule(org.eclipse.debug.core.model.IDebugElement) + * @see org.eclipse.debug.internal.core.IDebugRuleFactory#accessRule(java.lang.Object) */ - public ISchedulingRule accessRule(IDebugElement debugElement) { - return new PessimisticRule(debugElement); + public ISchedulingRule accessRule(Object artifact) { + if (artifact instanceof IDebugElement) { + return new PessimisticRule((IDebugElement)artifact); + } + return null; } /* (non-Javadoc) - * @see org.eclipse.debug.internal.core.IDebugRuleFactory#modificationRule(org.eclipse.debug.core.model.IDebugElement) + * @see org.eclipse.debug.internal.core.IDebugRuleFactory#modificationRule(java.lang.Object) */ - public ISchedulingRule modificationRule(IDebugElement debugElement) { - return new PessimisticRule(debugElement); + public ISchedulingRule modificationRule(Object artifact) { + if (artifact instanceof IDebugElement) { + return new PessimisticRule((IDebugElement)artifact); + } + return null; } }
diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/IDebugRuleFactory.java b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/IDebugRuleFactory.java index 83a8752..de0c95a 100644 --- a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/IDebugRuleFactory.java +++ b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/IDebugRuleFactory.java
@@ -11,7 +11,6 @@ package org.eclipse.debug.internal.core; import org.eclipse.core.runtime.jobs.ISchedulingRule; -import org.eclipse.debug.core.model.IDebugElement; /** * Creates scheduling rules for debug elements. @@ -21,18 +20,20 @@ public interface IDebugRuleFactory { /** - * Returns a scheduling rule used to schedule a job that accesses a debug element. + * Returns a scheduling rule used to schedule a job that accesses a debug artifact, + * or <code>null</code> if none. * - * @param debugElement debug element to be accessed - * @return rule used to schedule a job that accesses a debug element. + * @param artifact debug artifact to be accessed + * @return rule used to schedule a job that accesses an artifact, or <code>null</code> */ - public ISchedulingRule accessRule(IDebugElement debugElement); + public ISchedulingRule accessRule(Object artifact); /** * Returns a scheduling rule used to schedule a job that modifies the state of - * a debug element - * @param debugElement debug element to be modified - * @return rule used to schedule a job that modifies a debug element + * a debug artifact, or <code>null</code> if none. + * + * @param artifact debug artifact to be modified + * @return rule used to schedule a job that modifies an artifact, or <code>null</code> */ - public ISchedulingRule modificationRule(IDebugElement debugElement); + public ISchedulingRule modificationRule(Object artifact); }
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/LazyModelPresentation.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/LazyModelPresentation.java index 2be3c4c..aaa5f1d 100644 --- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/LazyModelPresentation.java +++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/LazyModelPresentation.java
@@ -18,16 +18,11 @@ import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; -import org.eclipse.core.runtime.Platform; -import org.eclipse.core.runtime.jobs.ISchedulingRule; import org.eclipse.debug.core.DebugPlugin; -import org.eclipse.debug.core.model.IDebugElement; -import org.eclipse.debug.core.model.IDebugTarget; import org.eclipse.debug.core.model.IMemoryBlock; import org.eclipse.debug.core.model.IStackFrame; import org.eclipse.debug.core.model.IThread; import org.eclipse.debug.core.model.IValue; -import org.eclipse.debug.internal.core.IDebugRuleFactory; import org.eclipse.debug.internal.core.ListenerList; import org.eclipse.debug.internal.ui.views.memory.IMemoryBlockModelPresentation; import org.eclipse.debug.internal.ui.views.memory.IMemoryRenderingType; @@ -122,40 +117,16 @@ */ public String getText(Object element) { String text = null; - ISchedulingRule rule = null; + Object lock = null; try { - rule = beginRule(element); + lock = DebugPlugin.getAccessLock(element); text = getPresentation().getText(element); } finally { - endRule(rule); + DebugPlugin.releaseLock(lock); } return text; } - /** - * @param rule - */ - private void endRule(ISchedulingRule rule) { - if (rule != null) { - Platform.getJobManager().endRule(rule); - } - } - - /** - * @param element - * @return - */ - private ISchedulingRule beginRule(Object object) { - ISchedulingRule rule = null; - if (object instanceof IDebugElement) { - rule = DebugPlugin.accessRule((IDebugElement)object); - if (rule != null) { - Platform.getJobManager().beginRule(rule, null); - } - } - return rule; - } - /** * @see IDebugModelPresentation#computeDetail(IValue, IValueDetailListener) */
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ResumeActionDelegate.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ResumeActionDelegate.java index cc8864d..7730ff6 100644 --- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ResumeActionDelegate.java +++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/actions/ResumeActionDelegate.java
@@ -14,6 +14,7 @@ import java.util.Iterator; import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.model.IDebugElement; import org.eclipse.debug.core.model.ISuspendResume; import org.eclipse.debug.core.model.IThread; @@ -88,7 +89,9 @@ protected boolean isEnabledForAllThreads(Object element) { if (element instanceof IDebugElement) { IDebugElement debugElement = (IDebugElement) element; + Object lock = null; try { + lock = DebugPlugin.getAccessLock(debugElement); IThread[] threads = debugElement.getDebugTarget().getThreads(); for (int i = 0; i < threads.length; i++) { if (threads[i].canResume()) { @@ -96,6 +99,8 @@ } } } catch (DebugException e) { + } finally { + DebugPlugin.releaseLock(lock); } } return false;
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/AbstractDebugEventHandler.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/AbstractDebugEventHandler.java index 94f0bbf..3b7d5fb 100644 --- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/AbstractDebugEventHandler.java +++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/AbstractDebugEventHandler.java
@@ -16,13 +16,10 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.jobs.ISchedulingRule; import org.eclipse.debug.core.DebugEvent; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.IDebugEventSetListener; -import org.eclipse.debug.core.model.IDebugElement; import org.eclipse.debug.ui.AbstractDebugView; import org.eclipse.jface.viewers.IBasicPropertyConstants; import org.eclipse.jface.viewers.ITreeContentProvider; @@ -34,8 +31,6 @@ import org.eclipse.ui.PlatformUI; import org.eclipse.ui.progress.UIJob; -import com.ibm.xslt4j.bcel.generic.FADD; - /** * Handles debug events, updating a view and viewer. */ @@ -353,25 +348,5 @@ */ protected void viewBecomesHidden() { } - - /** - * - * @param element - * @return - * @since 3.1 - */ - protected ISchedulingRule beginAccessRule(IDebugElement element) { - ISchedulingRule rule = DebugPlugin.accessRule(element); - if (rule != null) { - Platform.getJobManager().beginRule(rule, null); - } - return rule; - } - - protected void endRule(ISchedulingRule rule) { - if (rule != null) { - Platform.getJobManager().endRule(rule); - } - } }
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/launch/LaunchViewEventHandler.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/launch/LaunchViewEventHandler.java index 657ba05..e8a3744 100644 --- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/launch/LaunchViewEventHandler.java +++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/views/launch/LaunchViewEventHandler.java
@@ -16,7 +16,6 @@ import java.util.Map; import java.util.Set; -import org.eclipse.core.runtime.jobs.ISchedulingRule; import org.eclipse.debug.core.DebugEvent; import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.DebugPlugin; @@ -586,14 +585,14 @@ case DebugEvent.SUSPEND: if (source instanceof IThread) { IThread thread = (IThread)source; - ISchedulingRule rule = null; + Object lock = null; try { - rule = beginAccessRule(thread); + lock = DebugPlugin.getAccessLock(thread); IStackFrame frame = thread.getTopStackFrame(); queueData(frame); } catch (DebugException e) { } finally { - endRule(rule); + DebugPlugin.releaseLock(lock); } } break; @@ -601,10 +600,10 @@ if (source instanceof IThread) { // When a thread resumes, try to select another suspended thread // in the same target. - ISchedulingRule rule = null; + Object lock = null; try { IDebugTarget target = ((IThread) source).getDebugTarget(); - rule = beginAccessRule(target); + lock = DebugPlugin.getAccessLock(target); IThread[] threads= target.getThreads(); for (int j = 0; j < threads.length; j++) { IStackFrame frame = threads[j].getTopStackFrame(); @@ -615,7 +614,7 @@ } } catch (DebugException e) { } finally { - endRule(rule); + DebugPlugin.releaseLock(lock); } } break;