1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-08-04 14:55:41 +02:00

Bug 397715 - [memory][expressions] Make use of GDB 7.6 new

=memory-changed MI event

Change-Id: I98c3cd273e185dfb1782527d7abd553351a163d9
Reviewed-on: https://git.eclipse.org/r/9662
Reviewed-by: Marc Khouzam <marc.khouzam@ericsson.com>
IP-Clean: Marc Khouzam <marc.khouzam@ericsson.com>
Tested-by: Marc Khouzam <marc.khouzam@ericsson.com>
This commit is contained in:
Marc Khouzam 2013-01-10 14:34:14 -05:00
parent 7f1f78e77a
commit 0248aa4474
7 changed files with 551 additions and 19 deletions

View file

@ -0,0 +1,165 @@
/*******************************************************************************
* Copyright (c) 2013 Ericsson 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:
* Marc Khouzam (Ericsson) - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.service;
import java.util.Hashtable;
import org.eclipse.cdt.core.IAddress;
import org.eclipse.cdt.dsf.concurrent.ImmediateRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
import org.eclipse.cdt.dsf.datamodel.DMContexts;
import org.eclipse.cdt.dsf.debug.service.IMemory;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService;
import org.eclipse.cdt.dsf.debug.service.command.IEventListener;
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
import org.eclipse.cdt.dsf.mi.service.IMIProcesses;
import org.eclipse.cdt.dsf.mi.service.MIMemory;
import org.eclipse.cdt.dsf.mi.service.command.output.MIConst;
import org.eclipse.cdt.dsf.mi.service.command.output.MINotifyAsyncOutput;
import org.eclipse.cdt.dsf.mi.service.command.output.MIOOBRecord;
import org.eclipse.cdt.dsf.mi.service.command.output.MIOutput;
import org.eclipse.cdt.dsf.mi.service.command.output.MIResult;
import org.eclipse.cdt.dsf.mi.service.command.output.MIValue;
import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.cdt.utils.Addr64;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
/**
* Memory service that uses the enhancements from GDB 7.6:
* =memory-changed MI event
*
* @since 4.2
*/
public class GDBMemory_7_6 extends GDBMemory_7_0 implements IEventListener {
private ICommandControlService fConnection;
public GDBMemory_7_6(DsfSession session) {
super(session);
}
@Override
public void initialize(final RequestMonitor requestMonitor) {
super.initialize(
new ImmediateRequestMonitor(requestMonitor) {
@Override
public void handleSuccess() {
doInitialize(requestMonitor);
}});
}
private void doInitialize(final RequestMonitor requestMonitor) {
register(new String[] { MIMemory.class.getName(),
IMemory.class.getName(),
GDBMemory_7_0.class.getName(),
GDBMemory_7_6.class.getName()},
new Hashtable<String, String>());
fConnection = getServicesTracker().getService(ICommandControlService.class);
if (fConnection == null) {
requestMonitor.done(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, "CommandControl Service is not available")); //$NON-NLS-1$
return;
}
fConnection.addEventListener(this);
requestMonitor.done();
}
@Override
public void shutdown(final RequestMonitor requestMonitor) {
fConnection.removeEventListener(this);
unregister();
super.shutdown(requestMonitor);
}
@Override
public void eventReceived(Object output) {
if (output instanceof MIOutput) {
MIOOBRecord[] records = ((MIOutput)output).getMIOOBRecords();
for (MIOOBRecord r : records) {
if (r instanceof MINotifyAsyncOutput) {
MINotifyAsyncOutput notifyOutput = (MINotifyAsyncOutput)r;
String asyncClass = notifyOutput.getAsyncClass();
// These events have been added with GDB 7.6
if ("memory-changed".equals(asyncClass)) { //$NON-NLS-1$
String groupId = null;
String addr = null;
int length = 0;
MIResult[] results = notifyOutput.getMIResults();
for (int i = 0; i < results.length; i++) {
String var = results[i].getVariable();
MIValue val = results[i].getMIValue();
if (var.equals("thread-group")) { //$NON-NLS-1$
if (val instanceof MIConst) {
groupId = ((MIConst)val).getString();
}
} else if (var.equals("addr")) { //$NON-NLS-1$
if (val instanceof MIConst) {
addr = ((MIConst)val).getString();
}
} else if (var.equals("len")) { //$NON-NLS-1$
if (val instanceof MIConst) {
try {
String lenStr = ((MIConst)val).getString().trim();
if (lenStr.startsWith("0x")) { //$NON-NLS-1$
length = Integer.parseInt(lenStr.substring(2), 16);
} else {
length = Integer.parseInt(lenStr);
}
} catch (NumberFormatException e) {
assert false;
}
}
} else if (var.equals("type")) { //$NON-NLS-1$
if (val instanceof MIConst) {
if ("code".equals(((MIConst)val).getString())) { //$NON-NLS-1$
}
}
}
}
IMIProcesses procService = getServicesTracker().getService(IMIProcesses.class);
if (procService != null && groupId != null && addr != null && length > 0) {
IContainerDMContext containerDmc =
procService.createContainerContextFromGroupId(fConnection.getContext(), groupId);
// Now refresh our memory cache, it case it contained this address. Don't have
// it send the potential IMemoryChangedEvent as we will send it ourselves (see below).
final IMemoryDMContext memoryDMC = DMContexts.getAncestorOfType(containerDmc, IMemoryDMContext.class);
final IAddress address = new Addr64(addr);
// The length returned by GDB is in bytes, while the memory cache expects
// a count of number of addresses of 8 bytes.
int count = length/8 + 1;
getMemoryCache(memoryDMC).refreshMemory(memoryDMC, address, 0, 1, count, false,
new RequestMonitor(getExecutor(), null) {
@Override
protected void handleCompleted() {
// Only once the memory cache is updated, we send the IMemoryChangedEvent. If we were to do it
// earlier, the memory view may not show the updated value.
//
// We must always send this event when GDB reports a memory change because it can mean that
// an expression or register has changed, and therefore we must notify the different views
// and services of it. We cannot rely on this event to be sent by the memory cache after being
// refreshed, because if the memory cache does not contain this address, it will not send
// the event.
getSession().dispatchEvent(new MemoryChangedEvent(memoryDMC, new IAddress[] { address }), getProperties());
}
});
}
}
}
}
}
}
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2008, 2012 Ericsson and others.
* Copyright (c) 2008, 2013 Ericsson 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
@ -12,6 +12,7 @@
* Marc Khouzam (Ericsson) - Support for GDB 7.4 (Bug 367788)
* Marc Khouzam (Ericsson) - Include IGDBHardware service for the multicore visualizer (Bug 335027)
* Vladimir Prus (Mentor Graphics) - Support for OS resources.
* Marc Khouzam (Ericsson) - Support for GDB 7.6 memory service
*******************************************************************************/
package org.eclipse.cdt.dsf.gdb.service;
@ -67,6 +68,8 @@ public class GdbDebugServicesFactory extends AbstractDsfDebugServicesFactory {
public static final String GDB_7_4_VERSION = "7.4"; //$NON-NLS-1$
/** @since 4.2*/
public static final String GDB_7_5_VERSION = "7.5"; //$NON-NLS-1$
/** @since 4.2*/
public static final String GDB_7_6_VERSION = "7.5.50"; //$NON-NLS-1$
private final String fVersion;
@ -172,6 +175,10 @@ public class GdbDebugServicesFactory extends AbstractDsfDebugServicesFactory {
@Override
protected IMemory createMemoryService(DsfSession session) {
if (GDB_7_6_VERSION.compareTo(fVersion) <= 0) {
return new GDBMemory_7_6(session);
}
if (GDB_7_0_VERSION.compareTo(fVersion) <= 0) {
return new GDBMemory_7_0(session);
}

View file

@ -34,6 +34,7 @@ import org.eclipse.cdt.dsf.datamodel.DMContexts;
import org.eclipse.cdt.dsf.datamodel.IDMContext;
import org.eclipse.cdt.dsf.debug.service.ICachingService;
import org.eclipse.cdt.dsf.debug.service.IExpressions;
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionChangedDMEvent;
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMAddress;
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
import org.eclipse.cdt.dsf.debug.service.IMemory;
@ -92,7 +93,8 @@ public class MIMemory extends AbstractDsfService implements IMemory, ICachingSer
// Map of memory caches
private Map<IMemoryDMContext, MIMemoryCache> fMemoryCaches;
private MIMemoryCache getMemoryCache(IMemoryDMContext memoryDMC) {
/** @since 4.2 */
protected MIMemoryCache getMemoryCache(IMemoryDMContext memoryDMC) {
MIMemoryCache cache = fMemoryCaches.get(memoryDMC);
if (cache == null) {
cache = new MIMemoryCache();
@ -490,12 +492,19 @@ public class MIMemory extends AbstractDsfService implements IMemory, ICachingSer
}
}
/**
* @nooverride This method is not intended to be re-implemented or extended by clients.
* @noreference This method is not intended to be referenced by clients.
*/
@DsfServiceEventHandler
/**
* @deprecated Replaced by the generic {@link #eventDispatched(IExpressionChangedDMEvent)}
*/
@Deprecated
public void eventDispatched(ExpressionChangedEvent e) {
}
/**
* @noreference This method is not intended to be referenced by clients.
* @since 4.2
*/
@DsfServiceEventHandler
public void eventDispatched(IExpressionChangedDMEvent e) {
// Get the context and expression service handle
final IExpressionDMContext context = e.getDMContext();
@ -518,7 +527,7 @@ public class MIMemory extends AbstractDsfService implements IMemory, ICachingSer
address = new Addr64(expAddress.getValue());
final IMemoryDMContext memoryDMC = DMContexts.getAncestorOfType(context, IMemoryDMContext.class);
getMemoryCache(memoryDMC).refreshMemory(memoryDMC, address, 0, 1, count,
getMemoryCache(memoryDMC).refreshMemory(memoryDMC, address, 0, 1, count, true,
new RequestMonitor(getExecutor(), null));
}
});
@ -629,7 +638,8 @@ public class MIMemory extends AbstractDsfService implements IMemory, ICachingSer
// MIMemoryCache
///////////////////////////////////////////////////////////////////////////
private class MIMemoryCache {
/** @since 4.2 */
protected class MIMemoryCache {
// The memory cache data structure
private SortedMemoryBlockList fMemoryBlockList;
@ -965,10 +975,12 @@ public class MIMemory extends AbstractDsfService implements IMemory, ICachingSer
* @param offset
* @param word_size
* @param count
* @param sendMemoryEvent Indicates if a IMemoryChangedEvent should be sent if the memory cache has changed.
* @param rm
*/
public void refreshMemory(final IMemoryDMContext memoryDMC, final IAddress address,
final long offset, final int word_size, final int count, final RequestMonitor rm)
final long offset, final int word_size, final int count, final boolean sendMemoryEvent,
final RequestMonitor rm)
{
// Check if we already cache part of this memory area (which means it
// is used by a memory service client that will have to be updated)
@ -983,16 +995,10 @@ public class MIMemory extends AbstractDsfService implements IMemory, ICachingSer
rm.done();
return;
}
// Prepare the data for the MemoryChangedEvent
final IAddress[] addresses = new IAddress[count];
for (int i = 0; i < count; i++) {
addresses[i] = address.add(i);
}
// Read the corresponding memory block
fCommandCache.reset();
readMemoryBlock(memoryDMC, address, 0, 1, count,
readMemoryBlock(memoryDMC, address, offset, word_size, count,
new DataRequestMonitor<MemoryByte[]>(getExecutor(), rm) {
@Override
protected void handleSuccess() {
@ -1006,8 +1012,15 @@ public class MIMemory extends AbstractDsfService implements IMemory, ICachingSer
}
}
if (blocksDiffer) {
updateMemoryCache(address, count, newBlock);
getSession().dispatchEvent(new MemoryChangedEvent(memoryDMC, addresses), getProperties());
updateMemoryCache(address.add(offset), count, newBlock);
if (sendMemoryEvent) {
// Send the MemoryChangedEvent
final IAddress[] addresses = new IAddress[count];
for (int i = 0; i < count; i++) {
addresses[i] = address.add(offset + i);
}
getSession().dispatchEvent(new MemoryChangedEvent(memoryDMC, addresses), getProperties());
}
}
rm.done();
}

View file

@ -0,0 +1,15 @@
#include <stdio.h>
int testMemoryChanges() {
int i = 8;
return i;
}
int main() {
printf("Running ConsoleSyncTestApp\n");
testMemoryChanges();
return 0;
}

View file

@ -0,0 +1,330 @@
/*******************************************************************************
* Copyright (c) 2013 Ericsson 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:
* Marc Khouzam (Ericsson) - Initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.tests.dsf.gdb.tests.tests_7_6;
import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.eclipse.cdt.core.IAddress;
import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.Query;
import org.eclipse.cdt.dsf.datamodel.DMContexts;
import org.eclipse.cdt.dsf.datamodel.IDMContext;
import org.eclipse.cdt.dsf.datamodel.IDMEvent;
import org.eclipse.cdt.dsf.debug.service.IExpressions;
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMAddress;
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
import org.eclipse.cdt.dsf.debug.service.IMemory;
import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryChangedEvent;
import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryDMContext;
import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl;
import org.eclipse.cdt.dsf.mi.service.command.events.MIStoppedEvent;
import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo;
import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
import org.eclipse.cdt.dsf.service.DsfServicesTracker;
import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.cdt.tests.dsf.gdb.framework.BackgroundRunner;
import org.eclipse.cdt.tests.dsf.gdb.framework.BaseTestCase;
import org.eclipse.cdt.tests.dsf.gdb.framework.SyncUtil;
import org.eclipse.cdt.tests.dsf.gdb.launching.TestsPlugin;
import org.eclipse.cdt.tests.dsf.gdb.tests.ITestConstants;
import org.eclipse.debug.core.model.MemoryByte;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
/**
* This test case verifies that different commands issued from the
* GDB console cause proper updating within the CDT views.
*/
@RunWith(BackgroundRunner.class)
public class GDBConsoleSynchronizingTest_7_6 extends BaseTestCase {
final static private int DEFAULT_TIMEOUT = 1000;
final static private TimeUnit DEFAULT_TIME_UNIT = TimeUnit.MILLISECONDS;
private DsfSession fSession;
private DsfServicesTracker fServicesTracker;
private IGDBControl fCommandControl;
private IMemory fMemoryService;
private IExpressions fExprService;
private List<IDMEvent<? extends IDMContext>> fEventsReceived = new ArrayList<IDMEvent<? extends IDMContext>>();
@Override
protected void setGdbVersion() {
setGdbProgramNamesLaunchAttributes(ITestConstants.SUFFIX_GDB_7_6);
}
@Override
protected void setLaunchAttributes() {
super.setLaunchAttributes();
setLaunchAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, "data/launch/bin/ConsoleSyncTestApp.exe");
}
@Override
public void doBeforeTest() throws Exception {
super.doBeforeTest();
fSession = getGDBLaunch().getSession();
Runnable runnable = new Runnable() {
@Override
public void run() {
fServicesTracker = new DsfServicesTracker(TestsPlugin.getBundleContext(), fSession.getId());
Assert.assertTrue(fServicesTracker != null);
fCommandControl = fServicesTracker.getService(IGDBControl.class);
Assert.assertTrue(fCommandControl != null);
fMemoryService = fServicesTracker.getService(IMemory.class);
Assert.assertTrue(fMemoryService != null);
fExprService = fServicesTracker.getService(IExpressions.class);
Assert.assertTrue(fExprService != null);
// Register to breakpoint events
fSession.addServiceEventListener(GDBConsoleSynchronizingTest_7_6.this, null);
}
};
fSession.getExecutor().submit(runnable).get();
}
@Override
public void doAfterTest() throws Exception {
Runnable runnable = new Runnable() {
@Override
public void run() {
fSession.removeServiceEventListener(GDBConsoleSynchronizingTest_7_6.this);
}
};
fSession.getExecutor().submit(runnable).get();
fEventsReceived.clear();
fServicesTracker.dispose();
super.doAfterTest();
}
//////////////////////////////////////////////////////////////////////////////////////
// Start of tests
//////////////////////////////////////////////////////////////////////////////////////
/**
* This test verifies that setting a variable from the console
* using the set command will properly trigger a DSF event to
* indicate the change. This test makes sure the value that
* changes is in the memory cache also.
*/
@Test
public void testSettingVariableWithSetWithMemory() throws Throwable {
MIStoppedEvent stoppedEvent = SyncUtil.runToLocation("testMemoryChanges");
final IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0);
final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, "i");
// Read the memory that will change first, or else there will be no event for it
Query<IExpressionDMAddress> query = new Query<IExpressionDMAddress>() {
@Override
protected void execute(final DataRequestMonitor<IExpressionDMAddress> rm) {
fExprService.getExpressionAddressData(exprDmc, rm);
}
};
fSession.getExecutor().execute(query);
IExpressionDMAddress data = query.get();
IMemoryDMContext memoryDmc = DMContexts.getAncestorOfType(frameDmc, IMemoryDMContext.class);
readMemory(memoryDmc, data.getAddress(), data.getSize());
fEventsReceived.clear();
queueConsoleCommand("set variable i=100");
IMemoryChangedEvent memoryEvent = waitForEvent(IMemoryChangedEvent.class);
assertEquals(1, memoryEvent.getAddresses().length);
assertEquals(data.getAddress(), memoryEvent.getAddresses()[0]);
}
/**
* This test verifies that setting a variable from the console
* using the set command will properly trigger a DSF event to
* indicate the change, when the address is not in the memory cache.
*/
@Test
public void testSettingVariableWithSet() throws Throwable {
MIStoppedEvent stoppedEvent = SyncUtil.runToLocation("testMemoryChanges");
final IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0);
final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, "i");
// Read the memory that will change first, or else there will be no event for it
Query<IExpressionDMAddress> query = new Query<IExpressionDMAddress>() {
@Override
protected void execute(final DataRequestMonitor<IExpressionDMAddress> rm) {
fExprService.getExpressionAddressData(exprDmc, rm);
}
};
fSession.getExecutor().execute(query);
IExpressionDMAddress data = query.get();
fEventsReceived.clear();
queueConsoleCommand("set variable i=100");
IMemoryChangedEvent memoryEvent = waitForEvent(IMemoryChangedEvent.class);
assertEquals(1, memoryEvent.getAddresses().length);
assertEquals(data.getAddress(), memoryEvent.getAddresses()[0]);
}
/**
* This test verifies that setting a variable from the console
* using the print command will properly trigger a DSF event
* to indicate the change.
*/
@Test
public void testSettingVariableWithPrint() throws Throwable {
MIStoppedEvent stoppedEvent = SyncUtil.runToLocation("testMemoryChanges");
final IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0);
final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, "i");
// Read the memory that will change first, or else there will be no event for it
Query<IExpressionDMAddress> query = new Query<IExpressionDMAddress>() {
@Override
protected void execute(final DataRequestMonitor<IExpressionDMAddress> rm) {
fExprService.getExpressionAddressData(exprDmc, rm);
}
};
fSession.getExecutor().execute(query);
IExpressionDMAddress data = query.get();
fEventsReceived.clear();
queueConsoleCommand("print i=100");
IMemoryChangedEvent memoryEvent = waitForEvent(IMemoryChangedEvent.class);
assertEquals(1, memoryEvent.getAddresses().length);
assertEquals(data.getAddress(), memoryEvent.getAddresses()[0]);
}
/**
* This test verifies that setting a memory location from the
* console will properly trigger a DSF event to indicate the change.
*/
@Test
public void testSettingMemory() throws Throwable {
MIStoppedEvent stoppedEvent = SyncUtil.runToLocation("testMemoryChanges");
final IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0);
final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, "i");
// Read the memory that will change first, or else there will be no event for it
Query<IExpressionDMAddress> query = new Query<IExpressionDMAddress>() {
@Override
protected void execute(final DataRequestMonitor<IExpressionDMAddress> rm) {
fExprService.getExpressionAddressData(exprDmc, rm);
}
};
fSession.getExecutor().execute(query);
IExpressionDMAddress data = query.get();
fEventsReceived.clear();
queueConsoleCommand("set {int}&i=100");
IMemoryChangedEvent memoryEvent = waitForEvent(IMemoryChangedEvent.class);
assertEquals(1, memoryEvent.getAddresses().length);
assertEquals(data.getAddress(), memoryEvent.getAddresses()[0]);
}
//////////////////////////////////////////////////////////////////////////////////////
// End of tests
//////////////////////////////////////////////////////////////////////////////////////
@DsfServiceEventHandler
public void eventDispatched(IDMEvent<? extends IDMContext> e) {
synchronized(this) {
fEventsReceived.add(e);
notifyAll();
}
}
private MemoryByte[] readMemory(final IMemoryDMContext dmc, final IAddress address, final int count)
throws Throwable
{
Query<MemoryByte[]> query = new Query<MemoryByte[]>() {
@Override
protected void execute(DataRequestMonitor<MemoryByte[]> rm) {
fMemoryService.getMemory(dmc, address, 0, 1, count, rm);
}
};
fSession.getExecutor().execute(query);
return query.get(DEFAULT_TIMEOUT, DEFAULT_TIME_UNIT);
}
private void queueConsoleCommand(String command) throws Throwable {
queueConsoleCommand(command, DEFAULT_TIMEOUT, DEFAULT_TIME_UNIT);
}
private void queueConsoleCommand(final String command, int timeout, TimeUnit unit) throws Throwable {
Query<MIInfo> query = new Query<MIInfo>() {
@Override
protected void execute(DataRequestMonitor<MIInfo> rm) {
fCommandControl.queueCommand(
fCommandControl.getCommandFactory().createMIInterpreterExecConsole(
fCommandControl.getContext(),
command),
rm);
}
};
fSession.getExecutor().execute(query);
query.get(timeout, unit);
}
private <V extends IDMEvent<? extends IDMContext>> V waitForEvent(Class<V> eventType) throws Exception {
return waitForEvent(eventType, DEFAULT_TIMEOUT);
}
@SuppressWarnings("unchecked")
private <V extends IDMEvent<? extends IDMContext>> V waitForEvent(Class<V> eventType, int timeout) throws Exception {
IDMEvent<?> event = getEvent(eventType);
if (event == null) {
synchronized(this) {
try {
wait(timeout);
}
catch (InterruptedException ex) {
}
}
event = getEvent(eventType);
if (event == null) {
throw new Exception(String.format("Timed out waiting for '%s' to occur.", eventType.getName()));
}
}
return (V)event;
}
@SuppressWarnings("unchecked")
private synchronized <V extends IDMEvent<? extends IDMContext>> V getEvent(Class<V> eventType) {
for (IDMEvent<?> e : fEventsReceived) {
if (eventType.isAssignableFrom(e.getClass())) {
fEventsReceived.remove(e);
return (V)e;
}
}
return null;
}
}

View file

@ -48,6 +48,7 @@ import org.junit.runners.Suite;
GDBMultiNonStopRunControlTest_7_6.class,
Suite_Sessionless_Tests.class,
GDBConsoleBreakpointsTest_7_6.class,
GDBConsoleSynchronizingTest_7_6.class,
/* Add your test class here */
})

View file

@ -49,6 +49,7 @@ import org.junit.runners.Suite;
Suite_Sessionless_Tests.class,
GDBConsoleBreakpointsTest_7_6.class,
TraceFileTest_7_6.class,
GDBConsoleSynchronizingTest_7_6.class,
/* Add your test class here */
})