1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-29 19:45:01 +02:00

Bugzilla 205603 & 221899.

This commit is contained in:
Randy Rohrbach 2008-05-02 20:16:34 +00:00
parent 34baaa437d
commit b80e85ffde
28 changed files with 2988 additions and 112 deletions

View file

@ -71,7 +71,11 @@ public class StackFramesVMNode extends AbstractDMVMNode
@Override @Override
protected void updateElementsInSessionThread(final IChildrenUpdate update) { protected void updateElementsInSessionThread(final IChildrenUpdate update) {
if (!checkService(IStack.class, null, update)) return;
if ( getServicesTracker().getService(IStack.class) == null ) {
handleFailedUpdate(update);
return;
}
final IExecutionDMContext execDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IExecutionDMContext.class); final IExecutionDMContext execDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IExecutionDMContext.class);
if (execDmc == null) { if (execDmc == null) {
@ -88,7 +92,10 @@ public class StackFramesVMNode extends AbstractDMVMNode
// Failed to retrieve frames. If we are stepping, we // Failed to retrieve frames. If we are stepping, we
// might still be able to retrieve just the top stack // might still be able to retrieve just the top stack
// frame, which would still be useful in Debug View. // frame, which would still be useful in Debug View.
if (!checkService(IRunControl.class, null, update)) return; if ( getServicesTracker().getService(IRunControl.class) == null ) {
handleFailedUpdate(update);
return;
}
if (getServicesTracker().getService(IRunControl.class).isStepping(execDmc)) { if (getServicesTracker().getService(IRunControl.class).isStepping(execDmc)) {
getElementsTopStackFrameOnly(update); getElementsTopStackFrameOnly(update);
} else { } else {
@ -121,7 +128,10 @@ public class StackFramesVMNode extends AbstractDMVMNode
try { try {
getSession().getExecutor().execute(new DsfRunnable() { getSession().getExecutor().execute(new DsfRunnable() {
public void run() { public void run() {
if (!checkService(IStack.class, null, update)) return; if ( getServicesTracker().getService(IStack.class) == null ) {
handleFailedUpdate(update);
return;
}
getServicesTracker().getService(IStack.class).getTopFrame( getServicesTracker().getService(IStack.class).getTopFrame(
execDmc, execDmc,
@ -173,7 +183,16 @@ public class StackFramesVMNode extends AbstractDMVMNode
protected void updateLabelInSessionThread(ILabelUpdate[] updates) { protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
for (final ILabelUpdate update : updates) { for (final ILabelUpdate update : updates) {
final IFrameDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IFrameDMContext.class); final IFrameDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IFrameDMContext.class);
if (!checkDmc(dmc, update) || !checkService(IStack.class, null, update)) continue;
if ( dmc == null ) {
handleFailedUpdate(update);
continue;
}
if ( getServicesTracker().getService(IStack.class) == null ) {
handleFailedUpdate(update);
continue;
}
getDMVMProvider().getModelData( getDMVMProvider().getModelData(
this, update, this, update,

View file

@ -42,7 +42,11 @@ public class ModulesVMNode extends AbstractDMVMNode
@Override @Override
protected void updateElementsInSessionThread(final IChildrenUpdate update) { protected void updateElementsInSessionThread(final IChildrenUpdate update) {
if (!checkService(IModules.class, null, update)) return;
if ( getServicesTracker().getService(IModules.class) == null ) {
handleFailedUpdate(update);
return;
}
final ISymbolDMContext symDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), ISymbolDMContext.class) ; final ISymbolDMContext symDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), ISymbolDMContext.class) ;
@ -83,7 +87,16 @@ public class ModulesVMNode extends AbstractDMVMNode
protected void updateLabelInSessionThread(ILabelUpdate[] updates) { protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
for (final ILabelUpdate update : updates) { for (final ILabelUpdate update : updates) {
final IModuleDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IModuleDMContext.class); final IModuleDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IModuleDMContext.class);
if (!checkDmc(dmc, update) || !checkService(IModules.class, null, update)) continue; // If either update or service are not valid, fail the update and exit.
if ( dmc == null ) {
handleFailedUpdate(update);
continue;
}
if ( getServicesTracker().getService(IModules.class) == null ) {
handleFailedUpdate(update);
continue;
}
// Use different image for loaded and unloaded symbols when event to report loading of symbols is implemented. // Use different image for loaded and unloaded symbols when event to report loading of symbols is implemented.
update.setImageDescriptor(DsfDebugUIPlugin.getImageDescriptor(IDsfDebugUIConstants.IMG_OBJS_SHARED_LIBRARY_SYMBOLS_LOADED), 0); update.setImageDescriptor(DsfDebugUIPlugin.getImageDescriptor(IDsfDebugUIConstants.IMG_OBJS_SHARED_LIBRARY_SYMBOLS_LOADED), 0);

View file

@ -29,6 +29,7 @@ import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.numberformat.I
import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.register.RegisterBitFieldCellModifier.BitFieldEditorStyle; import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.register.RegisterBitFieldCellModifier.BitFieldEditorStyle;
import org.eclipse.dd.dsf.debug.internal.ui.DsfDebugUIPlugin; import org.eclipse.dd.dsf.debug.internal.ui.DsfDebugUIPlugin;
import org.eclipse.dd.dsf.debug.service.IFormattedValues; import org.eclipse.dd.dsf.debug.service.IFormattedValues;
import org.eclipse.dd.dsf.debug.service.IMemory;
import org.eclipse.dd.dsf.debug.service.IRegisters; import org.eclipse.dd.dsf.debug.service.IRegisters;
import org.eclipse.dd.dsf.debug.service.IRunControl; import org.eclipse.dd.dsf.debug.service.IRunControl;
import org.eclipse.dd.dsf.debug.service.IFormattedValues.FormattedValueDMContext; import org.eclipse.dd.dsf.debug.service.IFormattedValues.FormattedValueDMContext;
@ -71,7 +72,6 @@ import org.eclipse.swt.widgets.Composite;
public class RegisterBitFieldVMNode extends AbstractExpressionVMNode public class RegisterBitFieldVMNode extends AbstractExpressionVMNode
implements IElementEditor, IElementLabelProvider implements IElementEditor, IElementLabelProvider
{ {
protected class BitFieldVMC extends DMVMContext protected class BitFieldVMC extends DMVMContext
implements IFormattedValueVMContext implements IFormattedValueVMContext
{ {
@ -271,7 +271,10 @@ public class RegisterBitFieldVMNode extends AbstractExpressionVMNode
); );
} }
/*
* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider#update(org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate[])
*/
public void update(final ILabelUpdate[] updates) { public void update(final ILabelUpdate[] updates) {
try { try {
getSession().getExecutor().execute(new DsfRunnable() { getSession().getExecutor().execute(new DsfRunnable() {
@ -285,17 +288,25 @@ public class RegisterBitFieldVMNode extends AbstractExpressionVMNode
} }
} }
/*
* Updates the requested label based on the specified column.
*/
protected void updateLabelInSessionThread(ILabelUpdate[] updates) { protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
for (final ILabelUpdate update : updates) { for (final ILabelUpdate update : updates) {
if (!checkService(IRegisters.class, null, update)) continue; final IRegisters regService = getServicesTracker().getService(IRegisters.class);
if ( regService == null ) {
handleFailedUpdate(update);
continue;
}
final IBitFieldDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IRegisters.IBitFieldDMContext.class); final IBitFieldDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IRegisters.IBitFieldDMContext.class);
getDMVMProvider().getModelData( getDMVMProvider().getModelData(
this, update, this,
getServicesTracker().getService(IRegisters.class), update,
regService,
dmc, dmc,
new DataRequestMonitor<IBitFieldDMData>(getSession().getExecutor(), null) { new DataRequestMonitor<IBitFieldDMData>(getSession().getExecutor(), null) {
@Override @Override
@ -422,6 +433,10 @@ public class RegisterBitFieldVMNode extends AbstractExpressionVMNode
} }
} }
/*
* (non-Javadoc)
* @see org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMNode#updateElementsInSessionThread(org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate)
*/
@Override @Override
protected void updateElementsInSessionThread(final IChildrenUpdate update) { protected void updateElementsInSessionThread(final IChildrenUpdate update) {
final IRegisterDMContext regDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IRegisterDMContext.class); final IRegisterDMContext regDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IRegisterDMContext.class);
@ -431,9 +446,15 @@ public class RegisterBitFieldVMNode extends AbstractExpressionVMNode
return; return;
} }
if (!checkService(IRegisters.class, null, update)) return; IRegisters regService = getServicesTracker().getService(IRegisters.class);
getServicesTracker().getService(IRegisters.class).getBitFields( if ( regService == null ) {
handleFailedUpdate(update);
return;
}
regService.getBitFields(
regDmc, regDmc,
new DataRequestMonitor<IBitFieldDMContext[]>(getSession().getExecutor(), null) { new DataRequestMonitor<IBitFieldDMContext[]>(getSession().getExecutor(), null) {
@Override @Override
@ -449,11 +470,19 @@ public class RegisterBitFieldVMNode extends AbstractExpressionVMNode
}); });
} }
/*
* (non-Javadoc)
* @see org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMNode#createVMContext(org.eclipse.dd.dsf.datamodel.IDMContext)
*/
@Override @Override
protected IDMVMContext createVMContext(IDMContext dmc) { protected IDMVMContext createVMContext(IDMContext dmc) {
return new BitFieldVMC(dmc); return new BitFieldVMC(dmc);
} }
/*
* (non-Javadoc)
* @see org.eclipse.dd.dsf.ui.viewmodel.IVMNode#getDeltaFlags(java.lang.Object)
*/
public int getDeltaFlags(Object e) { public int getDeltaFlags(Object e) {
if (e instanceof IRunControl.ISuspendedDMEvent) { if (e instanceof IRunControl.ISuspendedDMEvent) {
return IModelDelta.CONTENT; return IModelDelta.CONTENT;
@ -463,6 +492,10 @@ public class RegisterBitFieldVMNode extends AbstractExpressionVMNode
return IModelDelta.STATE; return IModelDelta.STATE;
} }
if (e instanceof IMemory.IMemoryChangedEvent) {
return IModelDelta.CONTENT;
}
if (e instanceof PropertyChangeEvent && if (e instanceof PropertyChangeEvent &&
((PropertyChangeEvent)e).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE) ((PropertyChangeEvent)e).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE)
{ {
@ -472,6 +505,10 @@ public class RegisterBitFieldVMNode extends AbstractExpressionVMNode
return IModelDelta.NO_CHANGE; return IModelDelta.NO_CHANGE;
} }
/*
* (non-Javadoc)
* @see org.eclipse.dd.dsf.ui.viewmodel.IVMNode#buildDelta(java.lang.Object, org.eclipse.dd.dsf.ui.viewmodel.VMDelta, int, org.eclipse.dd.dsf.concurrent.RequestMonitor)
*/
public void buildDelta(Object e, VMDelta parentDelta, int nodeOffset, RequestMonitor rm) { public void buildDelta(Object e, VMDelta parentDelta, int nodeOffset, RequestMonitor rm) {
if (e instanceof IRunControl.ISuspendedDMEvent) { if (e instanceof IRunControl.ISuspendedDMEvent) {
// Create a delta that the whole register group has changed. // Create a delta that the whole register group has changed.
@ -479,13 +516,16 @@ public class RegisterBitFieldVMNode extends AbstractExpressionVMNode
} }
if (e instanceof IRegisters.IBitFieldChangedDMEvent) { if (e instanceof IRegisters.IBitFieldChangedDMEvent) {
/* /*
* Create a delta indicating the bit field has changed. * Create a delta indicating the bit field has changed.
*/ */
parentDelta.addNode( createVMContext(((IRegisters.IBitFieldChangedDMEvent)e).getDMContext()), IModelDelta.STATE ); parentDelta.addNode( createVMContext(((IRegisters.IBitFieldChangedDMEvent)e).getDMContext()), IModelDelta.STATE );
} }
if (e instanceof IMemory.IMemoryChangedEvent) {
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
}
if (e instanceof PropertyChangeEvent && if (e instanceof PropertyChangeEvent &&
((PropertyChangeEvent)e).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE) ((PropertyChangeEvent)e).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE)
{ {
@ -495,6 +535,10 @@ public class RegisterBitFieldVMNode extends AbstractExpressionVMNode
rm.done(); rm.done();
} }
/*
* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementEditor#getCellEditor(org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext, java.lang.String, java.lang.Object, org.eclipse.swt.widgets.Composite)
*/
public CellEditor getCellEditor(IPresentationContext context, String columnId, Object element, Composite parent) { public CellEditor getCellEditor(IPresentationContext context, String columnId, Object element, Composite parent) {
if (IDebugVMConstants.COLUMN_ID__VALUE.equals(columnId)) { if (IDebugVMConstants.COLUMN_ID__VALUE.equals(columnId)) {
@ -541,6 +585,10 @@ public class RegisterBitFieldVMNode extends AbstractExpressionVMNode
return null; return null;
} }
/*
* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementEditor#getCellModifier(org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext, java.lang.Object)
*/
public ICellModifier getCellModifier(IPresentationContext context, Object element) { public ICellModifier getCellModifier(IPresentationContext context, Object element) {
/* /*
@ -628,6 +676,10 @@ public class RegisterBitFieldVMNode extends AbstractExpressionVMNode
return null; return null;
} }
/*
* (non-Javadoc)
* @see org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.expression.AbstractExpressionVMNode#testElementForExpression(java.lang.Object, org.eclipse.debug.core.model.IExpression, org.eclipse.dd.dsf.concurrent.DataRequestMonitor)
*/
@Override @Override
protected void testElementForExpression(Object element, IExpression expression, final DataRequestMonitor<Boolean> rm) { protected void testElementForExpression(Object element, IExpression expression, final DataRequestMonitor<Boolean> rm) {
if (!(element instanceof IDMVMContext)) { if (!(element instanceof IDMVMContext)) {
@ -670,6 +722,10 @@ public class RegisterBitFieldVMNode extends AbstractExpressionVMNode
} }
} }
/*
* (non-Javadoc)
* @see org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.expression.AbstractExpressionVMNode#associateExpression(java.lang.Object, org.eclipse.debug.core.model.IExpression)
*/
@Override @Override
protected void associateExpression(Object element, IExpression expression) { protected void associateExpression(Object element, IExpression expression) {
if (element instanceof BitFieldVMC) { if (element instanceof BitFieldVMC) {
@ -677,33 +733,56 @@ public class RegisterBitFieldVMNode extends AbstractExpressionVMNode
} }
} }
/*
* (non-Javadoc)
* @see org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.expression.IExpressionVMNode#getDeltaFlagsForExpression(org.eclipse.debug.core.model.IExpression, java.lang.Object)
*/
public int getDeltaFlagsForExpression(IExpression expression, Object event) { public int getDeltaFlagsForExpression(IExpression expression, Object event) {
if (event instanceof IRunControl.ISuspendedDMEvent) { if (event instanceof IRunControl.ISuspendedDMEvent) {
return IModelDelta.CONTENT; return IModelDelta.CONTENT;
} }
if (event instanceof PropertyChangeEvent && if (event instanceof PropertyChangeEvent &&
((PropertyChangeEvent)event).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE) ((PropertyChangeEvent)event).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE) {
{ return IModelDelta.CONTENT;
}
if (event instanceof IMemory.IMemoryChangedEvent) {
return IModelDelta.CONTENT; return IModelDelta.CONTENT;
} }
return IModelDelta.NO_CHANGE; return IModelDelta.NO_CHANGE;
} }
/*
* (non-Javadoc)
* @see org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.expression.IExpressionVMNode#buildDeltaForExpression(org.eclipse.debug.core.model.IExpression, int, java.lang.Object, org.eclipse.dd.dsf.ui.viewmodel.VMDelta, org.eclipse.jface.viewers.TreePath, org.eclipse.dd.dsf.concurrent.RequestMonitor)
*/
public void buildDeltaForExpression(final IExpression expression, final int elementIdx, final Object event, final VMDelta parentDelta, final TreePath path, final RequestMonitor rm) public void buildDeltaForExpression(final IExpression expression, final int elementIdx, final Object event, final VMDelta parentDelta, final TreePath path, final RequestMonitor rm)
{ {
if (event instanceof ISuspendedDMEvent) { if (event instanceof ISuspendedDMEvent) {
// Mark the parent delta indicating that elements were added and/or removed. // Mark the parent delta indicating that elements were added and/or removed.
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT); parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
} else if (event instanceof IRegisters.IRegisterChangedDMEvent) { }
else if (event instanceof IRegisters.IRegisterChangedDMEvent) {
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT); parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
} }
else if (event instanceof IMemory.IMemoryChangedEvent) {
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
}
rm.done(); rm.done();
} }
/*
* (non-Javadoc)
* @see org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.expression.IExpressionVMNode#buildDeltaForExpressionElement(java.lang.Object, int, java.lang.Object, org.eclipse.dd.dsf.ui.viewmodel.VMDelta, org.eclipse.dd.dsf.concurrent.RequestMonitor)
*/
public void buildDeltaForExpressionElement(Object element, int elementIdx, Object event, VMDelta parentDelta, final RequestMonitor rm) public void buildDeltaForExpressionElement(Object element, int elementIdx, Object event, VMDelta parentDelta, final RequestMonitor rm)
{ {
if (event instanceof IMemory.IMemoryChangedEvent) {
parentDelta.addNode(element, IModelDelta.STATE);
}
if (event instanceof IBitFieldChangedDMEvent) { if (event instanceof IBitFieldChangedDMEvent) {
parentDelta.addNode(element, IModelDelta.STATE); parentDelta.addNode(element, IModelDelta.STATE);
} }

View file

@ -58,7 +58,6 @@ import org.eclipse.swt.widgets.Composite;
public class RegisterGroupVMNode extends AbstractExpressionVMNode public class RegisterGroupVMNode extends AbstractExpressionVMNode
implements IElementEditor, IElementLabelProvider implements IElementEditor, IElementLabelProvider
{ {
protected class RegisterGroupVMC extends DMVMContext protected class RegisterGroupVMC extends DMVMContext
{ {
private IExpression fExpression; private IExpression fExpression;
@ -134,10 +133,21 @@ public class RegisterGroupVMNode extends AbstractExpressionVMNode
return fSyncRegisterDataAccess; return fSyncRegisterDataAccess;
} }
/*
* (non-Javadoc)
* @see org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMNode#updateElementsInSessionThread(org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate)
*/
@Override @Override
protected void updateElementsInSessionThread(final IChildrenUpdate update) { protected void updateElementsInSessionThread(final IChildrenUpdate update) {
if (!checkService(IRegisters.class, null, update)) return;
getServicesTracker().getService(IRegisters.class).getRegisterGroups( IRegisters regService = getServicesTracker().getService(IRegisters.class);
if ( regService == null ) {
handleFailedUpdate(update);
return;
}
regService.getRegisterGroups(
createCompositeDMVMContext(update), createCompositeDMVMContext(update),
new DataRequestMonitor<IRegisterGroupDMContext[]>(getSession().getExecutor(), null) { new DataRequestMonitor<IRegisterGroupDMContext[]>(getSession().getExecutor(), null) {
@Override @Override
@ -151,12 +161,19 @@ public class RegisterGroupVMNode extends AbstractExpressionVMNode
}}); }});
} }
/*
* (non-Javadoc)
* @see org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMNode#createVMContext(org.eclipse.dd.dsf.datamodel.IDMContext)
*/
@Override @Override
protected IDMVMContext createVMContext(IDMContext dmc) { protected IDMVMContext createVMContext(IDMContext dmc) {
return new RegisterGroupVMC(dmc); return new RegisterGroupVMC(dmc);
} }
/*
* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider#update(org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate[])
*/
public void update(final ILabelUpdate[] updates) { public void update(final ILabelUpdate[] updates) {
try { try {
getSession().getExecutor().execute(new DsfRunnable() { getSession().getExecutor().execute(new DsfRunnable() {
@ -170,15 +187,28 @@ public class RegisterGroupVMNode extends AbstractExpressionVMNode
} }
} }
/*
* Updates the labels with the required information for each visible column.
*/
protected void updateLabelInSessionThread(ILabelUpdate[] updates) { protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
for (final ILabelUpdate update : updates) { for (final ILabelUpdate update : updates) {
final IRegisterGroupDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IRegisterGroupDMContext.class); final IRegisterGroupDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IRegisterGroupDMContext.class);
if (!checkDmc(dmc, update) || !checkService(IRegisters.class, null, update)) continue; if ( dmc == null ) {
handleFailedUpdate(update);
continue;
}
IRegisters regService = getServicesTracker().getService(IRegisters.class);
if ( regService == null ) {
handleFailedUpdate(update);
continue;
}
getDMVMProvider().getModelData( getDMVMProvider().getModelData(
this, update, this,
getServicesTracker().getService(IRegisters.class, null), update,
regService,
dmc, dmc,
new DataRequestMonitor<IRegisterGroupDMData>(getSession().getExecutor(), null) { new DataRequestMonitor<IRegisterGroupDMData>(getSession().getExecutor(), null) {
@Override @Override
@ -214,6 +244,9 @@ public class RegisterGroupVMNode extends AbstractExpressionVMNode
} }
} }
/*
* Based on the specified visible column, provide the appropriate value/label.
*/
protected void fillColumnLabel(IRegisterGroupDMContext dmContext, IRegisterGroupDMData dmData, protected void fillColumnLabel(IRegisterGroupDMContext dmContext, IRegisterGroupDMData dmData,
String columnId, int idx, ILabelUpdate update) String columnId, int idx, ILabelUpdate update)
{ {
@ -248,6 +281,10 @@ public class RegisterGroupVMNode extends AbstractExpressionVMNode
} }
} }
/*
* (non-Javadoc)
* @see org.eclipse.dd.dsf.ui.viewmodel.IVMNode#getDeltaFlags(java.lang.Object)
*/
public int getDeltaFlags(Object e) { public int getDeltaFlags(Object e) {
if (e instanceof IRunControl.ISuspendedDMEvent) { if (e instanceof IRunControl.ISuspendedDMEvent) {
return IModelDelta.CONTENT; return IModelDelta.CONTENT;
@ -261,6 +298,10 @@ public class RegisterGroupVMNode extends AbstractExpressionVMNode
return IModelDelta.NO_CHANGE; return IModelDelta.NO_CHANGE;
} }
/*
* (non-Javadoc)
* @see org.eclipse.dd.dsf.ui.viewmodel.IVMNode#buildDelta(java.lang.Object, org.eclipse.dd.dsf.ui.viewmodel.VMDelta, int, org.eclipse.dd.dsf.concurrent.RequestMonitor)
*/
public void buildDelta(Object e, VMDelta parentDelta, int nodeOffset, RequestMonitor rm) { public void buildDelta(Object e, VMDelta parentDelta, int nodeOffset, RequestMonitor rm) {
if (e instanceof IRunControl.ISuspendedDMEvent) { if (e instanceof IRunControl.ISuspendedDMEvent) {
// Create a delta that indicates all groups have changed // Create a delta that indicates all groups have changed
@ -277,6 +318,10 @@ public class RegisterGroupVMNode extends AbstractExpressionVMNode
rm.done(); rm.done();
} }
/*
* (non-Javadoc)
* @see org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.expression.IExpressionVMNode#canParseExpression(org.eclipse.debug.core.model.IExpression)
*/
public boolean canParseExpression(IExpression expression) { public boolean canParseExpression(IExpression expression) {
return parseExpressionForGroupName(expression.getExpressionText()) != null; return parseExpressionForGroupName(expression.getExpressionText()) != null;
} }
@ -298,6 +343,10 @@ public class RegisterGroupVMNode extends AbstractExpressionVMNode
return null; return null;
} }
/*
* (non-Javadoc)
* @see org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.expression.IExpressionVMNode#getDeltaFlagsForExpression(org.eclipse.debug.core.model.IExpression, java.lang.Object)
*/
public int getDeltaFlagsForExpression(IExpression expression, Object event) { public int getDeltaFlagsForExpression(IExpression expression, Object event) {
if (event instanceof IRunControl.ISuspendedDMEvent) { if (event instanceof IRunControl.ISuspendedDMEvent) {
return IModelDelta.CONTENT; return IModelDelta.CONTENT;
@ -306,6 +355,10 @@ public class RegisterGroupVMNode extends AbstractExpressionVMNode
return IModelDelta.NO_CHANGE; return IModelDelta.NO_CHANGE;
} }
/*
* (non-Javadoc)
* @see org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.expression.IExpressionVMNode#buildDeltaForExpression(org.eclipse.debug.core.model.IExpression, int, java.lang.Object, org.eclipse.dd.dsf.ui.viewmodel.VMDelta, org.eclipse.jface.viewers.TreePath, org.eclipse.dd.dsf.concurrent.RequestMonitor)
*/
public void buildDeltaForExpression(IExpression expression, int elementIdx, Object event, VMDelta parentDelta, public void buildDeltaForExpression(IExpression expression, int elementIdx, Object event, VMDelta parentDelta,
TreePath path, RequestMonitor rm) TreePath path, RequestMonitor rm)
{ {
@ -316,6 +369,10 @@ public class RegisterGroupVMNode extends AbstractExpressionVMNode
rm.done(); rm.done();
} }
/*
* (non-Javadoc)
* @see org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.expression.IExpressionVMNode#buildDeltaForExpressionElement(java.lang.Object, int, java.lang.Object, org.eclipse.dd.dsf.ui.viewmodel.VMDelta, org.eclipse.dd.dsf.concurrent.RequestMonitor)
*/
public void buildDeltaForExpressionElement(Object element, int elementIdx, Object event, VMDelta parentDelta, final RequestMonitor rm) public void buildDeltaForExpressionElement(Object element, int elementIdx, Object event, VMDelta parentDelta, final RequestMonitor rm)
{ {
if (event instanceof IRegisters.IGroupsChangedDMEvent) { if (event instanceof IRegisters.IGroupsChangedDMEvent) {
@ -327,6 +384,10 @@ public class RegisterGroupVMNode extends AbstractExpressionVMNode
rm.done(); rm.done();
} }
/*
* (non-Javadoc)
* @see org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.expression.AbstractExpressionVMNode#testElementForExpression(java.lang.Object, org.eclipse.debug.core.model.IExpression, org.eclipse.dd.dsf.concurrent.DataRequestMonitor)
*/
@Override @Override
protected void testElementForExpression(Object element, IExpression expression, final DataRequestMonitor<Boolean> rm) { protected void testElementForExpression(Object element, IExpression expression, final DataRequestMonitor<Boolean> rm) {
if (!(element instanceof IDMVMContext)) { if (!(element instanceof IDMVMContext)) {
@ -368,6 +429,10 @@ public class RegisterGroupVMNode extends AbstractExpressionVMNode
} }
} }
/*
* (non-Javadoc)
* @see org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.expression.AbstractExpressionVMNode#associateExpression(java.lang.Object, org.eclipse.debug.core.model.IExpression)
*/
@Override @Override
protected void associateExpression(Object element, IExpression expression) { protected void associateExpression(Object element, IExpression expression) {
if (element instanceof RegisterGroupVMC) { if (element instanceof RegisterGroupVMC) {
@ -375,6 +440,10 @@ public class RegisterGroupVMNode extends AbstractExpressionVMNode
} }
} }
/*
* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementEditor#getCellEditor(org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext, java.lang.String, java.lang.Object, org.eclipse.swt.widgets.Composite)
*/
public CellEditor getCellEditor(IPresentationContext context, String columnId, Object element, Composite parent) { public CellEditor getCellEditor(IPresentationContext context, String columnId, Object element, Composite parent) {
if (IDebugVMConstants.COLUMN_ID__EXPRESSION.equals(columnId)) { if (IDebugVMConstants.COLUMN_ID__EXPRESSION.equals(columnId)) {
return new TextCellEditor(parent); return new TextCellEditor(parent);
@ -382,8 +451,11 @@ public class RegisterGroupVMNode extends AbstractExpressionVMNode
return null; return null;
} }
/*
* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementEditor#getCellModifier(org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext, java.lang.Object)
*/
public ICellModifier getCellModifier(IPresentationContext context, Object element) { public ICellModifier getCellModifier(IPresentationContext context, Object element) {
return fWatchExpressionCellModifier; return fWatchExpressionCellModifier;
} }
} }

View file

@ -28,6 +28,7 @@ import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.numberformat.I
import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.numberformat.IFormattedValueVMContext; import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.numberformat.IFormattedValueVMContext;
import org.eclipse.dd.dsf.debug.internal.ui.DsfDebugUIPlugin; import org.eclipse.dd.dsf.debug.internal.ui.DsfDebugUIPlugin;
import org.eclipse.dd.dsf.debug.service.IFormattedValues; import org.eclipse.dd.dsf.debug.service.IFormattedValues;
import org.eclipse.dd.dsf.debug.service.IMemory;
import org.eclipse.dd.dsf.debug.service.IRegisters; import org.eclipse.dd.dsf.debug.service.IRegisters;
import org.eclipse.dd.dsf.debug.service.IRunControl; import org.eclipse.dd.dsf.debug.service.IRunControl;
import org.eclipse.dd.dsf.debug.service.IFormattedValues.FormattedValueDMContext; import org.eclipse.dd.dsf.debug.service.IFormattedValues.FormattedValueDMContext;
@ -159,9 +160,13 @@ public class RegisterVMNode extends AbstractExpressionVMNode
*/ */
private void updateFormattedRegisterValue(final ILabelUpdate update, final int labelIndex, final IRegisterDMContext dmc) private void updateFormattedRegisterValue(final ILabelUpdate update, final int labelIndex, final IRegisterDMContext dmc)
{ {
if (!checkService(IRegisters.class, null, update)) return;
final IRegisters regService = getServicesTracker().getService(IRegisters.class); final IRegisters regService = getServicesTracker().getService(IRegisters.class);
if ( regService == null ) {
handleFailedUpdate(update);
return;
}
/* /*
* First select the format to be used. This involves checking so see that the preference * First select the format to be used. This involves checking so see that the preference
* page format is supported by the register service. If the format is not supported then * page format is supported by the register service. If the format is not supported then
@ -260,6 +265,10 @@ public class RegisterVMNode extends AbstractExpressionVMNode
); );
} }
/*
* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider#update(org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate[])
*/
public void update(final ILabelUpdate[] updates) { public void update(final ILabelUpdate[] updates) {
try { try {
@ -274,15 +283,29 @@ public class RegisterVMNode extends AbstractExpressionVMNode
} }
} }
/*
* Updates the labels which are controlled by the column being requested.
*/
protected void updateLabelInSessionThread(ILabelUpdate[] updates) { protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
for (final ILabelUpdate update : updates) { for (final ILabelUpdate update : updates) {
final IRegisterDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IRegisters.IRegisterDMContext.class); final IRegisterDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IRegisters.IRegisterDMContext.class);
if (!checkDmc(dmc, update) || !checkService(IRegisters.class, null, update)) continue; if ( dmc == null ) {
handleFailedUpdate(update);
continue;
}
IRegisters regService = getServicesTracker().getService(IRegisters.class);
if ( regService == null ) {
handleFailedUpdate(update);
continue;
}
getDMVMProvider().getModelData( getDMVMProvider().getModelData(
this, update, this,
getServicesTracker().getService(IRegisters.class), update,
regService,
dmc, dmc,
new DataRequestMonitor<IRegisterDMData>(getSession().getExecutor(), null) { new DataRequestMonitor<IRegisterDMData>(getSession().getExecutor(), null) {
@Override @Override
@ -409,10 +432,21 @@ public class RegisterVMNode extends AbstractExpressionVMNode
} }
} }
/*
* (non-Javadoc)
* @see org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMNode#updateElementsInSessionThread(org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate)
*/
@Override @Override
protected void updateElementsInSessionThread(final IChildrenUpdate update) { protected void updateElementsInSessionThread(final IChildrenUpdate update) {
if (!checkService(IRegisters.class, null, update)) return;
getServicesTracker().getService(IRegisters.class).getRegisters( IRegisters regService = getServicesTracker().getService(IRegisters.class);
if ( regService == null ) {
handleFailedUpdate(update);
return;
}
regService.getRegisters(
createCompositeDMVMContext(update), createCompositeDMVMContext(update),
new DataRequestMonitor<IRegisterDMContext[]>(getSession().getExecutor(), null) { new DataRequestMonitor<IRegisterDMContext[]>(getSession().getExecutor(), null) {
@Override @Override
@ -427,21 +461,20 @@ public class RegisterVMNode extends AbstractExpressionVMNode
}); });
} }
/*
* (non-Javadoc)
* @see org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMNode#createVMContext(org.eclipse.dd.dsf.datamodel.IDMContext)
*/
@Override @Override
protected IDMVMContext createVMContext(IDMContext dmc) { protected IDMVMContext createVMContext(IDMContext dmc) {
return new RegisterVMC(dmc); return new RegisterVMC(dmc);
} }
/*
* (non-Javadoc)
* @see org.eclipse.dd.dsf.ui.viewmodel.IVMNode#getDeltaFlags(java.lang.Object)
*/
public int getDeltaFlags(Object e) { public int getDeltaFlags(Object e) {
/* In theory we want each node to act independently in terms of events. It might be
* the case that we would only have elements of this type at the root level. It is
* the case that the current layout model always starts with the GROUPS followed by
* REGISTERS followed by BITFIELDS. But if we do this when a run-control event has
* occured we generate a DELTA for every element, which can create a massive list
* of entries all of which say update the entire view. So for now we will just have
* the GROUP LAYOUT node do this. Later we need to revisit the logic and make sure
* there is a way for the nodes to operate independently and efficiently.
*/
if (e instanceof IRunControl.ISuspendedDMEvent) { if (e instanceof IRunControl.ISuspendedDMEvent) {
return IModelDelta.CONTENT; return IModelDelta.CONTENT;
} }
@ -450,10 +483,14 @@ public class RegisterVMNode extends AbstractExpressionVMNode
return IModelDelta.CONTENT; return IModelDelta.CONTENT;
} }
if (e instanceof IMemory.IMemoryChangedEvent) {
return IModelDelta.CONTENT;
}
if (e instanceof IRegisters.IRegisterChangedDMEvent) { if (e instanceof IRegisters.IRegisterChangedDMEvent) {
/* /*
* Logically one would think that STATE should be specified here. But we specifiy CONTENT * Logically one would think that STATE should be specified here. But we specify CONTENT
* as well so that if there are subregisters ( BIT FIELDS ) they will be forced to update * as well so that if there are sub-registers ( BIT FIELDS ) they will be forced to update
* and show new values when the total register changes. * and show new values when the total register changes.
*/ */
return IModelDelta.CONTENT; return IModelDelta.CONTENT;
@ -467,6 +504,10 @@ public class RegisterVMNode extends AbstractExpressionVMNode
return IModelDelta.NO_CHANGE; return IModelDelta.NO_CHANGE;
} }
/*
* (non-Javadoc)
* @see org.eclipse.dd.dsf.ui.viewmodel.IVMNode#buildDelta(java.lang.Object, org.eclipse.dd.dsf.ui.viewmodel.VMDelta, int, org.eclipse.dd.dsf.concurrent.RequestMonitor)
*/
public void buildDelta(Object e, VMDelta parentDelta, int nodeOffset, RequestMonitor rm) { public void buildDelta(Object e, VMDelta parentDelta, int nodeOffset, RequestMonitor rm) {
if (e instanceof IRunControl.ISuspendedDMEvent) { if (e instanceof IRunControl.ISuspendedDMEvent) {
// Create a delta that the whole register group has changed. // Create a delta that the whole register group has changed.
@ -477,6 +518,11 @@ public class RegisterVMNode extends AbstractExpressionVMNode
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);; parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);;
} }
if (e instanceof IMemory.IMemoryChangedEvent) {
// Mark the parent delta indicating that elements were added and/or removed.
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
}
if (e instanceof IRegisters.IRegisterChangedDMEvent) { if (e instanceof IRegisters.IRegisterChangedDMEvent) {
parentDelta.addNode( createVMContext(((IRegisterChangedDMEvent)e).getDMContext()), IModelDelta.CONTENT | IModelDelta.STATE ); parentDelta.addNode( createVMContext(((IRegisterChangedDMEvent)e).getDMContext()), IModelDelta.CONTENT | IModelDelta.STATE );
} }
@ -539,6 +585,11 @@ public class RegisterVMNode extends AbstractExpressionVMNode
return null; return null;
} }
/*
* (non-Javadoc)
* @see org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.expression.AbstractExpressionVMNode#testElementForExpression(java.lang.Object, org.eclipse.debug.core.model.IExpression, org.eclipse.dd.dsf.concurrent.DataRequestMonitor)
*/
@Override @Override
protected void testElementForExpression(Object element, IExpression expression, final DataRequestMonitor<Boolean> rm) { protected void testElementForExpression(Object element, IExpression expression, final DataRequestMonitor<Boolean> rm) {
if (!(element instanceof IDMVMContext)) { if (!(element instanceof IDMVMContext)) {
@ -580,6 +631,10 @@ public class RegisterVMNode extends AbstractExpressionVMNode
} }
} }
/*
* (non-Javadoc)
* @see org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.expression.AbstractExpressionVMNode#associateExpression(java.lang.Object, org.eclipse.debug.core.model.IExpression)
*/
@Override @Override
protected void associateExpression(Object element, IExpression expression) { protected void associateExpression(Object element, IExpression expression) {
if (element instanceof RegisterVMC) { if (element instanceof RegisterVMC) {
@ -587,6 +642,10 @@ public class RegisterVMNode extends AbstractExpressionVMNode
} }
} }
/*
* (non-Javadoc)
* @see org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.expression.IExpressionVMNode#getDeltaFlagsForExpression(org.eclipse.debug.core.model.IExpression, java.lang.Object)
*/
public int getDeltaFlagsForExpression(IExpression expression, Object event) { public int getDeltaFlagsForExpression(IExpression expression, Object event) {
if (event instanceof IRunControl.ISuspendedDMEvent) { if (event instanceof IRunControl.ISuspendedDMEvent) {
return IModelDelta.CONTENT; return IModelDelta.CONTENT;
@ -597,9 +656,17 @@ public class RegisterVMNode extends AbstractExpressionVMNode
return IModelDelta.CONTENT; return IModelDelta.CONTENT;
} }
if (event instanceof IMemory.IMemoryChangedEvent) {
return IModelDelta.CONTENT;
}
return IModelDelta.NO_CHANGE; return IModelDelta.NO_CHANGE;
} }
/*
* (non-Javadoc)
* @see org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.expression.IExpressionVMNode#buildDeltaForExpression(org.eclipse.debug.core.model.IExpression, int, java.lang.Object, org.eclipse.dd.dsf.ui.viewmodel.VMDelta, org.eclipse.jface.viewers.TreePath, org.eclipse.dd.dsf.concurrent.RequestMonitor)
*/
public void buildDeltaForExpression(IExpression expression, int elementIdx, Object event, VMDelta parentDelta, public void buildDeltaForExpression(IExpression expression, int elementIdx, Object event, VMDelta parentDelta,
TreePath path, RequestMonitor rm) TreePath path, RequestMonitor rm)
{ {
@ -607,9 +674,18 @@ public class RegisterVMNode extends AbstractExpressionVMNode
// Mark the parent delta indicating that elements were added and/or removed. // Mark the parent delta indicating that elements were added and/or removed.
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT); parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
} }
if (event instanceof IMemory.IMemoryChangedEvent) {
parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
}
rm.done(); rm.done();
} }
/*
* (non-Javadoc)
* @see org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.expression.IExpressionVMNode#buildDeltaForExpressionElement(java.lang.Object, int, java.lang.Object, org.eclipse.dd.dsf.ui.viewmodel.VMDelta, org.eclipse.dd.dsf.concurrent.RequestMonitor)
*/
public void buildDeltaForExpressionElement(Object element, int elementIdx, Object event, VMDelta parentDelta, final RequestMonitor rm) public void buildDeltaForExpressionElement(Object element, int elementIdx, Object event, VMDelta parentDelta, final RequestMonitor rm)
{ {
if (event instanceof IRegisters.IRegisterChangedDMEvent) { if (event instanceof IRegisters.IRegisterChangedDMEvent) {
@ -620,6 +696,10 @@ public class RegisterVMNode extends AbstractExpressionVMNode
parentDelta.addNode(element, IModelDelta.STATE); parentDelta.addNode(element, IModelDelta.STATE);
} }
if (event instanceof IMemory.IMemoryChangedEvent) {
parentDelta.addNode(element, IModelDelta.CONTENT);
}
if (event instanceof PropertyChangeEvent && if (event instanceof PropertyChangeEvent &&
((PropertyChangeEvent)event).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE) ((PropertyChangeEvent)event).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE)
{ {
@ -629,7 +709,10 @@ public class RegisterVMNode extends AbstractExpressionVMNode
rm.done(); rm.done();
} }
/*
* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementEditor#getCellEditor(org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext, java.lang.String, java.lang.Object, org.eclipse.swt.widgets.Composite)
*/
public CellEditor getCellEditor(IPresentationContext context, String columnId, Object element, Composite parent) { public CellEditor getCellEditor(IPresentationContext context, String columnId, Object element, Composite parent) {
if (IDebugVMConstants.COLUMN_ID__EXPRESSION.equals(columnId)) { if (IDebugVMConstants.COLUMN_ID__EXPRESSION.equals(columnId)) {
return new TextCellEditor(parent); return new TextCellEditor(parent);
@ -648,6 +731,10 @@ public class RegisterVMNode extends AbstractExpressionVMNode
return null; return null;
} }
/*
* (non-Javadoc)
* @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementEditor#getCellModifier(org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext, java.lang.Object)
*/
public ICellModifier getCellModifier(IPresentationContext context, Object element) { public ICellModifier getCellModifier(IPresentationContext context, Object element) {
return new RegisterCellModifier( return new RegisterCellModifier(
getDMVMProvider(), fFormattedPrefStore, fSyncRegisterDataAccess ); getDMVMProvider(), fFormattedPrefStore, fSyncRegisterDataAccess );

View file

@ -71,7 +71,7 @@ public class VariableVMNode extends AbstractExpressionVMNode
implements IElementEditor, IElementLabelProvider implements IElementEditor, IElementLabelProvider
{ {
private final static int MAX_STRING_VALUE_LENGTH = 40; //private final static int MAX_STRING_VALUE_LENGTH = 40;
public int getDeltaFlags(Object e) { public int getDeltaFlags(Object e) {
/* /*
@ -408,11 +408,9 @@ public class VariableVMNode extends AbstractExpressionVMNode
update.setFontData(JFaceResources.getFontDescriptor(IInternalDebugUIConstants.VARIABLE_TEXT_FONT).getFontData()[0], labelIndex); update.setFontData(JFaceResources.getFontDescriptor(IInternalDebugUIConstants.VARIABLE_TEXT_FONT).getFontData()[0], labelIndex);
// Color based on change history // Color based on change history
FormattedValueDMData oldData = (FormattedValueDMData) getDMVMProvider().getArchivedModelData( FormattedValueDMData oldData = (FormattedValueDMData) getDMVMProvider().getArchivedModelData(VariableVMNode.this, update, valueDmc);
VariableVMNode.this, update, valueDmc);
IExpressionDMData oldDMData = (IExpressionDMData) getDMVMProvider().getArchivedModelData( IExpressionDMData oldDMData = (IExpressionDMData) getDMVMProvider().getArchivedModelData(VariableVMNode.this, update, dmc);
VariableVMNode.this, update, dmc);
/* Commented out, to be replaced. See bug 225612. /* Commented out, to be replaced. See bug 225612.
String oldStringValue = oldDMData == null ? null : oldDMData.getStringValue();*/ String oldStringValue = oldDMData == null ? null : oldDMData.getStringValue();*/
@ -421,9 +419,7 @@ public class VariableVMNode extends AbstractExpressionVMNode
/* Commented out, to be replaced. See bug 225612. /* Commented out, to be replaced. See bug 225612.
|| (oldStringValue != null && !oldStringValue.equals(stringValue))) {*/ || (oldStringValue != null && !oldStringValue.equals(stringValue))) {*/
update.setBackground( update.setBackground(
DebugUIPlugin.getPreferenceColor( DebugUIPlugin.getPreferenceColor(IInternalDebugUIConstants.PREF_CHANGED_VALUE_BACKGROUND).getRGB(), labelIndex);
IInternalDebugUIConstants.PREF_CHANGED_VALUE_BACKGROUND).getRGB(),
labelIndex);
} }
update.done(); update.done();

View file

@ -183,7 +183,24 @@ abstract public class AbstractDMVMNode extends AbstractVMNode implements IVMNode
* @param dmc Data Model Context (DMC) to check. * @param dmc Data Model Context (DMC) to check.
* @param update Update to handle in case the DMC is null. * @param update Update to handle in case the DMC is null.
* @return true if the DMC is NOT null, indicating that it's OK to proceed. * @return true if the DMC is NOT null, indicating that it's OK to proceed.
*
* This method has been deprecated. Users should simply perform this functionality in-line
*
* Example :
*
* IExampleDmc dmc = final TimerDMContext dmc = findDmcInPath(...)
* if ( dmc == null ) {
* handleFailedUpdate(update);
* //
* // Perform whatever cleanup or completion is needed because of a lack of
* // a valid data model context.
* //
* ........
* return;
* }
*/ */
@Deprecated
protected boolean checkDmc(IDMContext dmc, IViewerUpdate update) { protected boolean checkDmc(IDMContext dmc, IViewerUpdate update) {
if (dmc == null) { if (dmc == null) {
update.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, update.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE,
@ -201,6 +218,20 @@ abstract public class AbstractDMVMNode extends AbstractVMNode implements IVMNode
* @param filter Service filter to use in addition to the service class name. * @param filter Service filter to use in addition to the service class name.
* @param update Update object to fill in. * @param update Update object to fill in.
* @return true if service IS found, indicating that it's OK to proceed. * @return true if service IS found, indicating that it's OK to proceed.
*
* This method has been deprecated. Users should simply perform this functionality in-line
*
* Example :
*
* IExampleService service = getServicesTracker().getService(IExampleService.class,null);
* if ( service == null ) {
* handleFailedUpdate(update);
* //
* // Perform whatever cleanup or completion is needed because of a lack of the service.
* //
* ........
* return;
* }
*/ */
@Deprecated @Deprecated
protected boolean checkService(Class<? extends IDsfService> serviceClass, String filter, IViewerUpdate update) { protected boolean checkService(Class<? extends IDsfService> serviceClass, String filter, IViewerUpdate update) {

View file

@ -0,0 +1,272 @@
/*******************************************************************************
* Copyright (c) 2006, 2008 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.examples.dsf.dataviewer;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor;
import org.eclipse.dd.dsf.concurrent.ThreadSafe;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.DsfExecutor;
import org.eclipse.dd.dsf.concurrent.ImmediateExecutor;
import org.eclipse.dd.dsf.concurrent.Query;
import org.eclipse.dd.dsf.ui.concurrent.DisplayDsfExecutor;
import org.eclipse.jface.viewers.ILazyContentProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
/**
* Data viewer based on a table, which reads data using asynchronous methods.
* <p>
* This viewer implements the {@link ILazyContentProvider} interface
* which is used by the JFace TableViewer class to populate a Table. This
* interface contains separate asynchronous methods for requesting the count
* and values for individual indexes, which neatly correspond to the methods
* in {@link IDataGenerator}. As an added optimization, this viewer
* implementation checks for the range of visible items in the view upon each
* request, and it cancels old requests which scroll out of view but have not
* been completed yet. However, it is up to the data generator implementation
* to check the canceled state of the requests and ignore them.
* </p>
*/
@ConfinedToDsfExecutor("fDisplayExecutor")
public class AsyncDataViewer
implements ILazyContentProvider, IDataGenerator.Listener
{
// Executor to use instead of Display.asyncExec().
@ThreadSafe
final private DsfExecutor fDisplayExecutor;
// The viewer and generator that this content provider using.
final private TableViewer fViewer;
final private IDataGenerator fDataGenerator;
// Fields used in request cancellation logic.
private List<ValueDataRequestMonitor> fItemDataRequestMonitors = new LinkedList<ValueDataRequestMonitor>();
private Set<Integer> fIndexesToCancel = new HashSet<Integer>();
private int fCancelCallsPending = 0;
public AsyncDataViewer(TableViewer viewer, IDataGenerator generator) {
fViewer = viewer;
fDisplayExecutor = DisplayDsfExecutor.getDisplayDsfExecutor(fViewer.getTable().getDisplay());
fDataGenerator = generator;
fDataGenerator.addListener(this);
}
public void dispose() {
fDataGenerator.removeListener(this);
}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
// Set the initial count to the viewer after the input is set.
queryItemCount();
}
public void updateElement(final int index) {
// Calculate the visible index range.
final int topIdx = fViewer.getTable().getTopIndex();
final int botIdx = topIdx + getVisibleItemCount(topIdx);
// Request the item for the given index.
queryValue(index);
// Invoke a cancel task with a delay. The delay allows multiple cancel
// calls to be combined together improving performance of the viewer.
fCancelCallsPending++;
fDisplayExecutor.schedule(
new Runnable() { public void run() {
cancelStaleRequests(topIdx, botIdx);
}},
1, TimeUnit.MILLISECONDS);
}
private int getVisibleItemCount(int top) {
Table table = fViewer.getTable();
int itemCount = table.getItemCount();
return Math.min((table.getBounds().height / table.getItemHeight()) + 2, itemCount - top);
}
@ThreadSafe
public void countChanged() {
queryItemCount();
}
@ThreadSafe
public void valuesChanged(final Set<Integer> indexes) {
// Mark the changed items in table viewer as dirty, this will
// trigger update requests for these indexes if they are
// visible in the viewer.
final TableViewer tableViewer = fViewer;
fDisplayExecutor.execute( new Runnable() {
public void run() {
if (!fViewer.getTable().isDisposed()) {
for (Integer index : indexes) {
tableViewer.clear(index);
}
}
}});
}
private void queryItemCount() {
// Request count from data provider. When the count is returned, we
// have to re-dispatch into the display thread to avoid calling
// the table widget on the DSF dispatch thread.
fIndexesToCancel.clear();
fDataGenerator.getCount(
// Use the display executor to construct the request monitor, this
// will cause the handleCompleted() method to be automatically
// called on the display thread.
new DataRequestMonitor<Integer>(fDisplayExecutor, null) {
@Override
protected void handleCompleted() {
if (!fViewer.getTable().isDisposed()) {
fViewer.setItemCount(getData());
fViewer.getTable().clearAll();
}
}
});
}
// Dedicated class for data item requests. This class holds the index
// argument so it can be examined when canceling stale requests.
private class ValueDataRequestMonitor extends DataRequestMonitor<String> {
/** Index is used when canceling stale requests. */
int fIndex;
ValueDataRequestMonitor(int index) {
super(fDisplayExecutor, null);
fIndex = index;
}
@Override
protected void handleCompleted() {
fItemDataRequestMonitors.remove(this);
// Check if the request completed successfully, otherwise ignore it.
if (isSuccess()) {
if (!fViewer.getTable().isDisposed()) {
fViewer.replace(getData(), fIndex);
}
}
}
}
private void queryValue(final int index) {
ValueDataRequestMonitor rm = new ValueDataRequestMonitor(index);
fItemDataRequestMonitors.add(rm);
fDataGenerator.getValue(index, rm);
}
private void cancelStaleRequests(int topIdx, int botIdx) {
// Decrement the count of outstanding cancel calls.
fCancelCallsPending--;
// Must check again, in case disposed while re-dispatching.
if (fDataGenerator == null || fViewer.getTable().isDisposed()) return;
// Go through the outstanding requests and cancel any that
// are not visible anymore.
for (Iterator<ValueDataRequestMonitor> itr = fItemDataRequestMonitors.iterator(); itr.hasNext();) {
ValueDataRequestMonitor item = itr.next();
if (item.fIndex < topIdx || item.fIndex > botIdx) {
// Set the item to canceled status, so that the data provider
// will ignore it.
item.cancel();
// Add the item index to list of indexes that were canceled,
// which will be sent to the table widget.
fIndexesToCancel.add(item.fIndex);
// Remove the item from the outstanding cancel requests.
itr.remove();
}
}
if (!fIndexesToCancel.isEmpty() && fCancelCallsPending == 0) {
Set<Integer> canceledIdxs = fIndexesToCancel;
fIndexesToCancel = new HashSet<Integer>();
// Clear the indexes of the canceled request, so that the
// viewer knows to request them again when needed.
// Note: clearing using TableViewer.clear(int) seems very
// inefficient, it's better to use Table.clear(int[]).
int[] canceledIdxsArray = new int[canceledIdxs.size()];
int i = 0;
for (Integer index : canceledIdxs) {
canceledIdxsArray[i++] = index;
}
fViewer.getTable().clear(canceledIdxsArray);
}
}
public static void main(String[] args) {
// Create the shell to hold the viewer.
Display display = new Display();
Shell shell = new Shell(display, SWT.SHELL_TRIM);
shell.setLayout(new GridLayout());
GridData data = new GridData(GridData.FILL_BOTH);
shell.setLayoutData(data);
Font font = new Font(display, "Courier", 10, SWT.NORMAL);
// Create the table viewer.
TableViewer tableViewer = new TableViewer(shell, SWT.BORDER | SWT.VIRTUAL);
tableViewer.getControl().setLayoutData(data);
// Create the data generator.
final IDataGenerator generator = new DataGeneratorWithExecutor();
// Create the content provider which will populate the viewer.
AsyncDataViewer contentProvider = new AsyncDataViewer(tableViewer, generator);
tableViewer.setContentProvider(contentProvider);
tableViewer.setInput(new Object());
// Open the shell and service the display dispatch loop until user
// closes the shell.
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
// The IDataGenerator.shutdown() method is asynchronous, this requires
// using a query again in order to wait for its completion.
Query<Object> shutdownQuery = new Query<Object>() {
@Override
protected void execute(DataRequestMonitor<Object> rm) {
generator.shutdown(rm);
}
};
ImmediateExecutor.getInstance().execute(shutdownQuery);
try {
shutdownQuery.get();
} catch (Exception e) {}
// Shut down the display.
font.dispose();
display.dispose();
}
}

View file

@ -0,0 +1,336 @@
/*******************************************************************************
* 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.examples.dsf.dataviewer;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.DefaultDsfExecutor;
import org.eclipse.dd.dsf.concurrent.DsfExecutor;
import org.eclipse.dd.dsf.concurrent.DsfRunnable;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
import org.eclipse.dd.examples.dsf.DsfExamplesPlugin;
/**
* DSF Executor-based implementation of the data generator.
* <p>
* This generator uses a queue of client requests and processes these
* requests periodically using a DSF executor. The main feature of this
* generator is that it uses the executor as its only synchronization object.
* This means that all the fields with the exception of the executor can only
* be accessed while running in the executor thread.
* </p>
*/
//TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
//indicating allowed thread access to this class/method/member
public class DataGeneratorWithExecutor implements IDataGenerator {
// Request objects are used to serialize the interface calls into objects
// which can then be pushed into a queue.
// TODO Ecercise 4 - Add an annotationindicating allowed concurrency access
// Hint: Request and its subclasses have all their fields declared as final.
abstract class Request {
final RequestMonitor fRequestMonitor;
Request(RequestMonitor rm) {
fRequestMonitor = rm;
}
}
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
// indicating allowed thread access to this class/method/member
class CountRequest extends Request {
CountRequest(DataRequestMonitor<Integer> rm) {
super(rm);
}
}
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
// indicating allowed thread access to this class/method/member
class ItemRequest extends Request {
final int fIndex;
ItemRequest(int index, DataRequestMonitor<String> rm) {
super(rm);
fIndex = index;
}
}
// The executor used to access all internal data of the generator.
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
// indicating allowed thread access to this class/method/member
// Hint: If a member does not have an annotation, the programmer can assume
// that the concurrency rule that applies to the class also applies to this
// member.
private DsfExecutor fExecutor;
// Main request queue of the data generator. The getValue(), getCount(),
// and shutdown() methods write into the queue, while the serviceQueue()
// method reads from it.
// The executor used to access all internal data of the generator.
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
// indicating allowed thread access to this class/method/member
private List<Request> fQueue = new LinkedList<Request>();
// List of listeners is not synchronized, it also has to be accessed
// using the executor.
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
// indicating allowed thread access to this class/method/member
private List<Listener> fListeners = new LinkedList<Listener>();
// Current number of elements in this generator.
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
// indicating allowed thread access to this class/method/member
private int fCount = MIN_COUNT;
// Counter used to determine when to reset the element count.
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
// indicating allowed thread access to this class/method/member
private int fCountResetTrigger = 0;
// Elements which were modified since the last reset.
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
// indicating allowed thread access to this class/method/member
private Set<Integer> fChangedIndexes = new HashSet<Integer>();
// Flag used to ensure that requests are processed sequentially.
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
// indicating allowed thread access to this class/method/member
private boolean fServiceQueueInProgress = false;
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
// indicating allowed thread access to this class/method/member
public DataGeneratorWithExecutor() {
// Create the executor
fExecutor = new DefaultDsfExecutor("Supplier Executor");
// Schedule a runnable to make the random changes.
fExecutor.scheduleAtFixedRate(
new DsfRunnable() {
public void run() {
randomChanges();
}
},
RANDOM_CHANGE_INTERVAL,
RANDOM_CHANGE_INTERVAL,
TimeUnit.MILLISECONDS);
}
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
// indicating allowed thread access to this class/method/member
public void shutdown(final RequestMonitor rm) {
try {
fExecutor.execute( new DsfRunnable() {
public void run() {
// Empty the queue of requests and fail them.
for (Request request : fQueue) {
request.fRequestMonitor.setStatus(
new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
request.fRequestMonitor.done();
}
fQueue.clear();
// Kill executor.
fExecutor.shutdown();
rm.done();
}
});
} catch (RejectedExecutionException e) {
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
rm.done();
}
}
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
// indicating allowed thread access to this class/method/member
public void getCount(final DataRequestMonitor<Integer> rm) {
try {
fExecutor.execute( new DsfRunnable() {
public void run() {
fQueue.add(new CountRequest(rm));
serviceQueue();
}
});
} catch (RejectedExecutionException e) {
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
rm.done();
}
}
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
// indicating allowed thread access to this class/method/member
public void getValue(final int index, final DataRequestMonitor<String> rm) {
try {
fExecutor.execute( new DsfRunnable() {
public void run() {
fQueue.add(new ItemRequest(index, rm));
serviceQueue();
}
});
} catch (RejectedExecutionException e) {
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
rm.done();
}
}
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
// indicating allowed thread access to this class/method/member
public void addListener(final Listener listener) {
try {
fExecutor.execute( new DsfRunnable() {
public void run() {
fListeners.add(listener);
}
});
} catch (RejectedExecutionException e) {}
}
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
// indicating allowed thread access to this class/method/member
public void removeListener(final Listener listener) {
try {
fExecutor.execute( new DsfRunnable() {
public void run() {
fListeners.remove(listener);
}
});
} catch (RejectedExecutionException e) {}
}
// Main processing function of this generator.
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
// indicating allowed thread access to this class/method/member
private void serviceQueue() {
// TODO Exercise 3 - Add logic to discard cancelled requests from queue.
// Hint: Since serviceQueue() is called using the executor, and the
// fQueue list can only be modified when running in the executor
// thread. This method can safely iterate and modify fQueue without
// risk of race conditions or concurrent modification exceptions.
// If a queue servicing is already scheduled, do nothing.
if (fServiceQueueInProgress) {
return;
}
if (fQueue.size() != 0) {
// If there are requests to service, remove one from the queue and
// schedule a runnable to process the request after a processing
// delay.
fServiceQueueInProgress = true;
final Request request = fQueue.remove(0);
fExecutor.schedule(
new DsfRunnable() {
public void run() {
if (request instanceof CountRequest) {
processCountRequest((CountRequest)request);
} else if (request instanceof ItemRequest) {
processItemRequest((ItemRequest)request);
}
// Reset the processing flag and process next
// request.
fServiceQueueInProgress = false;
serviceQueue();
}
},
PROCESSING_DELAY, TimeUnit.MILLISECONDS);
}
}
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
// indicating allowed thread access to this class/method/member
private void processCountRequest(CountRequest request) {
@SuppressWarnings("unchecked") // Suppress warning about lost type info.
DataRequestMonitor<Integer> rm = (DataRequestMonitor<Integer>)request.fRequestMonitor;
rm.setData(fCount);
rm.done();
}
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
// indicating allowed thread access to this class/method/member
private void processItemRequest(ItemRequest request) {
@SuppressWarnings("unchecked") // Suppress warning about lost type info.
DataRequestMonitor<String> rm = (DataRequestMonitor<String>)request.fRequestMonitor;
if (fChangedIndexes.contains(request.fIndex)) {
rm.setData("Changed: " + request.fIndex);
} else {
rm.setData(Integer.toString(request.fIndex));
}
rm.done();
}
/**
* This method simulates changes in the supplier's data set.
*/
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
// indicating allowed thread access to this class/method/member
private void randomChanges() {
// Once every number of changes, reset the count, the rest of the
// times just change certain values.
if (++fCountResetTrigger % RANDOM_COUNT_CHANGE_INTERVALS == 0){
randomCountReset();
} else {
randomDataChange();
}
}
/**
* Calculates new size for provider's data set.
*/
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
// indicating allowed thread access to this class/method/member
private void randomCountReset() {
// Calculate the new count.
Random random = new java.util.Random();
fCount = MIN_COUNT + Math.abs(random.nextInt()) % (MAX_COUNT - MIN_COUNT);
// Reset the changed values.
fChangedIndexes.clear();
// Notify listeners
for (Listener listener : fListeners) {
listener.countChanged();
}
}
/**
* Invalidates a random range of indexes.
*/
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
// indicating allowed thread access to this class/method/member
private void randomDataChange() {
// Calculate the indexes to change.
Random random = new java.util.Random();
Set<Integer> set = new HashSet<Integer>();
for (int i = 0; i < fCount * RANDOM_CHANGE_SET_PERCENTAGE / 100; i++) {
set.add( new Integer(Math.abs(random.nextInt()) % fCount) );
}
// Add the indexes to an overall set of changed indexes.
fChangedIndexes.addAll(set);
// Notify listeners
for (Listener listener : fListeners) {
listener.valuesChanged(set);
}
}
}

View file

@ -0,0 +1,238 @@
/*******************************************************************************
* Copyright (c) 2006, 2008 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.examples.dsf.dataviewer;
import java.util.Collections;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.core.runtime.Status;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
import org.eclipse.dd.examples.dsf.DsfExamplesPlugin;
/**
* Thread-based implementation of the data generator.
* <p>
* This generator is based around a queue of client requests and a thread which
* reads the requests from the queue and processes them. The distinguishing
* feature of this generator is that it uses a a blocking queue as the main
* synchronization object. However, fListeners, fShutdown, and fChangedIndexes
* fields also need to be thread-safe and so they implement their own
* synchronization.
* </p>
*/
public class DataGeneratorWithThread extends Thread implements IDataGenerator {
// Request objects are used to serialize the interface calls into objects
// which can then be pushed into a queue.
abstract class Request {
final RequestMonitor fRequestMonitor;
Request(RequestMonitor rm) {
fRequestMonitor = rm;
}
}
class CountRequest extends Request {
CountRequest(DataRequestMonitor<Integer> rm) {
super(rm);
}
}
class ItemRequest extends Request {
final int fIndex;
ItemRequest(int index, DataRequestMonitor<String> rm) {
super(rm);
fIndex = index;
}
}
class ShutdownRequest extends Request {
ShutdownRequest(RequestMonitor rm) {
super(rm);
}
}
// Main request queue of the data generator. The getValue(), getCount(),
// and shutdown() methods write into the queue, while the run() method
// reads from it.
private final BlockingQueue<Request> fQueue = new LinkedBlockingQueue<Request>();
// ListenerList class provides thread safety.
private ListenerList fListeners = new ListenerList();
// Current number of elements in this generator.
private int fCount = MIN_COUNT;
// Counter used to determine when to reset the element count.
private int fCountResetTrigger = 0;
// Elements which were modified since the last reset.
private Set<Integer> fChangedIndexes = Collections.synchronizedSet(new HashSet<Integer>());
// Used to determine when to make changes in data.
private long fLastChangeTime = System.currentTimeMillis();
// Flag indicating when the generator has been shut down.
private AtomicBoolean fShutdown = new AtomicBoolean(false);
public DataGeneratorWithThread() {
// Immediately kick off the request processing thread.
start();
}
public void shutdown(RequestMonitor rm) {
// Mark the generator as shut down. After the fShutdown flag is set,
// all new requests should be shut down.
if (!fShutdown.getAndSet(true)) {
fQueue.add(new ShutdownRequest(rm));
} else {
//
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
rm.done();
}
}
public void getCount(DataRequestMonitor<Integer> rm) {
if (!fShutdown.get()) {
fQueue.add(new CountRequest(rm));
} else {
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
rm.done();
}
}
public void getValue(int index, DataRequestMonitor<String> rm) {
if (!fShutdown.get()) {
fQueue.add(new ItemRequest(index, rm));
} else {
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
rm.done();
}
}
public void addListener(Listener listener) {
fListeners.add(listener);
}
public void removeListener(Listener listener) {
fListeners.remove(listener);
}
@Override
public void run() {
try {
while(true) {
// Get the next request from the queue. The time-out
// ensures that that the random changes get processed.
final Request request = fQueue.poll(100, TimeUnit.MILLISECONDS);
// If a request was dequeued, process it.
if (request != null) {
// Simulate a processing delay.
Thread.sleep(PROCESSING_DELAY);
if (request instanceof CountRequest) {
processCountRequest((CountRequest)request);
} else if (request instanceof ItemRequest) {
processItemRequest((ItemRequest)request);
} else if (request instanceof ShutdownRequest) {
// If shutting down, just break out of the while(true)
// loop and thread will exit.
request.fRequestMonitor.done();
break;
}
}
// Simulate data changes.
randomChanges();
}
}
catch (InterruptedException x) {}
}
private void processCountRequest(CountRequest request) {
@SuppressWarnings("unchecked") // Suppress warning about lost type info.
DataRequestMonitor<Integer> rm = (DataRequestMonitor<Integer>)request.fRequestMonitor;
rm.setData(fCount);
rm.done();
}
private void processItemRequest(ItemRequest request) {
@SuppressWarnings("unchecked") // Suppress warning about lost type info.
DataRequestMonitor<String> rm = (DataRequestMonitor<String>)request.fRequestMonitor;
if (fChangedIndexes.contains(request.fIndex)) {
rm.setData("Changed: " + request.fIndex);
} else {
rm.setData(Integer.toString(request.fIndex));
}
rm.done();
}
private void randomChanges() {
// Check if enough time is elapsed.
if (System.currentTimeMillis() > fLastChangeTime + RANDOM_CHANGE_INTERVAL) {
fLastChangeTime = System.currentTimeMillis();
// Once every number of changes, reset the count, the rest of the
// times just change certain values.
if (++fCountResetTrigger % RANDOM_COUNT_CHANGE_INTERVALS == 0){
randomCountReset();
} else {
randomDataChange();
}
}
}
private void randomCountReset() {
// Calculate the new count.
Random random = new java.util.Random();
fCount = MIN_COUNT + Math.abs(random.nextInt()) % (MAX_COUNT - MIN_COUNT);
// Reset the changed values.
fChangedIndexes.clear();
// Notify listeners
for (Object listener : fListeners.getListeners()) {
((Listener)listener).countChanged();
}
}
private void randomDataChange() {
// Calculate the indexes to change.
Random random = new java.util.Random();
Set<Integer> set = new HashSet<Integer>();
for (int i = 0; i < fCount * RANDOM_CHANGE_SET_PERCENTAGE / 100; i++) {
set.add( new Integer(Math.abs(random.nextInt()) % fCount) );
}
// Add the indexes to an overall set of changed indexes.
fChangedIndexes.addAll(set);
// Notify listeners
for (Object listener : fListeners.getListeners()) {
((Listener)listener).valuesChanged(set);
}
}
}

View file

@ -0,0 +1,59 @@
/*******************************************************************************
* Copyright (c) 2006, 2008 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.examples.dsf.dataviewer;
import java.util.Set;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
/**
* Data generator is simple source of data used to populate the example table
* view. It contains two asynchronous methods for retrieving the data
* parameters: the count and the value for a given index. It also allows the
* view to receive events indicating when the data supplied by the generator
* is changed.
*/
// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
// indicating allowed thread access to this class/method/member
public interface IDataGenerator {
// Constants which control the data generator behavior.
// Changing the count range can stress the scalability of the system, while
// changing of the process delay and random change interval can stress
// its performance.
final static int MIN_COUNT = 100;
final static int MAX_COUNT = 200;
final static int PROCESSING_DELAY = 10;
final static int RANDOM_CHANGE_INTERVAL = 10000;
final static int RANDOM_COUNT_CHANGE_INTERVALS = 3;
final static int RANDOM_CHANGE_SET_PERCENTAGE = 10;
// Listener interface that the view needs to implement to react
// to the changes in data.
public interface Listener {
void countChanged();
void valuesChanged(Set<Integer> indexes);
}
// Data access methods.
void getCount(DataRequestMonitor<Integer> rm);
void getValue(int index, DataRequestMonitor<String> rm);
// Method used to shutdown the data generator including any threads that
// it may use.
void shutdown(RequestMonitor rm);
// Methods for registering change listeners.
void addListener(Listener listener);
void removeListener(Listener listener);
}

View file

@ -0,0 +1,183 @@
/*******************************************************************************
* Copyright (c) 2008 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.examples.dsf.dataviewer;
import java.util.Set;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.ImmediateExecutor;
import org.eclipse.dd.dsf.concurrent.Query;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
/**
* Data viewer based on a table, which reads data using synchronous methods.
* <p>
* This viewer implements the {@link IStructuredContentProvider} interface
* which is used by the JFace TableViewer class to populate a Table. This
* interface contains one principal methods for reading data {@link #getElements(Object)},
* which synchronously returns an array of elements. In order to implement this
* method using the asynchronous data generator, this provider uses the
* {@link Query} object.
* </p>
*/
public class SyncDataViewer
implements IStructuredContentProvider, IDataGenerator.Listener
{
// The viewer and generator that this content provider using.
final private TableViewer fViewer;
final private IDataGenerator fDataGenerator;
public SyncDataViewer(TableViewer viewer, IDataGenerator generator) {
fViewer = viewer;
fDataGenerator = generator;
fDataGenerator.addListener(this);
}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
// Not used
}
public Object[] getElements(Object inputElement) {
// Create the query object for reading data count.
Query<Integer> countQuery = new Query<Integer>() {
@Override
protected void execute(DataRequestMonitor<Integer> rm) {
fDataGenerator.getCount(rm);
}
};
// Submit the query to be executed. A query implements a runnable
// interface and it has to be executed in order to do its work.
ImmediateExecutor.getInstance().execute(countQuery);
int count = 0;
// Block until the query completes, which will happen when the request
// monitor of the execute() method is marked done.
try {
count = countQuery.get();
} catch (Exception e) {
// InterruptedException and ExecutionException can be thrown here.
// ExecutionException containing a CoreException will be thrown
// if an error status is set to the Query's request monitor.
return new Object[0];
}
// Create the array that will be filled with elements.
// For each index in the array execute a query to get the element at
// that index.
final Object[] elements = new Object[count];
for (int i = 0; i < count; i++) {
final int index = i;
Query<String> valueQuery = new Query<String>() {
@Override
protected void execute(DataRequestMonitor<String> rm) {
fDataGenerator.getValue(index, rm);
}
};
ImmediateExecutor.getInstance().execute(valueQuery);
try {
elements[i] = valueQuery.get();
} catch (Exception e) {
elements[i] = "error";
}
}
return elements;
}
public void dispose() {
fDataGenerator.removeListener(this);
}
public void countChanged() {
// For any event from the generator, refresh the whole viewer.
refreshViewer();
}
public void valuesChanged(Set<Integer> indexes) {
// For any event from the generator, refresh the whole viewer.
refreshViewer();
}
private void refreshViewer() {
// TODO Exercise 5 - Add a call to getElements() to force a deadlock.
// This method may be called on any thread, switch to the display
// thread before calling the viewer.
Display display = fViewer.getControl().getDisplay();
display.asyncExec( new Runnable() {
public void run() {
if (!fViewer.getControl().isDisposed()) {
fViewer.refresh();
}
}
});
}
public static void main(String[] args) {
// Create the shell to hold the viewer.
Display display = new Display();
Shell shell = new Shell(display, SWT.SHELL_TRIM);
shell.setLayout(new GridLayout());
GridData data = new GridData(GridData.FILL_BOTH);
shell.setLayoutData(data);
Font font = new Font(display, "Courier", 10, SWT.NORMAL);
// Create the table viewer.
TableViewer tableViewer = new TableViewer(shell, SWT.BORDER);
tableViewer.getControl().setLayoutData(data);
// Create the data generator.
// TODO Exercise 5 - Use the DataGeneratorWithExecutor() instead.
final IDataGenerator generator = new DataGeneratorWithThread();
// Create the content provider which will populate the viewer.
SyncDataViewer contentProvider = new SyncDataViewer(tableViewer, generator);
tableViewer.setContentProvider(contentProvider);
tableViewer.setInput(new Object());
// Open the shell and service the display dispatch loop until user
// closes the shell.
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
// The IDataGenerator.shutdown() method is asynchronous, this requires
// using a query again in order to wait for its completion.
Query<Object> shutdownQuery = new Query<Object>() {
@Override
protected void execute(DataRequestMonitor<Object> rm) {
generator.shutdown(rm);
}
};
ImmediateExecutor.getInstance().execute(shutdownQuery);
try {
shutdownQuery.get();
} catch (Exception e) {}
// Shut down the display.
font.dispose();
display.dispose();
}
}

View file

@ -0,0 +1,272 @@
/*******************************************************************************
* Copyright (c) 2006, 2008 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.examples.dsf.dataviewer.answers;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor;
import org.eclipse.dd.dsf.concurrent.ThreadSafe;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.DsfExecutor;
import org.eclipse.dd.dsf.concurrent.ImmediateExecutor;
import org.eclipse.dd.dsf.concurrent.Query;
import org.eclipse.dd.dsf.ui.concurrent.DisplayDsfExecutor;
import org.eclipse.jface.viewers.ILazyContentProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
/**
* Data viewer based on a table, which reads data using asynchronous methods.
* <p>
* This viewer implements the {@link ILazyContentProvider} interface
* which is used by the JFace TableViewer class to populate a Table. This
* interface contains separate asynchronous methods for requesting the count
* and values for individual indexes, which neatly correspond to the methods
* in {@link IDataGenerator}. As an added optimization, this viewer
* implementation checks for the range of visible items in the view upon each
* request, and it cancels old requests which scroll out of view but have not
* been completed yet. However, it is up to the data generator implementation
* to check the canceled state of the requests and ignore them.
* </p>
*/
@ConfinedToDsfExecutor("fDisplayExecutor")
public class AsyncDataViewer
implements ILazyContentProvider, IDataGenerator.Listener
{
// Executor to use instead of Display.asyncExec().
@ThreadSafe
final private DsfExecutor fDisplayExecutor;
// The viewer and generator that this content provider using.
final private TableViewer fViewer;
final private IDataGenerator fDataGenerator;
// Fields used in request cancellation logic.
private List<ValueDataRequestMonitor> fItemDataRequestMonitors = new LinkedList<ValueDataRequestMonitor>();
private Set<Integer> fIndexesToCancel = new HashSet<Integer>();
private int fCancelCallsPending = 0;
public AsyncDataViewer(TableViewer viewer, IDataGenerator generator) {
fViewer = viewer;
fDisplayExecutor = DisplayDsfExecutor.getDisplayDsfExecutor(fViewer.getTable().getDisplay());
fDataGenerator = generator;
fDataGenerator.addListener(this);
}
public void dispose() {
fDataGenerator.removeListener(this);
}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
// Set the initial count to the viewer after the input is set.
queryItemCount();
}
public void updateElement(final int index) {
// Calculate the visible index range.
final int topIdx = fViewer.getTable().getTopIndex();
final int botIdx = topIdx + getVisibleItemCount(topIdx);
// Request the item for the given index.
queryValue(index);
// Invoke a cancel task with a delay. The delay allows multiple cancel
// calls to be combined together improving performance of the viewer.
fCancelCallsPending++;
fDisplayExecutor.schedule(
new Runnable() { public void run() {
cancelStaleRequests(topIdx, botIdx);
}},
1, TimeUnit.MILLISECONDS);
}
private int getVisibleItemCount(int top) {
Table table = fViewer.getTable();
int itemCount = table.getItemCount();
return Math.min((table.getBounds().height / table.getItemHeight()) + 2, itemCount - top);
}
@ThreadSafe
public void countChanged() {
queryItemCount();
}
@ThreadSafe
public void valuesChanged(final Set<Integer> indexes) {
// Mark the changed items in table viewer as dirty, this will
// trigger update requests for these indexes if they are
// visible in the viewer.
final TableViewer tableViewer = fViewer;
fDisplayExecutor.execute( new Runnable() {
public void run() {
if (!fViewer.getTable().isDisposed()) {
for (Integer index : indexes) {
tableViewer.clear(index);
}
}
}});
}
private void queryItemCount() {
// Request count from data provider. When the count is returned, we
// have to re-dispatch into the display thread to avoid calling
// the table widget on the DSF dispatch thread.
fIndexesToCancel.clear();
fDataGenerator.getCount(
// Use the display executor to construct the request monitor, this
// will cause the handleCompleted() method to be automatically
// called on the display thread.
new DataRequestMonitor<Integer>(fDisplayExecutor, null) {
@Override
protected void handleCompleted() {
if (!fViewer.getTable().isDisposed()) {
fViewer.setItemCount(getData());
fViewer.getTable().clearAll();
}
}
});
}
// Dedicated class for data item requests. This class holds the index
// argument so it can be examined when canceling stale requests.
private class ValueDataRequestMonitor extends DataRequestMonitor<String> {
/** Index is used when canceling stale requests. */
int fIndex;
ValueDataRequestMonitor(int index) {
super(fDisplayExecutor, null);
fIndex = index;
}
@Override
protected void handleCompleted() {
fItemDataRequestMonitors.remove(this);
// Check if the request completed successfully, otherwise ignore it.
if (isSuccess()) {
if (!fViewer.getTable().isDisposed()) {
fViewer.replace(getData(), fIndex);
}
}
}
}
private void queryValue(final int index) {
ValueDataRequestMonitor rm = new ValueDataRequestMonitor(index);
fItemDataRequestMonitors.add(rm);
fDataGenerator.getValue(index, rm);
}
private void cancelStaleRequests(int topIdx, int botIdx) {
// Decrement the count of outstanding cancel calls.
fCancelCallsPending--;
// Must check again, in case disposed while re-dispatching.
if (fDataGenerator == null || fViewer.getTable().isDisposed()) return;
// Go through the outstanding requests and cancel any that
// are not visible anymore.
for (Iterator<ValueDataRequestMonitor> itr = fItemDataRequestMonitors.iterator(); itr.hasNext();) {
ValueDataRequestMonitor item = itr.next();
if (item.fIndex < topIdx || item.fIndex > botIdx) {
// Set the item to canceled status, so that the data provider
// will ignore it.
item.cancel();
// Add the item index to list of indexes that were canceled,
// which will be sent to the table widget.
fIndexesToCancel.add(item.fIndex);
// Remove the item from the outstanding cancel requests.
itr.remove();
}
}
if (!fIndexesToCancel.isEmpty() && fCancelCallsPending == 0) {
Set<Integer> canceledIdxs = fIndexesToCancel;
fIndexesToCancel = new HashSet<Integer>();
// Clear the indexes of the canceled request, so that the
// viewer knows to request them again when needed.
// Note: clearing using TableViewer.clear(int) seems very
// inefficient, it's better to use Table.clear(int[]).
int[] canceledIdxsArray = new int[canceledIdxs.size()];
int i = 0;
for (Integer index : canceledIdxs) {
canceledIdxsArray[i++] = index;
}
fViewer.getTable().clear(canceledIdxsArray);
}
}
public static void main(String[] args) {
// Create the shell to hold the viewer.
Display display = new Display();
Shell shell = new Shell(display, SWT.SHELL_TRIM);
shell.setLayout(new GridLayout());
GridData data = new GridData(GridData.FILL_BOTH);
shell.setLayoutData(data);
Font font = new Font(display, "Courier", 10, SWT.NORMAL);
// Create the table viewer.
TableViewer tableViewer = new TableViewer(shell, SWT.BORDER | SWT.VIRTUAL);
tableViewer.getControl().setLayoutData(data);
// Create the data generator.
final IDataGenerator generator = new DataGeneratorWithExecutor();
// Create the content provider which will populate the viewer.
AsyncDataViewer contentProvider = new AsyncDataViewer(tableViewer, generator);
tableViewer.setContentProvider(contentProvider);
tableViewer.setInput(new Object());
// Open the shell and service the display dispatch loop until user
// closes the shell.
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
// The IDataGenerator.shutdown() method is asynchronous, this requires
// using a query again in order to wait for its completion.
Query<Object> shutdownQuery = new Query<Object>() {
@Override
protected void execute(DataRequestMonitor<Object> rm) {
generator.shutdown(rm);
}
};
ImmediateExecutor.getInstance().execute(shutdownQuery);
try {
shutdownQuery.get();
} catch (Exception e) {}
// Shut down the display.
font.dispose();
display.dispose();
}
}

View file

@ -0,0 +1,311 @@
/*******************************************************************************
* 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.examples.dsf.dataviewer.answers;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor;
import org.eclipse.dd.dsf.concurrent.Immutable;
import org.eclipse.dd.dsf.concurrent.ThreadSafe;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.DefaultDsfExecutor;
import org.eclipse.dd.dsf.concurrent.DsfExecutor;
import org.eclipse.dd.dsf.concurrent.DsfRunnable;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
import org.eclipse.dd.examples.dsf.DsfExamplesPlugin;
/**
* DSF Executor-based implementation of the data generator.
* <p>
* This generator uses a queue of client requests and processes these
* requests periodically using a DSF executor. The main feature of this
* generator is that it uses the executor as its only synchronization object.
* This means that all the fields with the exception of the executor can only
* be accessed while running in the executor thread.
* </p>
*/
@ThreadSafe
public class DataGeneratorWithExecutor implements IDataGenerator {
// Request objects are used to serialize the interface calls into objects
// which can then be pushed into a queue.
@Immutable
abstract class Request {
final RequestMonitor fRequestMonitor;
Request(RequestMonitor rm) {
fRequestMonitor = rm;
}
}
@Immutable
class CountRequest extends Request {
CountRequest(DataRequestMonitor<Integer> rm) {
super(rm);
}
}
@Immutable
class ItemRequest extends Request {
final int fIndex;
ItemRequest(int index, DataRequestMonitor<String> rm) {
super(rm);
fIndex = index;
}
}
// The executor used to access all internal data of the generator.
private DsfExecutor fExecutor;
// Main request queue of the data generator. The getValue(), getCount(),
// and shutdown() methods write into the queue, while the serviceQueue()
// method reads from it.
// The executor used to access all internal data of the generator.
@ConfinedToDsfExecutor("fExecutor")
private List<Request> fQueue = new LinkedList<Request>();
// List of listeners is not synchronized, it also has to be accessed
// using the executor.
@ConfinedToDsfExecutor("fExecutor")
private List<Listener> fListeners = new LinkedList<Listener>();
// Current number of elements in this generator.
@ConfinedToDsfExecutor("fExecutor")
private int fCount = MIN_COUNT;
// Counter used to determine when to reset the element count.
@ConfinedToDsfExecutor("fExecutor")
private int fCountResetTrigger = 0;
// Elements which were modified since the last reset.
@ConfinedToDsfExecutor("fExecutor")
private Set<Integer> fChangedIndexes = new HashSet<Integer>();
// Flag used to ensure that requests are processed sequentially.
@ConfinedToDsfExecutor("fExecutor")
private boolean fServiceQueueInProgress = false;
public DataGeneratorWithExecutor() {
// Create the executor
fExecutor = new DefaultDsfExecutor("Supplier Executor");
// Schedule a runnable to make the random changes.
fExecutor.scheduleAtFixedRate(
new DsfRunnable() {
public void run() {
randomChanges();
}
},
RANDOM_CHANGE_INTERVAL,
RANDOM_CHANGE_INTERVAL,
TimeUnit.MILLISECONDS);
}
public void shutdown(final RequestMonitor rm) {
try {
fExecutor.execute( new DsfRunnable() {
public void run() {
// Empty the queue of requests and fail them.
for (Request request : fQueue) {
request.fRequestMonitor.setStatus(
new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
request.fRequestMonitor.done();
}
fQueue.clear();
// Kill executor.
fExecutor.shutdown();
rm.done();
}
});
} catch (RejectedExecutionException e) {
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
rm.done();
}
}
public void getCount(final DataRequestMonitor<Integer> rm) {
try {
fExecutor.execute( new DsfRunnable() {
public void run() {
fQueue.add(new CountRequest(rm));
serviceQueue();
}
});
} catch (RejectedExecutionException e) {
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
rm.done();
}
}
public void getValue(final int index, final DataRequestMonitor<String> rm) {
try {
fExecutor.execute( new DsfRunnable() {
public void run() {
fQueue.add(new ItemRequest(index, rm));
serviceQueue();
}
});
} catch (RejectedExecutionException e) {
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
rm.done();
}
}
public void addListener(final Listener listener) {
try {
fExecutor.execute( new DsfRunnable() {
public void run() {
fListeners.add(listener);
}
});
} catch (RejectedExecutionException e) {}
}
public void removeListener(final Listener listener) {
try {
fExecutor.execute( new DsfRunnable() {
public void run() {
fListeners.remove(listener);
}
});
} catch (RejectedExecutionException e) {}
}
// Main processing function of this generator.
@ConfinedToDsfExecutor("fExecutor")
private void serviceQueue() {
for (Iterator<Request> requestItr = fQueue.iterator(); requestItr.hasNext();) {
Request request = requestItr.next();
if (request.fRequestMonitor.isCanceled()) {
request.fRequestMonitor.setStatus(
new Status(IStatus.CANCEL, DsfExamplesPlugin.PLUGIN_ID, "Request canceled"));
request.fRequestMonitor.done();
requestItr.remove();
}
}
// If a queue servicing is already scheduled, do nothing.
if (fServiceQueueInProgress) {
return;
}
if (fQueue.size() != 0) {
// If there are requests to service, remove one from the queue and
// schedule a runnable to process the request after a processing
// delay.
fServiceQueueInProgress = true;
final Request request = fQueue.remove(0);
fExecutor.schedule(
new DsfRunnable() {
public void run() {
if (request instanceof CountRequest) {
processCountRequest((CountRequest)request);
} else if (request instanceof ItemRequest) {
processItemRequest((ItemRequest)request);
}
// Reset the processing flag and process next
// request.
fServiceQueueInProgress = false;
serviceQueue();
}
},
PROCESSING_DELAY, TimeUnit.MILLISECONDS);
}
}
@ConfinedToDsfExecutor("fExecutor")
private void processCountRequest(CountRequest request) {
@SuppressWarnings("unchecked") // Suppress warning about lost type info.
DataRequestMonitor<Integer> rm = (DataRequestMonitor<Integer>)request.fRequestMonitor;
rm.setData(fCount);
rm.done();
}
@ConfinedToDsfExecutor("fExecutor")
private void processItemRequest(ItemRequest request) {
@SuppressWarnings("unchecked") // Suppress warning about lost type info.
DataRequestMonitor<String> rm = (DataRequestMonitor<String>)request.fRequestMonitor;
if (fChangedIndexes.contains(request.fIndex)) {
rm.setData("Changed: " + request.fIndex);
} else {
rm.setData(Integer.toString(request.fIndex));
}
rm.done();
}
/**
* This method simulates changes in the supplier's data set.
*/
@ConfinedToDsfExecutor("fExecutor")
private void randomChanges() {
// Once every number of changes, reset the count, the rest of the
// times just change certain values.
if (++fCountResetTrigger % RANDOM_COUNT_CHANGE_INTERVALS == 0){
randomCountReset();
} else {
randomDataChange();
}
}
/**
* Calculates new size for provider's data set.
*/
@ConfinedToDsfExecutor("fExecutor")
private void randomCountReset() {
// Calculate the new count.
Random random = new java.util.Random();
fCount = MIN_COUNT + Math.abs(random.nextInt()) % (MAX_COUNT - MIN_COUNT);
// Reset the changed values.
fChangedIndexes.clear();
// Notify listeners
for (Listener listener : fListeners) {
listener.countChanged();
}
}
/**
* Invalidates a random range of indexes.
*/
@ConfinedToDsfExecutor("fExecutor")
private void randomDataChange() {
// Calculate the indexes to change.
Random random = new java.util.Random();
Set<Integer> set = new HashSet<Integer>();
for (int i = 0; i < fCount * RANDOM_CHANGE_SET_PERCENTAGE / 100; i++) {
set.add( new Integer(Math.abs(random.nextInt()) % fCount) );
}
// Add the indexes to an overall set of changed indexes.
fChangedIndexes.addAll(set);
// Notify listeners
for (Listener listener : fListeners) {
listener.valuesChanged(set);
}
}
}

View file

@ -0,0 +1,238 @@
/*******************************************************************************
* Copyright (c) 2006, 2008 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.examples.dsf.dataviewer.answers;
import java.util.Collections;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.core.runtime.Status;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
import org.eclipse.dd.examples.dsf.DsfExamplesPlugin;
/**
* Thread-based implementation of the data generator.
* <p>
* This generator is based around a queue of client requests and a thread which
* reads the requests from the queue and processes them. The distinguishing
* feature of this generator is that it uses a a blocking queue as the main
* synchronization object. However, fListeners, fShutdown, and fChangedIndexes
* fields also need to be thread-safe and so they implement their own
* synchronization.
* </p>
*/
public class DataGeneratorWithThread extends Thread implements IDataGenerator {
// Request objects are used to serialize the interface calls into objects
// which can then be pushed into a queue.
abstract class Request {
final RequestMonitor fRequestMonitor;
Request(RequestMonitor rm) {
fRequestMonitor = rm;
}
}
class CountRequest extends Request {
CountRequest(DataRequestMonitor<Integer> rm) {
super(rm);
}
}
class ItemRequest extends Request {
final int fIndex;
ItemRequest(int index, DataRequestMonitor<String> rm) {
super(rm);
fIndex = index;
}
}
class ShutdownRequest extends Request {
ShutdownRequest(RequestMonitor rm) {
super(rm);
}
}
// Main request queue of the data generator. The getValue(), getCount(),
// and shutdown() methods write into the queue, while the run() method
// reads from it.
private final BlockingQueue<Request> fQueue = new LinkedBlockingQueue<Request>();
// ListenerList class provides thread safety.
private ListenerList fListeners = new ListenerList();
// Current number of elements in this generator.
private int fCount = MIN_COUNT;
// Counter used to determine when to reset the element count.
private int fCountResetTrigger = 0;
// Elements which were modified since the last reset.
private Set<Integer> fChangedIndexes = Collections.synchronizedSet(new HashSet<Integer>());
// Used to determine when to make changes in data.
private long fLastChangeTime = System.currentTimeMillis();
// Flag indicating when the generator has been shut down.
private AtomicBoolean fShutdown = new AtomicBoolean(false);
public DataGeneratorWithThread() {
// Immediately kick off the request processing thread.
start();
}
public void shutdown(RequestMonitor rm) {
// Mark the generator as shut down. After the fShutdown flag is set,
// all new requests should be shut down.
if (!fShutdown.getAndSet(true)) {
fQueue.add(new ShutdownRequest(rm));
} else {
//
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
rm.done();
}
}
public void getCount(DataRequestMonitor<Integer> rm) {
if (!fShutdown.get()) {
fQueue.add(new CountRequest(rm));
} else {
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
rm.done();
}
}
public void getValue(int index, DataRequestMonitor<String> rm) {
if (!fShutdown.get()) {
fQueue.add(new ItemRequest(index, rm));
} else {
rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
rm.done();
}
}
public void addListener(Listener listener) {
fListeners.add(listener);
}
public void removeListener(Listener listener) {
fListeners.remove(listener);
}
@Override
public void run() {
try {
while(true) {
// Get the next request from the queue. The time-out
// ensures that that the random changes get processed.
final Request request = fQueue.poll(100, TimeUnit.MILLISECONDS);
// If a request was dequeued, process it.
if (request != null) {
// Simulate a processing delay.
Thread.sleep(PROCESSING_DELAY);
if (request instanceof CountRequest) {
processCountRequest((CountRequest)request);
} else if (request instanceof ItemRequest) {
processItemRequest((ItemRequest)request);
} else if (request instanceof ShutdownRequest) {
// If shutting down, just break out of the while(true)
// loop and thread will exit.
request.fRequestMonitor.done();
break;
}
}
// Simulate data changes.
randomChanges();
}
}
catch (InterruptedException x) {}
}
private void processCountRequest(CountRequest request) {
@SuppressWarnings("unchecked") // Suppress warning about lost type info.
DataRequestMonitor<Integer> rm = (DataRequestMonitor<Integer>)request.fRequestMonitor;
rm.setData(fCount);
rm.done();
}
private void processItemRequest(ItemRequest request) {
@SuppressWarnings("unchecked") // Suppress warning about lost type info.
DataRequestMonitor<String> rm = (DataRequestMonitor<String>)request.fRequestMonitor;
if (fChangedIndexes.contains(request.fIndex)) {
rm.setData("Changed: " + request.fIndex);
} else {
rm.setData(Integer.toString(request.fIndex));
}
rm.done();
}
private void randomChanges() {
// Check if enough time is elapsed.
if (System.currentTimeMillis() > fLastChangeTime + RANDOM_CHANGE_INTERVAL) {
fLastChangeTime = System.currentTimeMillis();
// Once every number of changes, reset the count, the rest of the
// times just change certain values.
if (++fCountResetTrigger % RANDOM_COUNT_CHANGE_INTERVALS == 0){
randomCountReset();
} else {
randomDataChange();
}
}
}
private void randomCountReset() {
// Calculate the new count.
Random random = new java.util.Random();
fCount = MIN_COUNT + Math.abs(random.nextInt()) % (MAX_COUNT - MIN_COUNT);
// Reset the changed values.
fChangedIndexes.clear();
// Notify listeners
for (Object listener : fListeners.getListeners()) {
((Listener)listener).countChanged();
}
}
private void randomDataChange() {
// Calculate the indexes to change.
Random random = new java.util.Random();
Set<Integer> set = new HashSet<Integer>();
for (int i = 0; i < fCount * RANDOM_CHANGE_SET_PERCENTAGE / 100; i++) {
set.add( new Integer(Math.abs(random.nextInt()) % fCount) );
}
// Add the indexes to an overall set of changed indexes.
fChangedIndexes.addAll(set);
// Notify listeners
for (Object listener : fListeners.getListeners()) {
((Listener)listener).valuesChanged(set);
}
}
}

View file

@ -0,0 +1,59 @@
/*******************************************************************************
* Copyright (c) 2006, 2008 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.examples.dsf.dataviewer.answers;
import java.util.Set;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
import org.eclipse.dd.dsf.concurrent.ThreadSafe;
/**
* Data generator is simple source of data used to populate the example table
* view. It contains two asynchronous methods for retrieving the data
* parameters: the count and the value for a given index. It also allows the
* view to receive events indicating when the data supplied by the generator
* is changed.
*/
@ThreadSafe
public interface IDataGenerator {
// Constants which control the data generator behavior.
// Changing the count range can stress the scalability of the system, while
// changing of the process delay and random change interval can stress
// its performance.
final static int MIN_COUNT = 100;
final static int MAX_COUNT = 200;
final static int PROCESSING_DELAY = 10;
final static int RANDOM_CHANGE_INTERVAL = 10000;
final static int RANDOM_COUNT_CHANGE_INTERVALS = 3;
final static int RANDOM_CHANGE_SET_PERCENTAGE = 10;
// Listener interface that the view needs to implement to react
// to the changes in data.
public interface Listener {
void countChanged();
void valuesChanged(Set<Integer> indexes);
}
// Data access methods.
void getCount(DataRequestMonitor<Integer> rm);
void getValue(int index, DataRequestMonitor<String> rm);
// Method used to shutdown the data generator including any threads that
// it may use.
void shutdown(RequestMonitor rm);
// Methods for registering change listeners.
void addListener(Listener listener);
void removeListener(Listener listener);
}

View file

@ -0,0 +1,182 @@
/*******************************************************************************
* Copyright (c) 2008 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.examples.dsf.dataviewer.answers;
import java.util.Set;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.ImmediateExecutor;
import org.eclipse.dd.dsf.concurrent.Query;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
/**
* Data viewer based on a table, which reads data using synchronous methods.
* <p>
* This viewer implements the {@link IStructuredContentProvider} interface
* which is used by the JFace TableViewer class to populate a Table. This
* interface contains one principal methods for reading data {@link #getElements(Object)},
* which synchronously returns an array of elements. In order to implement this
* method using the asynchronous data generator, this provider uses the
* {@link Query} object.
* </p>
*/
public class SyncDataViewer
implements IStructuredContentProvider, IDataGenerator.Listener
{
// The viewer and generator that this content provider using.
final private TableViewer fViewer;
final private IDataGenerator fDataGenerator;
public SyncDataViewer(TableViewer viewer, IDataGenerator generator) {
fViewer = viewer;
fDataGenerator = generator;
fDataGenerator.addListener(this);
}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
// Not used
}
public Object[] getElements(Object inputElement) {
// Create the query object for reading data count.
Query<Integer> countQuery = new Query<Integer>() {
@Override
protected void execute(DataRequestMonitor<Integer> rm) {
fDataGenerator.getCount(rm);
}
};
// Submit the query to be executed. A query implements a runnable
// interface and it has to be executed in order to do its work.
ImmediateExecutor.getInstance().execute(countQuery);
int count = 0;
// Block until the query completes, which will happen when the request
// monitor of the execute() method is marked done.
try {
count = countQuery.get();
} catch (Exception e) {
// InterruptedException and ExecutionException can be thrown here.
// ExecutionException containing a CoreException will be thrown
// if an error status is set to the Query's request monitor.
return new Object[0];
}
// Create the array that will be filled with elements.
// For each index in the array execute a query to get the element at
// that index.
final Object[] elements = new Object[count];
for (int i = 0; i < count; i++) {
final int index = i;
Query<String> valueQuery = new Query<String>() {
@Override
protected void execute(DataRequestMonitor<String> rm) {
fDataGenerator.getValue(index, rm);
}
};
ImmediateExecutor.getInstance().execute(valueQuery);
try {
elements[i] = valueQuery.get();
} catch (Exception e) {
elements[i] = "error";
}
}
return elements;
}
public void dispose() {
fDataGenerator.removeListener(this);
}
public void countChanged() {
// For any event from the generator, refresh the whole viewer.
refreshViewer();
}
public void valuesChanged(Set<Integer> indexes) {
// For any event from the generator, refresh the whole viewer.
refreshViewer();
}
private void refreshViewer() {
getElements(null);
// This method may be called on any thread, switch to the display
// thread before calling the viewer.
Display display = fViewer.getControl().getDisplay();
display.asyncExec( new Runnable() {
public void run() {
if (!fViewer.getControl().isDisposed()) {
fViewer.refresh();
}
}
});
}
public static void main(String[] args) {
// Create the shell to hold the viewer.
Display display = new Display();
Shell shell = new Shell(display, SWT.SHELL_TRIM);
shell.setLayout(new GridLayout());
GridData data = new GridData(GridData.FILL_BOTH);
shell.setLayoutData(data);
Font font = new Font(display, "Courier", 10, SWT.NORMAL);
// Create the table viewer.
TableViewer tableViewer = new TableViewer(shell, SWT.BORDER);
tableViewer.getControl().setLayoutData(data);
// Create the data generator.
final IDataGenerator generator = new DataGeneratorWithExecutor();
// Create the content provider which will populate the viewer.
SyncDataViewer contentProvider = new SyncDataViewer(tableViewer, generator);
tableViewer.setContentProvider(contentProvider);
tableViewer.setInput(new Object());
// Open the shell and service the display dispatch loop until user
// closes the shell.
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
// The IDataGenerator.shutdown() method is asynchronous, this requires
// using a query again in order to wait for its completion.
Query<Object> shutdownQuery = new Query<Object>() {
@Override
protected void execute(DataRequestMonitor<Object> rm) {
generator.shutdown(rm);
}
};
ImmediateExecutor.getInstance().execute(shutdownQuery);
try {
shutdownQuery.get();
} catch (Exception e) {}
// Shut down the display.
font.dispose();
display.dispose();
}
}

View file

@ -0,0 +1,40 @@
/*******************************************************************************
* Copyright (c) 2008 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.examples.dsf.requestmonitor;
import java.util.concurrent.Executor;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.ImmediateExecutor;
/**
* Example of using a DataRequestMonitor to retrieve a result from an
* asynchronous method.
*/
public class Async2Plus2 {
public static void main(String[] args) {
Executor executor = ImmediateExecutor.getInstance();
DataRequestMonitor<Integer> rm =
new DataRequestMonitor<Integer>(executor, null) {
@Override
protected void handleCompleted() {
System.out.println("2 + 2 = " + getData());
}
};
asyncAdd(2, 2, rm);
}
static void asyncAdd(int value1, int value2, DataRequestMonitor<Integer> rm) {
rm.setData(value1 + value2);
rm.done();
}
}

View file

@ -0,0 +1,46 @@
/*******************************************************************************
* Copyright (c) 2008 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.examples.dsf.requestmonitor;
import java.util.concurrent.Executor;
import org.eclipse.dd.dsf.concurrent.ImmediateExecutor;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
/**
* "Hello world" example which uses an asynchronous method to print out
* the result.
* <p>
* The main method uses an immediate executor, which executes runnables
* as soon as they are submitted, in creating its request monitor.
*
*/
public class AsyncHelloWorld {
public static void main(String[] args) {
Executor executor = ImmediateExecutor.getInstance();
RequestMonitor rm = new RequestMonitor(executor, null);
asyncHelloWorld(rm);
}
static void asyncHelloWorld(RequestMonitor rm) {
System.out.println("Hello world");
// TODO Exercise 1: - Call the second async. "Hello world 2" method.
// Hint: Calling an asynchronous method requires passing to it a
// request monitor. A new request monitor can be constructed with
// a parent RequestMonitor as an argument argument. The parent gets
// completed automatically when the lower level request monitor is
// completed.
rm.done();
}
// TODO: Exercise 1 - Add a second async. "Hello world 2" method.
}

View file

@ -0,0 +1,111 @@
/*******************************************************************************
* Copyright (c) 2008 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.examples.dsf.requestmonitor;
import java.util.Arrays;
import java.util.concurrent.Executor;
import org.eclipse.dd.dsf.concurrent.CountingRequestMonitor;
import org.eclipse.dd.dsf.concurrent.ImmediateExecutor;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
/**
* Example of using a CountingRequestMonitor to wait for multiple
* asynchronous calls to complete.
*/
public class AsyncQuicksort {
static Executor fgExecutor = ImmediateExecutor.getInstance();
public static void main(String[] args) {
final int[] array = {5, 7, 8, 3, 2, 1, 9, 5, 4};
System.out.println("To sort: " + Arrays.toString(array));
asyncQuicksort(
array, 0, array.length - 1,
new RequestMonitor(fgExecutor, null) {
@Override
protected void handleCompleted() {
System.out.println("Sorted: " + Arrays.toString(array));
}
});
}
static void asyncQuicksort(final int[] array, final int left,
final int right, final RequestMonitor rm)
{
if (right > left) {
int pivot = left;
// TODO: Exercise 2 - Convert the call to partition into an
// asynchronous call to asyncPartition().
// Hint: The rest of the code below should be executed inside
// the DataRequestMonitor.handleCompleted() overriding method.
int newPivot = partition(array, left, right, pivot);
printArray(array, left, right, newPivot);
CountingRequestMonitor countingRm = new CountingRequestMonitor(fgExecutor, rm);
asyncQuicksort(array, left, newPivot - 1, countingRm);
asyncQuicksort(array, newPivot + 1, right, countingRm);
countingRm.setDoneCount(2);
} else {
rm.done();
}
}
// TODO Exercise 2 - Convert partition to an asynchronous method.
// Hint: a DataRequestMonitor<Integer> should be used to carry the
// return value to the caller.
static int partition(int[] array, int left, int right, int pivot)
{
int pivotValue = array[pivot];
array[pivot] = array[right];
array[right] = pivotValue;
int store = left;
for (int i = left; i < right; i++) {
if (array[i] <= pivotValue) {
int tmp = array[store];
array[store] = array[i];
array[i] = tmp;
store++;
}
}
array[right] = array[store];
array[store] = pivotValue;
// TODO: Request Monitors Exercise 2 - Return the data to caller using
// a request monitor.
return store;
}
static void printArray(int[] array, int left, int right, int pivot) {
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < array.length; i++ ) {
if (i == left) {
buffer.append('>');
} else if (i == pivot) {
buffer.append('-');
} else {
buffer.append(' ');
}
buffer.append(array[i]);
if (i == right) {
buffer.append('<');
} else if (i == pivot) {
buffer.append('-');
} else {
buffer.append(' ');
}
}
System.out.println(buffer);
}
}

View file

@ -0,0 +1,40 @@
/*******************************************************************************
* Copyright (c) 2008 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.examples.dsf.requestmonitor.answers;
import java.util.concurrent.Executor;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.ImmediateExecutor;
/**
* Example of using a DataRequestMonitor to retrieve a result from an
* asynchronous method.
*/
public class Async2Plus2 {
public static void main(String[] args) {
Executor executor = ImmediateExecutor.getInstance();
DataRequestMonitor<Integer> rm =
new DataRequestMonitor<Integer>(executor, null) {
@Override
protected void handleCompleted() {
System.out.println("2 + 2 = " + getData());
}
};
asyncAdd(2, 2, rm);
}
static void asyncAdd(int value1, int value2, DataRequestMonitor<Integer> rm) {
rm.setData(value1 + value2);
rm.done();
}
}

View file

@ -0,0 +1,44 @@
/*******************************************************************************
* Copyright (c) 2008 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.examples.dsf.requestmonitor.answers;
import java.util.concurrent.Executor;
import org.eclipse.dd.dsf.concurrent.ImmediateExecutor;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
/**
* "Hello world" example which uses an asynchronous method to print out
* the result.
* <p>
* The main method uses an immediate executor, which executes runnables
* as soon as they are submitted, in creating its request monitor.
*
*/
public class AsyncHelloWorld {
public static void main(String[] args) {
Executor executor = ImmediateExecutor.getInstance();
RequestMonitor rm = new RequestMonitor(executor, null);
asyncHelloWorld(rm);
}
static void asyncHelloWorld(RequestMonitor rm) {
System.out.println("Hello world");
RequestMonitor rm2 = new RequestMonitor(ImmediateExecutor.getInstance(), rm);
asyncHelloWorld2(rm2);
}
static void asyncHelloWorld2(RequestMonitor rm) {
System.out.println("Hello world 2");
rm.done();
}
}

View file

@ -0,0 +1,113 @@
/*******************************************************************************
* Copyright (c) 2008 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.examples.dsf.requestmonitor.answers;
import java.util.Arrays;
import java.util.concurrent.Executor;
import org.eclipse.dd.dsf.concurrent.CountingRequestMonitor;
import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
import org.eclipse.dd.dsf.concurrent.ImmediateExecutor;
import org.eclipse.dd.dsf.concurrent.RequestMonitor;
/**
* Example of using a CountingRequestMonitor to wait for multiple
* asynchronous calls to complete.
*/
public class AsyncQuicksort {
static Executor fgExecutor = ImmediateExecutor.getInstance();
public static void main(String[] args) {
final int[] array = {5, 7, 8, 3, 2, 1, 9, 5, 4};
System.out.println("To sort: " + Arrays.toString(array));
asyncQuicksort(
array, 0, array.length - 1,
new RequestMonitor(fgExecutor, null) {
@Override
protected void handleCompleted() {
System.out.println("Sorted: " + Arrays.toString(array));
}
});
}
static void asyncQuicksort(final int[] array, final int left,
final int right, final RequestMonitor rm)
{
if (right > left) {
int pivot = left;
asyncPartition(
array, left, right, pivot,
new DataRequestMonitor<Integer>(fgExecutor, rm) {
@Override
protected void handleCompleted() {
int newPivot = getData();
printArray(array, left, right, newPivot);
CountingRequestMonitor countingRm = new CountingRequestMonitor(fgExecutor, rm);
asyncQuicksort(array, left, newPivot - 1, countingRm);
asyncQuicksort(array, newPivot + 1, right, countingRm);
countingRm.setDoneCount(2);
}
});
} else {
rm.done();
}
}
static void asyncPartition(int[] array, int left, int right, int pivot, DataRequestMonitor<Integer> rm)
{
int pivotValue = array[pivot];
array[pivot] = array[right];
array[right] = pivotValue;
int store = left;
for (int i = left; i < right; i++) {
if (array[i] <= pivotValue) {
int tmp = array[store];
array[store] = array[i];
array[i] = tmp;
store++;
}
}
array[right] = array[store];
array[store] = pivotValue;
// Java 5 automatically converts the int type of the store variable
// to an Integer object.
rm.setData(store);
rm.done();
}
static void printArray(int[] array, int left, int right, int pivot) {
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < array.length; i++ ) {
if (i == left) {
buffer.append('>');
} else if (i == pivot) {
buffer.append('-');
} else {
buffer.append(' ');
}
buffer.append(array[i]);
if (i == right) {
buffer.append('<');
} else if (i == pivot) {
buffer.append('-');
} else {
buffer.append(' ');
}
}
System.out.println(buffer);
}
}

View file

@ -44,8 +44,14 @@ class AlarmsVMNode extends AbstractDMVMNode
@Override @Override
protected void updateElementsInSessionThread(final IChildrenUpdate update) { protected void updateElementsInSessionThread(final IChildrenUpdate update) {
// Check that the services are available // Check that the services are available
if (!checkService(AlarmService.class, null, update)) return; if ( getServicesTracker().getService(AlarmService.class) == null ) {
if (!checkService(TimerService.class, null, update)) return; handleFailedUpdate(update);
return;
}
if ( getServicesTracker().getService(TimerService.class) == null ) {
handleFailedUpdate(update);
return;
}
// Find the trigger and timer contexts. If not found, fail. // Find the trigger and timer contexts. If not found, fail.
TriggerDMContext alarmDmc = findDmcInPath( TriggerDMContext alarmDmc = findDmcInPath(

View file

@ -84,12 +84,14 @@ class TimersVMNode extends AbstractDMVMNode
@Override @Override
protected void updateElementsInSessionThread(final IChildrenUpdate update) { protected void updateElementsInSessionThread(final IChildrenUpdate update) {
if (!checkService(AlarmService.class, null, update)) return; if ( getServicesTracker().getService(TimerService.class) == null ) {
handleFailedUpdate(update);
return;
}
// Retrieve the timer DMContexts, create the corresponding VMCs array, and // Retrieve the timer DMContexts, create the corresponding VMCs array, and
// set them as result. // set them as result.
TimerDMContext[] timers = TimerDMContext[] timers = getServicesTracker().getService(TimerService.class).getTimers();
getServicesTracker().getService(TimerService.class).getTimers();
fillUpdateWithVMCs(update, timers); fillUpdateWithVMCs(update, timers);
update.done(); update.done();
} }
@ -118,14 +120,17 @@ class TimersVMNode extends AbstractDMVMNode
update.getViewerInput(), update.getElementPath(), TimerDMContext.class); update.getViewerInput(), update.getElementPath(), TimerDMContext.class);
// If either update or service are not valid, fail the update and exit. // If either update or service are not valid, fail the update and exit.
if (!checkDmc(dmc, update) || if ( dmc == null ) {
!checkService(TimerService.class, null, update)) handleFailedUpdate(update);
{ return;
return;
} }
TimerService timerService = TimerService timerService = getServicesTracker().getService(TimerService.class, null);
getServicesTracker().getService(TimerService.class, null); if ( timerService == null ) {
handleFailedUpdate(update);
return;
}
int value = timerService.getTimerValue(dmc); int value = timerService.getTimerValue(dmc);
if (value == -1) { if (value == -1) {

View file

@ -85,10 +85,12 @@ class TriggersVMNode extends AbstractDMVMNode
@Override @Override
protected void updateElementsInSessionThread(final IChildrenUpdate update) { protected void updateElementsInSessionThread(final IChildrenUpdate update) {
if (!checkService(AlarmService.class, null, update)) return; if ( getServicesTracker().getService(AlarmService.class) == null ) {
handleFailedUpdate(update);
return;
}
TriggerDMContext[] triggers = TriggerDMContext[] triggers = getServicesTracker().getService(AlarmService.class).getTriggers();
getServicesTracker().getService(AlarmService.class).getTriggers();
fillUpdateWithVMCs(update, triggers); fillUpdateWithVMCs(update, triggers);
update.done(); update.done();
} }
@ -119,16 +121,19 @@ class TriggersVMNode extends AbstractDMVMNode
TriggerDMContext triggerCtx = findDmcInPath( TriggerDMContext triggerCtx = findDmcInPath(
update.getViewerInput(), update.getElementPath(), TriggerDMContext.class); update.getViewerInput(), update.getElementPath(), TriggerDMContext.class);
// If either update or service are not valid, fail the update and exit. // If either update or service are not valid, fail the update and return.
if (!checkDmc(triggerCtx, update) || if ( triggerCtx == null ) {
!checkService(AlarmService.class, null, update)) handleFailedUpdate(update);
{
return; return;
} }
AlarmService alarmService = getServicesTracker().getService(AlarmService.class, null);
if ( alarmService == null ) {
handleFailedUpdate(update);
return;
}
// Calculate and set the update properties. // Calculate and set the update properties.
AlarmService alarmService =
getServicesTracker().getService(AlarmService.class, null);
int value = alarmService.getTriggerValue(triggerCtx); int value = alarmService.getTriggerValue(triggerCtx);
if (value == -1) { if (value == -1) {

View file

@ -54,9 +54,14 @@ public class ContainerVMNode extends AbstractDMVMNode
@Override @Override
protected void updateElementsInSessionThread(IChildrenUpdate update) { protected void updateElementsInSessionThread(IChildrenUpdate update) {
if (!checkService(AbstractMIControl.class, null, update)) return;
MIControlDMContext containerCtx = getServicesTracker().getService(AbstractMIControl.class).getControlDMContext(); AbstractMIControl controlService = getServicesTracker().getService(AbstractMIControl.class);
if ( controlService == null ) {
handleFailedUpdate(update);
return;
}
MIControlDMContext containerCtx = controlService.getControlDMContext();
update.setChild(createVMContext(containerCtx), 0); update.setChild(createVMContext(containerCtx), 0);
update.done(); update.done();
} }
@ -77,8 +82,11 @@ public class ContainerVMNode extends AbstractDMVMNode
protected void updateLabelInSessionThread(ILabelUpdate[] updates) { protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
for (final ILabelUpdate update : updates) { for (final ILabelUpdate update : updates) {
if (!checkService(GDBRunControl.class, null, update)) continue; final GDBRunControl runControl = getServicesTracker().getService(GDBRunControl.class);
final GDBRunControl runControl = getServicesTracker().getService(GDBRunControl.class); if ( runControl == null ) {
handleFailedUpdate(update);
continue;
}
final GDBControlDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), GDBControlDMContext.class); final GDBControlDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), GDBControlDMContext.class);

View file

@ -61,26 +61,30 @@ public class ThreadVMNode extends AbstractDMVMNode
@Override @Override
protected void updateElementsInSessionThread(final IChildrenUpdate update) { protected void updateElementsInSessionThread(final IChildrenUpdate update) {
if (!checkService(IRunControl.class, null, update)) return; IRunControl runControl = getServicesTracker().getService(IRunControl.class);
final IContainerDMContext contDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IContainerDMContext.class); if ( runControl == null ) {
handleFailedUpdate(update);
return;
}
if (contDmc == null) { final IContainerDMContext contDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IContainerDMContext.class);
handleFailedUpdate(update); if (contDmc == null) {
return; handleFailedUpdate(update);
} return;
}
getServicesTracker().getService(IRunControl.class).getExecutionContexts(contDmc, runControl.getExecutionContexts(contDmc,
new DataRequestMonitor<IExecutionDMContext[]>(getSession().getExecutor(), null){ new DataRequestMonitor<IExecutionDMContext[]>(getSession().getExecutor(), null){
@Override @Override
public void handleCompleted() { public void handleCompleted() {
if (!isSuccess()) { if (!isSuccess()) {
handleFailedUpdate(update); handleFailedUpdate(update);
return; return;
} }
fillUpdateWithVMCs(update, getData()); fillUpdateWithVMCs(update, getData());
update.done(); update.done();
} }
}); });
} }
@ -195,8 +199,11 @@ public class ThreadVMNode extends AbstractDMVMNode
protected void updateLabelInSessionThread(ILabelUpdate[] updates) { protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
for (final ILabelUpdate update : updates) { for (final ILabelUpdate update : updates) {
if (!checkService(GDBRunControl.class, null, update)) continue; final GDBRunControl runControl = getServicesTracker().getService(GDBRunControl.class);
final GDBRunControl runControl = getServicesTracker().getService(GDBRunControl.class); if ( runControl == null ) {
handleFailedUpdate(update);
continue;
}
final IMIExecutionDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IMIExecutionDMContext.class); final IMIExecutionDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IMIExecutionDMContext.class);
@ -220,7 +227,11 @@ public class ThreadVMNode extends AbstractDMVMNode
// We're in a new dispatch cycle, and we have to check whether the // We're in a new dispatch cycle, and we have to check whether the
// service reference is still valid. // service reference is still valid.
if (!checkService(GDBRunControl.class, null, update)) return; final GDBRunControl runControl = getServicesTracker().getService(GDBRunControl.class);
if ( runControl == null ) {
handleFailedUpdate(update);
return;
}
final StateChangeReason reason = getData().getStateChangeReason(); final StateChangeReason reason = getData().getStateChangeReason();