diff --git a/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/model/DataViewModelSchemaNode.java b/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/model/DataViewModelSchemaNode.java index 04a7fed2faf..781d0162301 100644 --- a/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/model/DataViewModelSchemaNode.java +++ b/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/model/DataViewModelSchemaNode.java @@ -14,6 +14,7 @@ import org.eclipse.dd.dsf.concurrent.Done; import org.eclipse.dd.dsf.concurrent.DoneTracker; import org.eclipse.dd.dsf.concurrent.DsfExecutor; import org.eclipse.dd.dsf.concurrent.GetDataDone; +import org.eclipse.dd.dsf.concurrent.Immutable; import org.eclipse.dd.dsf.model.DMCs; import org.eclipse.dd.dsf.model.IDataModelContext; import org.eclipse.dd.dsf.model.IDataModelEvent; @@ -35,9 +36,10 @@ abstract public class DataViewModelSchemaNode implements IViewModelSchemaNode { /** * IViewModelContext implementation used for this schema node. */ + @Immutable public class DataVMC implements IViewModelContext { - IViewModelContext fParent; - IDataModelContext fDmc; + private final IViewModelContext fParent; + private final IDataModelContext fDmc; public DataVMC(IViewModelContext parent, IDataModelContext dataModelContext) { fParent = parent; diff --git a/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/model/IViewModelContext.java b/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/model/IViewModelContext.java index 02dbf460d6d..cc14081913f 100644 --- a/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/model/IViewModelContext.java +++ b/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/model/IViewModelContext.java @@ -11,10 +11,12 @@ package org.eclipse.dd.dsf.ui.model; import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.dd.dsf.concurrent.Immutable; /** * View model element which is stored as the data object of nodes in the viewer. */ +@Immutable public interface IViewModelContext extends IAdaptable { /** diff --git a/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/model/IViewModelSchemaNode.java b/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/model/IViewModelSchemaNode.java index 3e6679e1b12..788fc63a781 100644 --- a/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/model/IViewModelSchemaNode.java +++ b/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/model/IViewModelSchemaNode.java @@ -10,6 +10,7 @@ *******************************************************************************/ package org.eclipse.dd.dsf.ui.model; +import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor; import org.eclipse.dd.dsf.concurrent.Done; import org.eclipse.dd.dsf.concurrent.GetDataDone; import org.eclipse.dd.dsf.model.IDataModelEvent; @@ -27,6 +28,7 @@ import org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta; * of other data in the view tree. * @see ViewModelProvider */ +@ConfinedToDsfExecutor("") @SuppressWarnings("restriction") public interface IViewModelSchemaNode { diff --git a/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/model/ViewModelProvider.java b/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/model/ViewModelProvider.java index a36fccca031..1246d15ae5e 100644 --- a/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/model/ViewModelProvider.java +++ b/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/model/ViewModelProvider.java @@ -15,9 +15,11 @@ import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.ISchedulingRule; import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor; import org.eclipse.dd.dsf.concurrent.Done; import org.eclipse.dd.dsf.concurrent.DoneTracker; import org.eclipse.dd.dsf.concurrent.GetDataDone; +import org.eclipse.dd.dsf.concurrent.ThreadSafe; import org.eclipse.dd.dsf.model.IDataModelEvent; import org.eclipse.dd.dsf.service.DsfSession; import org.eclipse.debug.internal.ui.viewers.provisional.AbstractModelProxy; @@ -44,10 +46,11 @@ import org.eclipse.debug.internal.ui.viewers.provisional.IModelProxy; * @see IModelProxy * @see IViewModelSchemaNode */ +@ConfinedToDsfExecutor("fSession#getExecutor") @SuppressWarnings("restriction") public class ViewModelProvider extends AbstractModelProxy { - private DsfSession fSession; + private final DsfSession fSession; /** * Counter for whether the model proxy is currently installed in the viewer. @@ -66,7 +69,7 @@ public class ViewModelProvider extends AbstractModelProxy * Root VMC node for the model. The devault value may be overriden with * an object from a tree, by the data model adapter. */ - IViewModelContext fRootVMC = new IViewModelContext() { + IViewModelContext fRootVMC = new IViewModelContext(){ public IViewModelContext getParent() { return null; } public IViewModelSchemaNode getSchemaNode() { return null; } public Object getAdapter(Class adapter) { @@ -209,10 +212,12 @@ public class ViewModelProvider extends AbstractModelProxy public boolean isConflicting(ISchedulingRule rule) { return rule == this; } }; + @ThreadSafe public void installed() { fProxyActive++; } + @ThreadSafe public void dispose() { fProxyActive--; super.dispose(); diff --git a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/ConfinedToDsfExecutor.java b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/ConfinedToDsfExecutor.java new file mode 100644 index 00000000000..3b880946af5 --- /dev/null +++ b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/ConfinedToDsfExecutor.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2006 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.concurrent; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation idicating that given package, class, method, or field can be + * access safely only from a DSF executor thread. If declared on package or type, + * a field or method could still be declared with an annotation indicating that it's + * thread-safe. + *
+ * Note: the runtime retention policy is there to allow automated testing
+ * and validation code.
+ *
+ * @param value The value indicates the method to use to obtain the executor.
+ * It should be null if it cannot be determined from the given object.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PACKAGE, ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
+@Inherited
+@Documented
+public @interface ConfinedToDsfExecutor {
+ String value();
+}
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 bae93caaf90..1453b258d82 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
@@ -24,6 +24,7 @@ import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
+import org.eclipse.core.runtime.ILog;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
@@ -70,18 +71,21 @@ public class DefaultDsfExecutor extends ScheduledThreadPoolExecutor
} catch (CancellationException e) { // Ignore also
} catch (ExecutionException e) {
if (e.getCause() != null) {
- DsfPlugin.getDefault().getLog().log(new Status(
- IStatus.ERROR, DsfPlugin.PLUGIN_ID, -1, "Uncaught exception in DSF executor thread", e.getCause()));
-
- // Print out the stack trace to console if assertions are enabled.
- if(ASSERTIONS_ENABLED) {
- ByteArrayOutputStream outStream = new ByteArrayOutputStream(512);
- PrintStream printStream = new PrintStream(outStream);
- try {
- printStream.write("Uncaught exception in session executor thread: ".getBytes());
- } catch (IOException e2) {}
- e.getCause().printStackTrace(new PrintStream(outStream));
- System.err.println(outStream.toString());
+ ILog log = DsfPlugin.getDefault().getLog();
+ if (log != null) {
+ log.log(new Status(
+ IStatus.ERROR, DsfPlugin.PLUGIN_ID, -1, "Uncaught exception in DSF executor thread", e.getCause()));
+
+ // Print out the stack trace to console if assertions are enabled.
+ if(ASSERTIONS_ENABLED) {
+ ByteArrayOutputStream outStream = new ByteArrayOutputStream(512);
+ PrintStream printStream = new PrintStream(outStream);
+ try {
+ printStream.write("Uncaught exception in session executor thread: ".getBytes());
+ } catch (IOException e2) {}
+ e.getCause().printStackTrace(new PrintStream(outStream));
+ System.err.println(outStream.toString());
+ }
}
}
}
diff --git a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/Done.java b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/Done.java
index 5bff4d2d26b..7136de89b8c 100644
--- a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/Done.java
+++ b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/Done.java
@@ -23,6 +23,7 @@ import org.eclipse.dd.dsf.DsfPlugin;
* clients have to make sure that access to this object is thread safe if
* it's used outside of the caller's dispatch thread.
*/
+@ConfinedToDsfExecutor("")
abstract public class Done extends DsfRunnable {
private IStatus fStatus = Status.OK_STATUS;
diff --git a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DsfExecutable.java b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DsfExecutable.java
index 2a845472759..6ed2646a003 100644
--- a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DsfExecutable.java
+++ b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DsfExecutable.java
@@ -21,6 +21,7 @@ import java.util.Set;
* contains fields and methods that used for debugging and tracing when
* tracing is enabled.
*/
+@Immutable
public class DsfExecutable {
final StackTraceElement[] fCreatedAt;
final DefaultDsfExecutor.TracingWrapper fCreatedBy;
diff --git a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DsfExecutor.java b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DsfExecutor.java
index a3243f4cbb8..b8e895d41da 100644
--- a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DsfExecutor.java
+++ b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DsfExecutor.java
@@ -20,6 +20,7 @@ import java.util.concurrent.ScheduledExecutorService;
* to be exclusive to the executor, it could be shared with
* another event dispatch service, such as the SWT display dispatch thread.
*/
+@ThreadSafe
public interface DsfExecutor extends ScheduledExecutorService
{
/**
diff --git a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DsfQuery.java b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DsfQuery.java
index b944df7bb09..351f84bd674 100644
--- a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DsfQuery.java
+++ b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DsfQuery.java
@@ -27,6 +27,7 @@ import org.eclipse.dd.dsf.service.IDsfService;
*
* @see java.util.concurrent.Callable
*/
+@ThreadSafe
abstract public class DsfQuery
+ * Note: the runtime retention policy is there to allow automated testing
+ * and validation code.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+@Documented
+public @interface Immutable {
+
+}
diff --git a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/ThreadSafe.java b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/ThreadSafe.java
new file mode 100644
index 00000000000..af24e0d4120
--- /dev/null
+++ b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/ThreadSafe.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2006 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.concurrent;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation idicating that given package, class, method, or field can be
+ * access safely from any thread. If declared on package or type, a field
+ * or method could still be declared with an annotation indicating that it's
+ * not thread-safe.
+ *
+ * Note: the runtime retention policy is there to allow automated testing
+ * and validation code.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PACKAGE, ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR})
+@Inherited
+@Documented
+public @interface ThreadSafe {
+
+}
diff --git a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/model/AbstractDMC.java b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/model/AbstractDMC.java
index ecc291300e0..7defea3c20e 100644
--- a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/model/AbstractDMC.java
+++ b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/model/AbstractDMC.java
@@ -11,6 +11,7 @@
package org.eclipse.dd.dsf.model;
import org.eclipse.core.runtime.PlatformObject;
+import org.eclipse.dd.dsf.concurrent.Immutable;
import org.eclipse.dd.dsf.service.AbstractDsfService;
import org.eclipse.dd.dsf.service.DsfSession;
@@ -20,6 +21,7 @@ import org.eclipse.dd.dsf.service.DsfSession;
* correctly.
* @param
* This interface is intended primarily to allow for future development of
* a generic API to parametrize data model data.
- *
*/
public interface IDataModelData {
diff --git a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/service/DsfSession.java b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/service/DsfSession.java
index fc20317d3fb..7c541cf5a94 100644
--- a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/service/DsfSession.java
+++ b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/service/DsfSession.java
@@ -27,8 +27,10 @@ import java.util.TreeMap;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.dd.dsf.DsfPlugin;
+import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor;
import org.eclipse.dd.dsf.concurrent.DsfExecutor;
import org.eclipse.dd.dsf.concurrent.DsfRunnable;
+import org.eclipse.dd.dsf.concurrent.ThreadSafe;
import org.osgi.framework.Filter;
/**
@@ -47,13 +49,12 @@ import org.osgi.framework.Filter;
*
* @see org.eclipse.dd.dsf.concurrent.DsfExecutor
*/
+@ConfinedToDsfExecutor("getExecutor")
public class DsfSession
-{
-
+{
/**
* Listener for session started events. This listener is always going to be
* called in the dispatch thread of the session's executor.
- *
*/
public static interface SessionStartedListener {
/**
@@ -86,12 +87,15 @@ public class DsfSession
}
/** Returns a session instance for given session identifier */
+ @ThreadSafe
public static DsfSession getSession(String sessionId) {
- for (DsfSession session : fgActiveSessions) {
- if (session.getId().equals(sessionId)) {
- return session;
- }
- }
+ synchronized(fgActiveSessions) {
+ for (DsfSession session : fgActiveSessions) {
+ if (session.getId().equals(sessionId)) {
+ return session;
+ }
+ }
+ }
return null;
}
@@ -99,6 +103,7 @@ public class DsfSession
* Registers a listener for session started events.
* Can be called on any thread.
*/
+ @ThreadSafe
public static void addSessionStartedListener(SessionStartedListener listener) {
assert !fSessionStartedListeners.contains(listener);
fSessionStartedListeners.add(listener);
@@ -108,6 +113,7 @@ public class DsfSession
* Un-registers a listener for session started events.
* Can be called on any thread.
*/
+ @ThreadSafe
public static void removeSessionStartedListener(SessionStartedListener listener) {
assert fSessionStartedListeners.contains(listener);
fSessionStartedListeners.remove(listener);
@@ -117,6 +123,7 @@ public class DsfSession
* Registers a listener for session ended events.
* Can be called on any thread.
*/
+ @ThreadSafe
public static void addSessionEndedListener(SessionEndedListener listener) {
assert !fSessionEndedListeners.contains(listener);
fSessionEndedListeners.add(listener);
@@ -126,6 +133,7 @@ public class DsfSession
* Un-registers a listener for session ended events.
* Can be called on any thread.
*/
+ @ThreadSafe
public static void removeSessionEndedListener(SessionEndedListener listener) {
assert fSessionEndedListeners.contains(listener);
fSessionEndedListeners.remove(listener);
@@ -139,6 +147,7 @@ public class DsfSession
* @param ownerId ID (plugin ID preferably) of the owner of this session
* @return instance object of the new session
*/
+ @ThreadSafe
public static DsfSession startSession(DsfExecutor executor, String ownerId) {
synchronized(fgActiveSessions) {
final DsfSession newSession = new DsfSession(executor, ownerId, Integer.toString(fgSessionIdCounter++));
@@ -160,6 +169,7 @@ public class DsfSession
* executor.
* @param session session to terminate
*/
+ @ThreadSafe
public static void endSession(final DsfSession session) {
synchronized(fgActiveSessions) {
if (!fgActiveSessions.contains(session)) {
@@ -260,6 +270,7 @@ public class DsfSession
* @param event to be sent out
* @param serviceProperties properties of the service requesting the event to be dispatched
*/
+ @ThreadSafe
public void dispatchEvent(final Object event, final Dictionary serviceProperties) {
getExecutor().submit(new DsfRunnable() {
public void run() { doDispatchEvent(event, serviceProperties);}
@@ -273,6 +284,7 @@ public class DsfSession
* @param adapter adapter instance to register
* @see org.eclipse.dsdp.model.AbstractDMC#getAdapter
*/
+ @ThreadSafe
public void registerModelAdapter(Class adapterType, Object adapter) {
fAdapters.put(adapterType, adapter);
}
@@ -282,6 +294,7 @@ public class DsfSession
* @param adapterType adapter type to unregister
* @see org.eclipse.dsdp.model.AbstractDMC#getAdapter
*/
+ @ThreadSafe
public void unregisterModelAdapter(Class adapterType) {
fAdapters.remove(adapterType);
}
@@ -292,14 +305,17 @@ public class DsfSession
* @return adapter object for given type, null if none is registered with the session
* @see org.eclipse.dsdp.model.AbstractDMC#getAdapter
*/
+ @ThreadSafe
public Object getModelAdapter(Class adapterType) {
return fAdapters.get(adapterType);
}
+ @ThreadSafe
public boolean equals(Object other) {
return other instanceof DsfSession && fId.equals(((DsfSession)other).fId);
}
+ @ThreadSafe
public int hashCode() { return fId.hashCode(); }
private void doDispatchEvent(Object event, Dictionary serviceProperties) {
@@ -391,6 +407,7 @@ public class DsfSession
/**
* Class to be instanciated only using startSession()
*/
+ @ThreadSafe
private DsfSession(DsfExecutor executor, String ownerId, String id) {
fId = id;
fOwnerId = ownerId;
diff --git a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/service/IDsfService.java b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/service/IDsfService.java
index 3b62dea946a..5db2136b8b0 100644
--- a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/service/IDsfService.java
+++ b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/service/IDsfService.java
@@ -12,6 +12,7 @@ package org.eclipse.dd.dsf.service;
import java.util.Dictionary;
+import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor;
import org.eclipse.dd.dsf.concurrent.Done;
import org.eclipse.dd.dsf.concurrent.DsfExecutor;
@@ -34,6 +35,7 @@ import org.eclipse.dd.dsf.concurrent.DsfExecutor;
*
* @see org.osgi.framework.BundleContext#registerService(String[], Object, Dictionary)
*/
+@ConfinedToDsfExecutor("getExecutor")
public interface IDsfService {
/**