diff --git a/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/concurrent/DisplayDsfExecutor.java b/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/concurrent/DisplayDsfExecutor.java new file mode 100644 index 00000000000..7a5dfe600b1 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/concurrent/DisplayDsfExecutor.java @@ -0,0 +1,232 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ + +package org.eclipse.dd.dsf.ui.concurrent; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.Future; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import org.eclipse.dd.dsf.concurrent.DefaultDsfExecutor; +import org.eclipse.dd.dsf.concurrent.DsfExecutor; +import org.eclipse.swt.SWT; +import org.eclipse.swt.SWTException; +import org.eclipse.swt.widgets.Display; + +public class DisplayDsfExecutor extends DefaultDsfExecutor +{ + /** + * Internal mapping of display objects to executors. + */ + private static Map fExecutors = Collections.synchronizedMap( new HashMap() ); + + /** + * Factory method for display executors. + * @param display Display to create an executor for. + * @return The new (or re-used) executor. + */ + public static DsfExecutor getDisplayDsfExecutor(Display display) { + synchronized (fExecutors) { + DisplayDsfExecutor executor = fExecutors.get(display); + if (executor == null) { + executor = new DisplayDsfExecutor(display); + fExecutors.put(display, executor); + } + return executor; + } + } + + /** + * The display class used by this executor to execute the submitted runnables. + */ + private final Display fDisplay; + + + private DisplayDsfExecutor(Display display) { + super("Display DSF Executor"); //$NON-NLS-1$ + fDisplay = display; + } + + /** + * Creates a callable wrapper, which delegates to the display to perform the + * operation. The callable blocks the executor thread while each call + * is executed in the display thred. + * @param Type used in the callable. + * @param callable Callable to wrap. + * @return Wrapper callable. + */ + private Callable createSWTDispatchCallable(final Callable callable) { + return new Callable() { + @SuppressWarnings("unchecked") + public V call() throws Exception { + final Object[] v = new Object[1]; + final Throwable[] e = new Throwable[1]; + + try { + fDisplay.syncExec(new Runnable() { + public void run() { + try { + v[0] = callable.call(); + } catch(Throwable exception) { + e[0] = exception; + } + } + }); + } catch (SWTException swtException) { + if (swtException.code == SWT.ERROR_DEVICE_DISPOSED) { + DisplayDsfExecutor.super.shutdown(); + } + } + + if(e[0] instanceof RuntimeException) + throw (RuntimeException) e[0]; + else if(e[0] instanceof Exception) + throw (Exception) e[0]; + + return (V) v[0]; + } + }; + } + + /** + * Creates a runnable wrapper, which delegates to the display to perform the + * operation. The runnable blocks the executor thread while each call + * is executed in the display thred. + * @param runnable Runnable to wrap. + * @return Wrapper runnable. + */ + private Runnable createSWTDispatchRunnable(final Runnable runnable) { + return new Runnable() { + public void run() { + final Throwable[] e = new Throwable[1]; + try { + fDisplay.syncExec(new Runnable() { + public void run() { + try { + runnable.run(); + } catch(Throwable exception) { + e[0] = exception; + } + } + }); + } catch (SWTException swtException) { + if (swtException.code == SWT.ERROR_DEVICE_DISPOSED) { + DisplayDsfExecutor.super.shutdown(); + } + } + if(e[0] instanceof RuntimeException) + throw (RuntimeException) e[0]; + } + }; + } + + @Override + public ScheduledFuture schedule(final Callable callable, long delay, TimeUnit unit) { + if (fDisplay.isDisposed()) { + if (!super.isShutdown()) super.shutdown(); + throw new RejectedExecutionException("Display " + fDisplay + " is disposed."); //$NON-NLS-1$ //$NON-NLS-2$ + } + return super.schedule(createSWTDispatchCallable(callable), delay, unit); + } + + @Override + public ScheduledFuture schedule(Runnable command, long delay, TimeUnit unit) { + if (fDisplay.isDisposed()) { + if (!super.isShutdown()) super.shutdown(); + throw new RejectedExecutionException("Display " + fDisplay + " is disposed."); //$NON-NLS-1$ //$NON-NLS-2$ + } + return super.schedule(createSWTDispatchRunnable(command), delay, unit); + } + + @Override + public ScheduledFuture scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) { + if (fDisplay.isDisposed()) { + if (!super.isShutdown()) super.shutdown(); + throw new RejectedExecutionException("Display " + fDisplay + " is disposed."); //$NON-NLS-1$ //$NON-NLS-2$ + } + return super.scheduleAtFixedRate(createSWTDispatchRunnable(command), initialDelay, period, unit); + } + + @Override + public ScheduledFuture scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) { + if (fDisplay.isDisposed()) { + if (!super.isShutdown()) super.shutdown(); + throw new RejectedExecutionException("Display " + fDisplay + " is disposed."); //$NON-NLS-1$ //$NON-NLS-2$ + } + return super.scheduleWithFixedDelay(createSWTDispatchRunnable(command), initialDelay, delay, unit); + } + + @Override + public void execute(Runnable command) { + if (fDisplay.isDisposed()) { + if (!super.isShutdown()) super.shutdown(); + throw new RejectedExecutionException("Display " + fDisplay + " is disposed."); //$NON-NLS-1$ //$NON-NLS-2$ + } + super.execute(createSWTDispatchRunnable(command)); + } + + @Override + public Future submit(Callable callable) { + if (fDisplay.isDisposed()) { + if (!super.isShutdown()) super.shutdown(); + throw new RejectedExecutionException("Display " + fDisplay + " is disposed."); //$NON-NLS-1$ //$NON-NLS-2$ + } + return super.submit(createSWTDispatchCallable(callable)); + } + + @Override + public Future submit(Runnable command, T result) { + if (fDisplay.isDisposed()) { + if (!super.isShutdown()) super.shutdown(); + throw new RejectedExecutionException("Display " + fDisplay + " is disposed."); //$NON-NLS-1$ //$NON-NLS-2$ + } + return super.submit(createSWTDispatchRunnable(command), result); + } + + @Override + public Future submit(Runnable command) { + if (fDisplay.isDisposed()) { + if (!super.isShutdown()) super.shutdown(); + throw new RejectedExecutionException("Display " + fDisplay + " is disposed."); //$NON-NLS-1$ //$NON-NLS-2$ + } + return super.submit(createSWTDispatchRunnable(command)); + } + + /** + * Override to prevent clients from shutting down. The executor will be + * shut down when the underlying display is discovered to be shut down. + */ + @Override + public void shutdown() { + } + + /** + * Override to prevent clients from shutting down. The executor will be + * shut down when the underlying display is discovered to be shut down. + */ + @SuppressWarnings({ "cast", "unchecked" }) + @Override + public List shutdownNow() { + return (List)Collections.EMPTY_LIST; + } + + @Override + public boolean isShutdown() { + // TODO Auto-generated method stub + return super.isShutdown(); + } +} diff --git a/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/concurrent/SWTDispatchDsfExecutor.java b/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/concurrent/SWTDispatchDsfExecutor.java deleted file mode 100644 index 3f1e61ec5c6..00000000000 --- a/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/concurrent/SWTDispatchDsfExecutor.java +++ /dev/null @@ -1,138 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007 Wind River Systems and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Wind River Systems - initial API and implementation - *******************************************************************************/ - -package org.eclipse.dd.dsf.ui.concurrent; - -import java.util.concurrent.Callable; -import java.util.concurrent.Future; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; - -import org.eclipse.dd.dsf.concurrent.DefaultDsfExecutor; -import org.eclipse.swt.widgets.Display; - -public class SWTDispatchDsfExecutor extends DefaultDsfExecutor -{ - - public SWTDispatchDsfExecutor() - { - super(); - } - - private Callable createSWTDispatchCallable(final Callable callable) - { - return new Callable() - { - @SuppressWarnings("unchecked") - public V call() throws Exception - { - final Object[] v = new Object[1]; - final Throwable[] e = new Throwable[1]; - - Display.getDefault().syncExec(new Runnable() - { - public void run() - { - try - { - v[0] = callable.call(); - } - catch(Throwable exception) - { - e[0] = exception; - } - } - }); - - if(e[0] instanceof RuntimeException) - throw (RuntimeException) e[0]; - else if(e[0] instanceof Exception) - throw (Exception) e[0]; - - return (V) v[0]; - } - }; - } - - private Runnable createSWTDispatchRunnable(final Runnable runnable) - { - return new Runnable() - { - public void run() - { - final Throwable[] e = new Throwable[1]; - - Display.getDefault().syncExec(new Runnable() - { - public void run() - { - try - { - runnable.run(); - } - catch(Throwable exception) - { - e[0] = exception; - } - } - }); - - if(e[0] instanceof RuntimeException) - throw (RuntimeException) e[0]; - } - }; - } - - @Override - public ScheduledFuture schedule(final Callable callable, long delay, - TimeUnit unit) { - return super.schedule(createSWTDispatchCallable(callable), delay, unit); - } - - @Override - public ScheduledFuture schedule(Runnable command, long delay, - TimeUnit unit) { - return super.schedule(createSWTDispatchRunnable(command), delay, unit); - } - - @Override - public ScheduledFuture scheduleAtFixedRate(Runnable command, - long initialDelay, long period, TimeUnit unit) { - return super.scheduleAtFixedRate(createSWTDispatchRunnable(command), initialDelay, period, unit); - } - - @Override - public ScheduledFuture scheduleWithFixedDelay(Runnable command, - long initialDelay, long delay, TimeUnit unit) { - return super.scheduleWithFixedDelay(createSWTDispatchRunnable(command), initialDelay, delay, unit); - } - - @Override - public void execute(Runnable command) { - super.execute(createSWTDispatchRunnable(command)); - } - - @Override - public Future submit(Callable callable) { - return super.submit(createSWTDispatchCallable(callable)); - } - - @Override - public Future submit(Runnable command, T result) { - return super.submit(createSWTDispatchRunnable(command), result); - } - - @Override - public Future submit(Runnable command) { - return super.submit(createSWTDispatchRunnable(command)); - } - -} diff --git a/plugins/org.eclipse.dd.dsf/.options b/plugins/org.eclipse.dd.dsf/.options index 54b07bac112..46b81df7dd3 100644 --- a/plugins/org.eclipse.dd.dsf/.options +++ b/plugins/org.eclipse.dd.dsf/.options @@ -1,2 +1,3 @@ org.eclipse.dd.dsf/debug = false org.eclipse.dd.dsf/debug/executor = false +org.eclipse.dd.dsf/debug/executorName = diff --git a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DefaultDsfExecutor.java b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DefaultDsfExecutor.java index 9860699b246..6bd0a31ba33 100644 --- a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DefaultDsfExecutor.java +++ b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DefaultDsfExecutor.java @@ -36,18 +36,43 @@ import org.eclipse.dd.dsf.DsfPlugin; public class DefaultDsfExecutor extends ScheduledThreadPoolExecutor implements DsfExecutor { + /** + * Instance counter for DSF executors. Used in the executor's thread name. + */ + private static int fgInstanceCounter = 0; + + /** + * Name of the executor, used in the executor's thread name. + */ + private String fName; + /** Thread factory that creates the single thread to be used for this executor */ static class DsfThreadFactory implements ThreadFactory { + private String fThreadName; + DsfThreadFactory(String name) { + fThreadName = name; + } + Thread fThread; public Thread newThread(Runnable r) { assert fThread == null; // Should be called only once. - fThread = new Thread(new ThreadGroup("DSF Thread Group"), r, "DSF Dispatch Thread", 0); //$NON-NLS-1$//$NON-NLS-2$ + fThread = new Thread(new ThreadGroup(fThreadName), r, fThreadName, 0); return fThread; } } public DefaultDsfExecutor() { - super(1, new DsfThreadFactory()); + this("DSF Executor"); //$NON-NLS-1$ + } + + /** + * Creates a new DSF Executor with the given name. + * @param name Name used to create executor's thread. + */ + public DefaultDsfExecutor(String name) { + super(1, new DsfThreadFactory(name + " - " + fgInstanceCounter++)); //$NON-NLS-1$ + fName = name; + if(DEBUG_EXECUTOR || ASSERTIONS_ENABLED) { // If tracing, pre-start the dispatch thread, and add it to the map. prestartAllCoreThreads(); @@ -84,10 +109,13 @@ public class DefaultDsfExecutor extends ScheduledThreadPoolExecutor // Utilities used for tracing. // static boolean DEBUG_EXECUTOR = false; + static String DEBUG_EXECUTOR_NAME = ""; static boolean ASSERTIONS_ENABLED = false; static { DEBUG_EXECUTOR = DsfPlugin.DEBUG && "true".equals( //$NON-NLS-1$ Platform.getDebugOption("org.eclipse.dd.dsf/debug/executor")); //$NON-NLS-1$ + DEBUG_EXECUTOR_NAME = DsfPlugin.DEBUG + ? Platform.getDebugOption("org.eclipse.dd.dsf/debug/executorName") : ""; //$NON-NLS-1$ assert (ASSERTIONS_ENABLED = true) == true; } @@ -141,7 +169,7 @@ public class DefaultDsfExecutor extends ScheduledThreadPoolExecutor fCurrentlyExecuting = this; // Write to console only if tracing is enabled (as opposed to tracing or assertions). - if (DEBUG_EXECUTOR) { + if (DEBUG_EXECUTOR && ("".equals(DEBUG_EXECUTOR_NAME) || fName.equals(DEBUG_EXECUTOR_NAME))) { //$NON-NLS-1$ StringBuilder traceBuilder = new StringBuilder(); // Record the time @@ -212,7 +240,9 @@ public class DefaultDsfExecutor extends ScheduledThreadPoolExecutor fRunnable = runnable; // Check if executable wasn't executed already. - if (DEBUG_EXECUTOR && fRunnable instanceof DsfExecutable) { + if (fRunnable instanceof DsfExecutable && + DEBUG_EXECUTOR && ("".equals(DEBUG_EXECUTOR_NAME) || fName.equals(DEBUG_EXECUTOR_NAME))) //$NON-NLS-1$ + { assert !((DsfExecutable)fRunnable).getSubmitted() : "Executable was previously executed."; //$NON-NLS-1$ ((DsfExecutable)fRunnable).setSubmitted(); }