mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-29 19:45:01 +02:00
[245749] Make the IMIProcesses service deal with the threadId to groupId map to allow for other parts of the code to have access to this knowledge.
This commit is contained in:
parent
352badaaf3
commit
9920518e26
5 changed files with 147 additions and 51 deletions
|
@ -12,6 +12,7 @@ package org.eclipse.dd.gdb.internal.provisional.service;
|
|||
|
||||
import java.util.HashMap;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
|
@ -40,6 +41,7 @@ import org.eclipse.dd.dsf.debug.service.IRunControl.ISuspendedDMEvent;
|
|||
import org.eclipse.dd.dsf.debug.service.ISignals.ISignalsDMContext;
|
||||
import org.eclipse.dd.dsf.debug.service.ISourceLookup.ISourceLookupDMContext;
|
||||
import org.eclipse.dd.dsf.debug.service.command.CommandCache;
|
||||
import org.eclipse.dd.dsf.debug.service.command.IEventListener;
|
||||
import org.eclipse.dd.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext;
|
||||
import org.eclipse.dd.dsf.service.AbstractDsfService;
|
||||
import org.eclipse.dd.dsf.service.DsfServiceEventHandler;
|
||||
|
@ -50,16 +52,23 @@ import org.eclipse.dd.mi.service.IMIContainerDMContext;
|
|||
import org.eclipse.dd.mi.service.IMIExecutionDMContext;
|
||||
import org.eclipse.dd.mi.service.IMIProcessDMContext;
|
||||
import org.eclipse.dd.mi.service.IMIProcesses;
|
||||
import org.eclipse.dd.mi.service.MIProcesses;
|
||||
import org.eclipse.dd.mi.service.command.commands.MIListThreadGroups;
|
||||
import org.eclipse.dd.mi.service.command.commands.MITargetAttach;
|
||||
import org.eclipse.dd.mi.service.command.commands.MITargetDetach;
|
||||
import org.eclipse.dd.mi.service.command.commands.MIThreadInfo;
|
||||
import org.eclipse.dd.mi.service.command.events.MIThreadGroupCreatedEvent;
|
||||
import org.eclipse.dd.mi.service.command.events.MIThreadGroupExitedEvent;
|
||||
import org.eclipse.dd.mi.service.command.output.MIConst;
|
||||
import org.eclipse.dd.mi.service.command.output.MIInfo;
|
||||
import org.eclipse.dd.mi.service.command.output.MIListThreadGroupsInfo;
|
||||
import org.eclipse.dd.mi.service.command.output.MINotifyAsyncOutput;
|
||||
import org.eclipse.dd.mi.service.command.output.MIOOBRecord;
|
||||
import org.eclipse.dd.mi.service.command.output.MIOutput;
|
||||
import org.eclipse.dd.mi.service.command.output.MIResult;
|
||||
import org.eclipse.dd.mi.service.command.output.MIThread;
|
||||
import org.eclipse.dd.mi.service.command.output.MIThreadInfoInfo;
|
||||
import org.eclipse.dd.mi.service.command.output.MIValue;
|
||||
import org.eclipse.dd.mi.service.command.output.MIListThreadGroupsInfo.IThreadGroupInfo;
|
||||
import org.osgi.framework.BundleContext;
|
||||
|
||||
|
@ -70,7 +79,8 @@ import org.osgi.framework.BundleContext;
|
|||
* which really mean it supports the new -list-thread-groups command.
|
||||
*
|
||||
*/
|
||||
public class GDBProcesses_7_0 extends AbstractDsfService implements IMIProcesses, ICachingService {
|
||||
public class GDBProcesses_7_0 extends AbstractDsfService
|
||||
implements IMIProcesses, ICachingService, IEventListener {
|
||||
|
||||
// Below is the context hierarchy that is implemented between the
|
||||
// MIProcesses service and the MIRunControl service for the MI
|
||||
|
@ -329,6 +339,11 @@ public class GDBProcesses_7_0 extends AbstractDsfService implements IMIProcesses
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A map of thread id to thread group id. We use this to find out to which threadGroup a thread belongs.
|
||||
*/
|
||||
private Map<String, String> fThreadToGroupMap = new HashMap<String, String>();
|
||||
|
||||
private IGDBControl fCommandControl;
|
||||
|
||||
// A cache for commands about the threadGroups
|
||||
|
@ -379,7 +394,8 @@ public class GDBProcesses_7_0 extends AbstractDsfService implements IMIProcesses
|
|||
fThreadCommandCache.setContextAvailable(fCommandControl.getContext(), true);
|
||||
|
||||
getSession().addServiceEventListener(this, null);
|
||||
|
||||
fCommandControl.addEventListener(this);
|
||||
|
||||
// Register this service.
|
||||
register(new String[] { IProcesses.class.getName(),
|
||||
IMIProcesses.class.getName(),
|
||||
|
@ -401,6 +417,7 @@ public class GDBProcesses_7_0 extends AbstractDsfService implements IMIProcesses
|
|||
public void shutdown(RequestMonitor requestMonitor) {
|
||||
unregister();
|
||||
getSession().removeServiceEventListener(this);
|
||||
fCommandControl.removeEventListener(this);
|
||||
super.shutdown(requestMonitor);
|
||||
}
|
||||
|
||||
|
@ -427,10 +444,16 @@ public class GDBProcesses_7_0 extends AbstractDsfService implements IMIProcesses
|
|||
}
|
||||
|
||||
public IMIContainerDMContext createContainerContext(IProcessDMContext processDmc,
|
||||
String groupId) {
|
||||
String groupId) {
|
||||
return new GDBContainerDMC(getSession().getId(), processDmc, groupId);
|
||||
}
|
||||
|
||||
public IMIContainerDMContext createContainerContextFromThreadId(ICommandControlDMContext controlDmc, String threadId) {
|
||||
String groupId = fThreadToGroupMap.get(threadId);
|
||||
IProcessDMContext processDmc = createProcessContext(controlDmc, groupId);
|
||||
return createContainerContext(processDmc, groupId);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method obtains the model data for a given IThreadDMContext object
|
||||
* which can represent a thread or a process.
|
||||
|
@ -765,4 +788,80 @@ public class GDBProcesses_7_0 extends AbstractDsfService implements IMIProcesses
|
|||
fContainerCommandCache.reset(context);
|
||||
fThreadCommandCache.reset(context);
|
||||
}
|
||||
|
||||
/*
|
||||
* Catch =thread-created/exited and =thread-group-exited events to update our
|
||||
* groupId to threadId map.
|
||||
*/
|
||||
public void eventReceived(Object output) {
|
||||
for (MIOOBRecord oobr : ((MIOutput)output).getMIOOBRecords()) {
|
||||
if (oobr instanceof MINotifyAsyncOutput) {
|
||||
MINotifyAsyncOutput exec = (MINotifyAsyncOutput) oobr;
|
||||
String miEvent = exec.getAsyncClass();
|
||||
if ("thread-created".equals(miEvent) || "thread-exited".equals(miEvent)) { //$NON-NLS-1$ //$NON-NLS-2$
|
||||
String threadId = null;
|
||||
String groupId = null;
|
||||
|
||||
MIResult[] results = exec.getMIResults();
|
||||
for (int i = 0; i < results.length; i++) {
|
||||
String var = results[i].getVariable();
|
||||
MIValue val = results[i].getMIValue();
|
||||
if (var.equals("group-id")) { //$NON-NLS-1$
|
||||
if (val instanceof MIConst) {
|
||||
groupId = ((MIConst) val).getString();
|
||||
}
|
||||
} else if (var.equals("id")) { //$NON-NLS-1$
|
||||
if (val instanceof MIConst) {
|
||||
threadId = ((MIConst) val).getString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Until GDB is officially supporting multi-process, we may not get
|
||||
// a groupId. In this case, we are running single process and we'll
|
||||
// need its groupId
|
||||
if (groupId == null) {
|
||||
groupId = MIProcesses.UNIQUE_GROUP_ID;
|
||||
}
|
||||
|
||||
if ("thread-created".equals(miEvent)) { //$NON-NLS-1$
|
||||
// Update the thread to groupId map with the new groupId
|
||||
fThreadToGroupMap.put(threadId, groupId);
|
||||
} else {
|
||||
fThreadToGroupMap.remove(threadId);
|
||||
}
|
||||
} else if ("thread-group-created".equals(miEvent) || "thread-group-exited".equals(miEvent)) { //$NON-NLS-1$ //$NON-NLS-2$
|
||||
|
||||
String groupId = null;
|
||||
|
||||
MIResult[] results = exec.getMIResults();
|
||||
for (int i = 0; i < results.length; i++) {
|
||||
String var = results[i].getVariable();
|
||||
MIValue val = results[i].getMIValue();
|
||||
if (var.equals("id")) { //$NON-NLS-1$
|
||||
if (val instanceof MIConst) {
|
||||
groupId = ((MIConst) val).getString().trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (groupId != null) {
|
||||
if ("thread-group-exited".equals(miEvent)) { //$NON-NLS-1$
|
||||
// Remove any entries for that group from our thread to group map
|
||||
// When detaching from a group, we won't have received any thread-exited event
|
||||
// but we don't want to keep those entries.
|
||||
if (fThreadToGroupMap.containsValue(groupId)) {
|
||||
Iterator<Map.Entry<String, String>> iterator = fThreadToGroupMap.entrySet().iterator();
|
||||
while (iterator.hasNext()){
|
||||
if (iterator.next().getValue().equals(groupId)) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ public interface IMIProcesses extends IProcesses
|
|||
IProcessDMContext createProcessContext(ICommandControlDMContext controlDmc, String pid);
|
||||
|
||||
/**
|
||||
* Create a execution context.
|
||||
* Create an execution context.
|
||||
*
|
||||
* @param containerDmc The parent process debugging context
|
||||
* @param threadDmc The parent thread context
|
||||
|
@ -54,5 +54,14 @@ public interface IMIProcesses extends IProcesses
|
|||
*/
|
||||
IMIContainerDMContext createContainerContext(IProcessDMContext processDmc,
|
||||
String groupId);
|
||||
|
||||
/**
|
||||
* Create a container context based on a threadId. This implies knowledge
|
||||
* of which threads belong to which container.
|
||||
*
|
||||
* @param controlDmc The parent command control context of this context
|
||||
* @param threadId The thread id belonging to the container we want to create
|
||||
*/
|
||||
IMIContainerDMContext createContainerContextFromThreadId(ICommandControlDMContext controlDmc, String threadId);
|
||||
}
|
||||
|
||||
|
|
|
@ -393,6 +393,12 @@ public class MIProcesses extends AbstractDsfService implements IMIProcesses, ICa
|
|||
return new MIContainerDMC(getSession().getId(), processDmc, groupId);
|
||||
}
|
||||
|
||||
public IMIContainerDMContext createContainerContextFromThreadId(ICommandControlDMContext controlDmc, String threadId) {
|
||||
String groupId = UNIQUE_GROUP_ID;
|
||||
IProcessDMContext processDmc = createProcessContext(controlDmc, groupId);
|
||||
return createContainerContext(processDmc, groupId);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method obtains the model data for a given IThreadDMContext object
|
||||
* which can represent a thread or a process.
|
||||
|
|
|
@ -183,7 +183,7 @@ public class MIRunControlEventProcessor
|
|||
IContainerDMContext processContainerDmc = procService.createContainerContext(procDmc, groupId);
|
||||
|
||||
IExecutionDMContext execDmc = processContainerDmc;
|
||||
if (procService != null && threadId != null) {
|
||||
if (threadId != null) {
|
||||
IThreadDMContext threadDmc = procService.createThreadContext(procDmc, threadId);
|
||||
execDmc = procService.createExecutionContext(processContainerDmc, threadDmc, threadId);
|
||||
}
|
||||
|
|
|
@ -11,12 +11,10 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.dd.mi.service.command;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.dd.dsf.datamodel.DMContexts;
|
||||
import org.eclipse.dd.dsf.debug.service.IProcesses.IProcessDMContext;
|
||||
import org.eclipse.dd.dsf.debug.service.IProcesses.IThreadDMContext;
|
||||
import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext;
|
||||
|
@ -91,11 +89,6 @@ public class MIRunControlEventProcessor_7_0
|
|||
|
||||
private final DsfServicesTracker fServicesTracker;
|
||||
|
||||
/**
|
||||
* A map of thread id to thread group id. We use this to find out to which threadGroup a thread belongs.
|
||||
*/
|
||||
private Map<String, String> fThreadToGroupMap = new HashMap<String, String>();
|
||||
|
||||
/**
|
||||
* Creates the event processor and registers it as listener with the debugger
|
||||
* control.
|
||||
|
@ -190,22 +183,16 @@ public class MIRunControlEventProcessor_7_0
|
|||
}
|
||||
}
|
||||
|
||||
if ("thread-created".equals(miEvent)) { //$NON-NLS-1$
|
||||
// Until GDB is officially supporting multi-process, we may not get
|
||||
// a groupId. In this case, we are running single process and we'll
|
||||
// need a groupId
|
||||
if (groupId == null) {
|
||||
groupId = MIProcesses.UNIQUE_GROUP_ID;
|
||||
}
|
||||
// Update the thread to groupId map with the new groupId
|
||||
fThreadToGroupMap.put(threadId, groupId);
|
||||
} else {
|
||||
// It was not clear if MI would specify the groupId in the thread-exited event
|
||||
if (groupId == null) {
|
||||
groupId = fThreadToGroupMap.get(threadId);
|
||||
}
|
||||
fThreadToGroupMap.remove(threadId);
|
||||
}
|
||||
// Until GDB is officially supporting multi-process, we may not get
|
||||
// a groupId. In this case, we are running single process and we'll
|
||||
// need its groupId
|
||||
if (groupId == null) {
|
||||
groupId = MIProcesses.UNIQUE_GROUP_ID;
|
||||
}
|
||||
|
||||
// Here, threads are created and removed. We cannot use the IMIProcesses service
|
||||
// to map a threadId to a groupId, because there would be a race condition.
|
||||
// Since we have the groupId anyway, we have no problems.
|
||||
IMIProcesses procService = fServicesTracker.getService(IMIProcesses.class);
|
||||
|
||||
if (procService != null) {
|
||||
|
@ -245,18 +232,6 @@ public class MIRunControlEventProcessor_7_0
|
|||
event = new MIThreadGroupCreatedEvent(procDmc, exec.getToken(), groupId);
|
||||
} else if ("thread-group-exited".equals(miEvent)) { //$NON-NLS-1$
|
||||
event = new MIThreadGroupExitedEvent(procDmc, exec.getToken(), groupId);
|
||||
|
||||
// Remove any entries for that group from our thread to group map
|
||||
// When detaching from a group, we won't have received any thread-exited event
|
||||
// but we don't want to keep those entries.
|
||||
if (fThreadToGroupMap.containsValue(groupId)) {
|
||||
Iterator<Map.Entry<String, String>> iterator = fThreadToGroupMap.entrySet().iterator();
|
||||
while (iterator.hasNext()){
|
||||
if (iterator.next().getValue().equals(groupId)) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fCommandControl.getSession().dispatchEvent(event, fCommandControl.getProperties());
|
||||
|
@ -291,19 +266,26 @@ public class MIRunControlEventProcessor_7_0
|
|||
return null;
|
||||
}
|
||||
|
||||
// MI does not currently provide the group-id in these events
|
||||
IProcessDMContext procDmc = null;
|
||||
IContainerDMContext containerDmc = null;
|
||||
if (groupId == null) {
|
||||
groupId = fThreadToGroupMap.get(threadId);
|
||||
}
|
||||
IProcessDMContext procDmc = procService.createProcessContext(fControlDmc, groupId);
|
||||
IContainerDMContext processContainerDmc = procService.createContainerContext(procDmc, groupId);
|
||||
|
||||
IExecutionDMContext execDmc = processContainerDmc;
|
||||
if (procService != null && threadId != null) {
|
||||
IThreadDMContext threadDmc = procService.createThreadContext(procDmc, threadId);
|
||||
execDmc = procService.createExecutionContext(processContainerDmc, threadDmc, threadId);
|
||||
// MI does not currently provide the group-id in these events
|
||||
if (threadId != null) {
|
||||
containerDmc = procService.createContainerContextFromThreadId(fControlDmc, threadId);
|
||||
procDmc = DMContexts.getAncestorOfType(containerDmc, IProcessDMContext.class);
|
||||
}
|
||||
} else {
|
||||
// This code would only trigger if the groupId was provided by MI
|
||||
procDmc = procService.createProcessContext(fControlDmc, groupId);
|
||||
containerDmc = procService.createContainerContext(procDmc, groupId);
|
||||
}
|
||||
|
||||
IExecutionDMContext execDmc = containerDmc;
|
||||
if (threadId != null) {
|
||||
IThreadDMContext threadDmc = procService.createThreadContext(procDmc, threadId);
|
||||
execDmc = procService.createExecutionContext(containerDmc, threadDmc, threadId);
|
||||
}
|
||||
|
||||
MIEvent<?> event = null;
|
||||
if ("breakpoint-hit".equals(reason)) { //$NON-NLS-1$
|
||||
event = MIBreakpointHitEvent.parse(execDmc, exec.getToken(), exec.getMIResults());
|
||||
|
|
Loading…
Add table
Reference in a new issue