diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_0_NS.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_0_NS.java index 40b96c68b6c..611d5a5388f 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_0_NS.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_0_NS.java @@ -222,20 +222,22 @@ public class GDBRunControl_7_0_NS extends AbstractDsfService implements IMIRunCo } public StateChangeReason getReason() { - switch(getMIEvent().getType()) { - case MIRunningEvent.CONTINUE: - return StateChangeReason.USER_REQUEST; - case MIRunningEvent.NEXT: - case MIRunningEvent.NEXTI: - return StateChangeReason.STEP; - case MIRunningEvent.STEP: - case MIRunningEvent.STEPI: - return StateChangeReason.STEP; - case MIRunningEvent.FINISH: - return StateChangeReason.STEP; - case MIRunningEvent.UNTIL: - case MIRunningEvent.RETURN: - break; + if (getMIEvent() != null) { + switch(getMIEvent().getType()) { + case MIRunningEvent.CONTINUE: + return StateChangeReason.USER_REQUEST; + case MIRunningEvent.NEXT: + case MIRunningEvent.NEXTI: + return StateChangeReason.STEP; + case MIRunningEvent.STEP: + case MIRunningEvent.STEPI: + return StateChangeReason.STEP; + case MIRunningEvent.FINISH: + return StateChangeReason.STEP; + case MIRunningEvent.UNTIL: + case MIRunningEvent.RETURN: + break; + } } return StateChangeReason.UNKNOWN; } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_2_NS.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_2_NS.java index 1b668fef050..a33a9221e10 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_2_NS.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBRunControl_7_2_NS.java @@ -17,6 +17,9 @@ import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor; import org.eclipse.cdt.dsf.concurrent.RequestMonitor; import org.eclipse.cdt.dsf.datamodel.DMContexts; +import org.eclipse.cdt.dsf.datamodel.IDMContext; +import org.eclipse.cdt.dsf.debug.service.IProcesses.IProcessDMContext; +import org.eclipse.cdt.dsf.debug.service.IProcesses.IThreadDMContext; import org.eclipse.cdt.dsf.debug.service.IRunControl; import org.eclipse.cdt.dsf.debug.service.IRunControl2; import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService; @@ -27,6 +30,10 @@ import org.eclipse.cdt.dsf.mi.service.IMIExecutionDMContext; import org.eclipse.cdt.dsf.mi.service.IMIRunControl; import org.eclipse.cdt.dsf.mi.service.command.CommandFactory; import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo; +import org.eclipse.cdt.dsf.mi.service.command.output.MIListThreadGroupsInfo; +import org.eclipse.cdt.dsf.mi.service.command.output.MIListThreadGroupsInfo.IThreadGroupInfo; +import org.eclipse.cdt.dsf.mi.service.command.output.MIListThreadGroupsInfo.IThreadGroupInfo2; +import org.eclipse.cdt.dsf.mi.service.command.output.MIThread; import org.eclipse.cdt.dsf.service.DsfSession; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; @@ -41,6 +48,7 @@ public class GDBRunControl_7_2_NS extends GDBRunControl_7_0_NS private ICommandControlService fConnection; private CommandFactory fCommandFactory; + private IGDBProcesses fProcService; /////////////////////////////////////////////////////////////////////////// // Initialization and shutdown @@ -70,6 +78,7 @@ public class GDBRunControl_7_2_NS extends GDBRunControl_7_0_NS new Hashtable()); fConnection = getServicesTracker().getService(ICommandControlService.class); fCommandFactory = getServicesTracker().getService(IMICommandControl.class).getCommandFactory(); + fProcService = getServicesTracker().getService(IGDBProcesses.class); getSession().addServiceEventListener(this, null); rm.done(); } @@ -169,4 +178,63 @@ public class GDBRunControl_7_2_NS extends GDBRunControl_7_0_NS private void doResumeContainer(IMIContainerDMContext context, final RequestMonitor rm) { fConnection.queueCommand(fCommandFactory.createMIExecContinue(context), new DataRequestMonitor(getExecutor(), rm)); } + + + /** + * @since 4.1 + */ + protected void refreshThreads() { + fConnection.queueCommand( + fCommandFactory.createMIListThreadGroups(fConnection.getContext(), false, true), + new DataRequestMonitor(getExecutor(), null) { + @Override + protected void handleSuccess() { + IThreadGroupInfo[] groups = getData().getGroupList(); + for (IThreadGroupInfo group : groups) { + if (group instanceof IThreadGroupInfo2) { + MIThread[] threadList = ((IThreadGroupInfo2)group).getThreads(); + for (MIThread thread : threadList) { + String threadId = thread.getThreadId(); + IMIContainerDMContext containerDmc = + fProcService.createContainerContextFromThreadId(fConnection.getContext(), threadId); + IProcessDMContext processDmc = DMContexts.getAncestorOfType(containerDmc, IProcessDMContext.class); + IThreadDMContext threadDmc = + fProcService.createThreadContext(processDmc, threadId); + IMIExecutionDMContext execDmc = fProcService.createExecutionContext(containerDmc, threadDmc, threadId); + + MIThreadRunState threadState = fThreadRunStates.get(execDmc); + if (threadState != null) { + // We may not know this thread. This can happen when dealing with a remote + // where thread events are not reported immediately. + // However, the -list-thread-groups command we just sent will make + // GDB send those events. Therefore, we can just ignore threads we don't + // know about, and wait for those events. + if (MIThread.MI_THREAD_STATE_RUNNING.equals(thread.getState())) { + if (threadState.fSuspended == true) { + // We missed a resumed event! Send it now. + IResumedDMEvent resumedEvent = new ResumedEvent(execDmc, null); + fConnection.getSession().dispatchEvent(resumedEvent, getProperties()); + } + } else if (MIThread.MI_THREAD_STATE_STOPPED.equals(thread.getState())) { + if (threadState.fSuspended == false) { + // We missed a suspend event! Send it now. + ISuspendedDMEvent suspendedEvent = new SuspendedEvent(execDmc, null); + fConnection.getSession().dispatchEvent(suspendedEvent, getProperties()); + } + } else { + assert false : "Invalid thread state: " + thread.getState(); //$NON-NLS-1$ + } + } + } + } + } + } + }); + } + + @Override + public void flushCache(IDMContext context) { + super.flushCache(context); + refreshThreads(); + } } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/CommandFactory.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/CommandFactory.java index 0f11dfe4c6b..cc7d731c265 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/CommandFactory.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/CommandFactory.java @@ -677,6 +677,11 @@ public class CommandFactory { return new MIListThreadGroups(ctx, listAll); } + /** @since 4.1 */ + public ICommand createMIListThreadGroups(ICommandControlDMContext ctx, boolean listAll, boolean recurse) { + return new MIListThreadGroups(ctx, listAll, recurse); + } + /** @since 4.0 */ public ICommand createMIRemoveInferior(ICommandControlDMContext ctx, String groupId) { return new MIRemoveInferior(ctx, groupId); diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIListThreadGroups.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIListThreadGroups.java index d08be578832..3a4aa19587b 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIListThreadGroups.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/MIListThreadGroups.java @@ -67,24 +67,42 @@ import org.eclipse.cdt.dsf.mi.service.command.output.MIOutput; */ public class MIListThreadGroups extends MICommand { - // List all groups being debugged + /** + * List all groups (processes) being debugged. + */ public MIListThreadGroups(ICommandControlDMContext ctx) { this(ctx, false); } - // List all groups or threads being debugged which are children of the specified group + /** + * If the parameter groupId is null, list all groups (processes) being debugged. + * If the parameter groupId is a valid group, list all threads + * which are children of the specified group + */ public MIListThreadGroups(ICommandControlDMContext ctx, String groupId) { - this(ctx, groupId, false); + this(ctx, groupId, false, false); } - // List all groups available on the target + /** + * If the parameter listAll is true, list all processes running on the + * target (not just the debugged ones). + * If the parameter listAll is false, list only the processes being debugged. + */ public MIListThreadGroups(ICommandControlDMContext ctx, boolean listAll) { - this(ctx, null, listAll); + this(ctx, null, listAll, false); } + /** + * If the parameter recurse is true, list all threads of all processes. + * @since 4.1 + */ + public MIListThreadGroups(ICommandControlDMContext ctx, boolean listAll, boolean recurse) { + this(ctx, null, listAll, recurse); + } + // There should be no reason to have both listAll and groupId specified, // so this constructor is private, and exists to avoid duplicating code. - private MIListThreadGroups(ICommandControlDMContext ctx, String groupId, boolean listAll) { + private MIListThreadGroups(ICommandControlDMContext ctx, String groupId, boolean listAll, boolean recurse) { super(ctx, "-list-thread-groups"); //$NON-NLS-1$ assert !((groupId != null) && listAll); // see comment above @@ -94,6 +112,11 @@ public class MIListThreadGroups extends MICommand { arguments.add("--available"); //$NON-NLS-1$ } + if (recurse) { + arguments.add("--recurse"); //$NON-NLS-1$ + arguments.add("1"); //$NON-NLS-1$ + } + if (groupId != null) { assert groupId.trim().length() > 0; arguments.add(groupId); diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIListThreadGroupsInfo.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIListThreadGroupsInfo.java index 1385333e21f..d8269b22f7d 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIListThreadGroupsInfo.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIListThreadGroupsInfo.java @@ -131,6 +131,21 @@ import org.eclipse.cdt.dsf.concurrent.Immutable; * -list-thread-groups --available * ^done,groups=[{id="19418",type="process",description="gdb.7.1 -i mi testing/a.out",user="lmckhou"},{id="19424",type="process",description="/local/lmckhou/testing/a.out",user="lmckhou"},{id="19438",type="process",description="sleep 5",user="lmckhou"}] * + * -list-thread-groups --recurse 1 + * ^done,groups=[{id="i2",type="process",pid="11805",executable="/home/lmckhou/Consumer",cores=["0","1"], + * threads=[{id="6",target-id="Thread 0xb6516b70 (LWP 11811)",state="running",core="1"}, + * {id="5",target-id="Thread 0xb6d17b70 (LWP 11810)",state="running",core="1"}, + * {id="4",target-id="Thread 0xb7518b70 (LWP 11809)", + * frame={level="0",addr="0x0804850d",func="main",args=[],file="Consumer.cc",fullname="/home/lmckhou/Consumer.cc",line="5"}, + * state="stopped",core="0"}, + * {id="3",target-id="Thread 0xb7d19b70 (LWP 11808)",state="running",core="1"}, + * {id="2",target-id="Thread 0xb7d1bb30 (LWP 11805)",state="running",core="0"}]}, + * {id="i1",type="process",pid="11793",executable="/home/lmckhProducer",cores=["0","1"], + * threads=[{id="10",target-id="Thread 0xb6516b70 (LWP 11815)",state="running",core="0"}, + * {id="8",target-id="Thread 0xb7518b70 (LWP 11813)",state="running",core="0"}, + * {id="7",target-id="Thread 0xb7d19b70 (LWP 11812)",state="running",core="1"}, + * {id="1",target-id="Thread 0xb7d1bb30 (LWP 11793)",state="running",core="1"}]}] + * * GDB 7.2 * * (when no inferior is running) @@ -171,8 +186,15 @@ public class MIListThreadGroupsInfo extends MIInfo { String getExecutable(); } + /** + * @since 4.1 + */ + public interface IThreadGroupInfo2 extends IThreadGroupInfo { + MIThread[] getThreads(); + } + @Immutable - private static class ThreadGroupInfo implements IThreadGroupInfo { + private static class ThreadGroupInfo implements IThreadGroupInfo2 { final String fGroupId; final String fDescription; final String fName; @@ -181,9 +203,10 @@ public class MIListThreadGroupsInfo extends MIInfo { final String fPid; final String[] fCores; final String fExecutable; + final MIThread[] fThreadList; public ThreadGroupInfo(String id, String description, String type, String pid, - String user, String[] cores, String exec) { + String user, String[] cores, String exec, MIThread[] threads) { fGroupId = id; fDescription = description; fType = type; @@ -194,6 +217,8 @@ public class MIListThreadGroupsInfo extends MIInfo { fExecutable = exec; fName = parseName(fDescription); + + fThreadList = threads; } private static String parseName(String desc) { @@ -225,6 +250,8 @@ public class MIListThreadGroupsInfo extends MIInfo { public String getType() { return fType; } public String getExecutable() { return fExecutable; } + + public MIThread[] getThreads() { return fThreadList; } } @@ -274,6 +301,7 @@ public class MIListThreadGroupsInfo extends MIInfo { MIResult[] results = ((MITuple)values[i]).getMIResults(); String id, desc, type, pid, exec, user; id = desc = type = pid = exec = user = "";//$NON-NLS-1$ + MIThread[] threads = null; String[] cores = null; @@ -322,6 +350,13 @@ public class MIListThreadGroupsInfo extends MIInfo { String str = ((MIConst)value).getCString(); exec = str.trim(); } + } else if (var.equals("threads")) { //$NON-NLS-1$ + // Staring with GDB 7.1 + // Re-use the MIThreadInfoInfo parsing + MIValue value = result.getMIValue(); + if (value instanceof MIList) { + threads = MIThreadInfoInfo.parseThreads(((MIList)value)); + } } } // In the case of -list-thread-groups --available, the pid field is not present, but the @@ -332,7 +367,7 @@ public class MIListThreadGroupsInfo extends MIInfo { if (pid.equals("") && !desc.equals("")) { //$NON-NLS-1$ //$NON-NLS-2$ pid = id; } - fGroupList[i] = new ThreadGroupInfo(id, desc, type, pid, user, cores, exec); + fGroupList[i] = new ThreadGroupInfo(id, desc, type, pid, user, cores, exec, threads); } } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIThread.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIThread.java index 679ee148d95..f718950a327 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIThread.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIThread.java @@ -25,6 +25,11 @@ import org.eclipse.cdt.dsf.concurrent.Immutable; @Immutable public class MIThread { + /** @since 4.1 */ + public final static String MI_THREAD_STATE_RUNNING = "running"; //$NON-NLS-1$ + /** @since 4.1 */ + public final static String MI_THREAD_STATE_STOPPED = "stopped"; //$NON-NLS-1$ + final private String fThreadId; final private String fTargetId; final private String fOsId; diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIThreadInfoInfo.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIThreadInfoInfo.java index 9163acd275e..788291998b3 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIThreadInfoInfo.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIThreadInfoInfo.java @@ -115,7 +115,7 @@ public class MIThreadInfoInfo extends MIInfo { if (var.equals("threads")) { //$NON-NLS-1$ MIValue val = results[i].getMIValue(); if (val instanceof MIList) { - parseThreads((MIList) val); + fThreadList = parseThreads((MIList) val); } } else if (var.equals("current-thread-id")) { //$NON-NLS-1$ @@ -136,13 +136,14 @@ public class MIThreadInfoInfo extends MIInfo { // id="n",target-id="Thread 0xb7c8ab90 (LWP 7010)",frame={...},state="stopped" // id="n",target-id="Thread 0xb7c8eb90 (LWP 7807)",state="running" // id="n",target-id="Thread 162.32942",details="...",frame={...},state="stopped" - private void parseThreads(MIList list) { + static MIThread[] parseThreads(MIList list) { MIValue[] values = list.getMIValues(); - fThreadList = new MIThread[values.length]; + MIThread[] threadList = new MIThread[values.length]; for (int i = 0; i < values.length; i++) { - fThreadList[i] = MIThread.parse((MITuple) values[i]); + threadList[i] = MIThread.parse((MITuple) values[i]); } + return threadList; } }