mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-09-10 12:03:16 +02:00
[275497] Return the names of all processes without having to store
them in the service. Not only is this more efficient because a single call to the service is used, but it allows us to only store the names of processes that we are currently debugging. That way, we know that a pid to name mapping remains correct. Note that I only made the change in the 7.0 version of the Processes service. Pre-7.0, we didn't handle multi-process and therefore, we only use one name for the process we are currently debugging, and that name is taken from the executable binary intead.
This commit is contained in:
parent
364d0c3ed0
commit
98c14b14d9
2 changed files with 159 additions and 113 deletions
|
@ -159,54 +159,76 @@ public class GdbConnectCommand implements IConnect {
|
||||||
|
|
||||||
final List<IProcessInfo> procInfoList = new ArrayList<IProcessInfo>();
|
final List<IProcessInfo> procInfoList = new ArrayList<IProcessInfo>();
|
||||||
|
|
||||||
// For each process, obtain its name
|
final CountingRequestMonitor countingRm =
|
||||||
// Once all the names are obtained, prompt the user for the pid to use
|
new CountingRequestMonitor(fExecutor, rm) {
|
||||||
final CountingRequestMonitor countingRm =
|
@Override
|
||||||
new CountingRequestMonitor(fExecutor, rm) {
|
protected void handleSuccess() {
|
||||||
@Override
|
new PromptForPidJob(
|
||||||
protected void handleSuccess() {
|
"Prompt for Process", procInfoList.toArray(new IProcessInfo[0]), //$NON-NLS-1$
|
||||||
new PromptForPidJob(
|
new DataRequestMonitor<Integer>(fExecutor, rm) {
|
||||||
"Prompt for Process", procInfoList.toArray(new IProcessInfo[0]), //$NON-NLS-1$
|
@Override
|
||||||
new DataRequestMonitor<Integer>(fExecutor, rm) {
|
protected void handleSuccess() {
|
||||||
@Override
|
// New cycle, look for service again
|
||||||
protected void handleSuccess() {
|
final IMIProcesses procService = fTracker.getService(IMIProcesses.class);
|
||||||
// New cycle, look for service again
|
if (procService != null) {
|
||||||
final IMIProcesses procService = fTracker.getService(IMIProcesses.class);
|
IProcessDMContext procDmc = procService.createProcessContext(controlCtx,
|
||||||
if (procService != null) {
|
Integer.toString(getData()));
|
||||||
IProcessDMContext procDmc = procService.createProcessContext(controlCtx,
|
procService.attachDebuggerToProcess(procDmc, new DataRequestMonitor<IDMContext>(fExecutor, rm));
|
||||||
Integer.toString(getData()));
|
}
|
||||||
procService.attachDebuggerToProcess(procDmc, new DataRequestMonitor<IDMContext>(fExecutor, rm));
|
}
|
||||||
}
|
}).schedule();
|
||||||
}
|
}
|
||||||
}).schedule();
|
};
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// New cycle, look for service again
|
if (getData().length > 0 && getData()[0] instanceof IThreadDMData) {
|
||||||
final IProcesses procService = fTracker.getService(IProcesses.class);
|
// The list of running processes also contains the name of the processes
|
||||||
|
// This is much more efficient. Let's use it.
|
||||||
|
for (IProcessDMContext processCtx : getData()) {
|
||||||
|
IThreadDMData processData = (IThreadDMData) processCtx;
|
||||||
|
int pid = 0;
|
||||||
|
try {
|
||||||
|
pid = Integer.parseInt(processData.getId());
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
}
|
||||||
|
procInfoList.add(new ProcessInfo(pid, processData.getName()));
|
||||||
|
}
|
||||||
|
|
||||||
if (procService != null) {
|
// Re-use the counting monitor and trigger it right away.
|
||||||
countingRm.setDoneCount(getData().length);
|
// No need to call done() in this case.
|
||||||
|
countingRm.setDoneCount(0);
|
||||||
for (IProcessDMContext processCtx : getData()) {
|
|
||||||
procService.getExecutionData(
|
|
||||||
processCtx,
|
|
||||||
new DataRequestMonitor<IThreadDMData> (fExecutor, countingRm) {
|
|
||||||
@Override
|
|
||||||
protected void handleSuccess() {
|
|
||||||
int pid = 0;
|
|
||||||
try {
|
|
||||||
pid = Integer.parseInt(getData().getId());
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
}
|
|
||||||
procInfoList.add(new ProcessInfo(pid, getData().getName()));
|
|
||||||
countingRm.done();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
countingRm.setDoneCount(1);
|
// The list of running processes does not contain the names, so
|
||||||
countingRm.done();
|
// we must obtain it individually
|
||||||
|
|
||||||
|
// For each process, obtain its name
|
||||||
|
// Once all the names are obtained, prompt the user for the pid to use
|
||||||
|
|
||||||
|
// New cycle, look for service again
|
||||||
|
final IProcesses procService = fTracker.getService(IProcesses.class);
|
||||||
|
|
||||||
|
if (procService != null) {
|
||||||
|
countingRm.setDoneCount(getData().length);
|
||||||
|
|
||||||
|
for (IProcessDMContext processCtx : getData()) {
|
||||||
|
procService.getExecutionData(
|
||||||
|
processCtx,
|
||||||
|
new DataRequestMonitor<IThreadDMData> (fExecutor, countingRm) {
|
||||||
|
@Override
|
||||||
|
protected void handleSuccess() {
|
||||||
|
int pid = 0;
|
||||||
|
try {
|
||||||
|
pid = Integer.parseInt(getData().getId());
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
}
|
||||||
|
procInfoList.add(new ProcessInfo(pid, getData().getName()));
|
||||||
|
countingRm.done();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Trigger right away. No need to call done() in this case.
|
||||||
|
countingRm.setDoneCount(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -148,11 +148,11 @@ public class GDBProcesses_7_0 extends AbstractDsfService
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
return super.baseEquals(obj) && ((MIExecutionDMC)obj).fThreadId.equals(fThreadId);
|
return baseEquals(obj) && ((MIExecutionDMC)obj).fThreadId.equals(fThreadId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() { return super.baseHashCode() ^ fThreadId.hashCode(); }
|
public int hashCode() { return baseHashCode() ^ fThreadId.hashCode(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -191,12 +191,12 @@ public class GDBProcesses_7_0 extends AbstractDsfService
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
return super.baseEquals(obj) &&
|
return baseEquals(obj) &&
|
||||||
(((MIContainerDMC)obj).fId == null ? fId == null : ((MIContainerDMC)obj).fId.equals(fId));
|
(((MIContainerDMC)obj).fId == null ? fId == null : ((MIContainerDMC)obj).fId.equals(fId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() { return super.baseHashCode() ^ (fId == null ? 0 : fId.hashCode()); }
|
public int hashCode() { return baseHashCode() ^ (fId == null ? 0 : fId.hashCode()); }
|
||||||
}
|
}
|
||||||
|
|
||||||
private class GDBContainerDMC extends MIContainerDMC
|
private class GDBContainerDMC extends MIContainerDMC
|
||||||
|
@ -245,12 +245,12 @@ public class GDBProcesses_7_0 extends AbstractDsfService
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
return super.baseEquals(obj) &&
|
return baseEquals(obj) &&
|
||||||
(((MIThreadDMC)obj).fId == null ? fId == null : ((MIThreadDMC)obj).fId.equals(fId));
|
(((MIThreadDMC)obj).fId == null ? fId == null : ((MIThreadDMC)obj).fId.equals(fId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() { return super.baseHashCode() ^ (fId == null ? 0 : fId.hashCode()); }
|
public int hashCode() { return baseHashCode() ^ (fId == null ? 0 : fId.hashCode()); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
|
@ -284,12 +284,12 @@ public class GDBProcesses_7_0 extends AbstractDsfService
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
return super.baseEquals(obj) &&
|
return baseEquals(obj) &&
|
||||||
(((MIProcessDMC)obj).fId == null ? fId == null : ((MIProcessDMC)obj).fId.equals(fId));
|
(((MIProcessDMC)obj).fId == null ? fId == null : ((MIProcessDMC)obj).fId.equals(fId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() { return super.baseHashCode() ^ (fId == null ? 0 : fId.hashCode()); }
|
public int hashCode() { return baseHashCode() ^ (fId == null ? 0 : fId.hashCode()); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -312,6 +312,34 @@ public class GDBProcesses_7_0 extends AbstractDsfService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
private static class MIProcessDMCAndData extends MIProcessDMC implements IThreadDMData {
|
||||||
|
final String fName;
|
||||||
|
|
||||||
|
public MIProcessDMCAndData(String sessionId, ICommandControlDMContext controlDmc, String id, String name) {
|
||||||
|
super(sessionId, controlDmc, id);
|
||||||
|
fName = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() { return getProcId(); }
|
||||||
|
public String getName() { return fName; }
|
||||||
|
public boolean isDebuggerAttached() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() { return baseToString() + ".proc[" + getId() + "," + getName() + "]"; } //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
return super.equals(obj) &&
|
||||||
|
(((MIProcessDMCAndData)obj).fName == null ? fName == null : ((MIProcessDMCAndData)obj).fName.equals(fName));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() { return super.hashCode() ^ (fName == null ? 0 : fName.hashCode()); }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Event indicating that an container (debugged process) has started. This event
|
* Event indicating that an container (debugged process) has started. This event
|
||||||
* implements the {@link IStartedMDEvent} from the IRunControl service.
|
* implements the {@link IStartedMDEvent} from the IRunControl service.
|
||||||
|
@ -358,8 +386,11 @@ public class GDBProcesses_7_0 extends AbstractDsfService
|
||||||
// overlapping situations.
|
// overlapping situations.
|
||||||
private CommandCache fListThreadGroupsAvailableCache;
|
private CommandCache fListThreadGroupsAvailableCache;
|
||||||
|
|
||||||
// A map of process id to process names. It is filled when we get all the processes that are running
|
// A map of process id to process names. A name is fetched whenever we start
|
||||||
private Map<String, String> fProcessNames = new HashMap<String, String>();
|
// debugging a process, and removed when we stop.
|
||||||
|
// This allows us to make sure that if a pid is re-used, we will not use an
|
||||||
|
// old name for it. Bug 275497
|
||||||
|
private Map<String, String> fDebuggedProcessNames = new HashMap<String, String>();
|
||||||
|
|
||||||
private static final String FAKE_THREAD_ID = "0"; //$NON-NLS-1$
|
private static final String FAKE_THREAD_ID = "0"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
@ -501,59 +532,29 @@ public class GDBProcesses_7_0 extends AbstractDsfService
|
||||||
|
|
||||||
public void getExecutionData(IThreadDMContext dmc, final DataRequestMonitor<IThreadDMData> rm) {
|
public void getExecutionData(IThreadDMContext dmc, final DataRequestMonitor<IThreadDMData> rm) {
|
||||||
if (dmc instanceof IMIProcessDMContext) {
|
if (dmc instanceof IMIProcessDMContext) {
|
||||||
if (fBackend.getSessionType() == SessionType.CORE) {
|
String id = ((IMIProcessDMContext)dmc).getProcId();
|
||||||
|
String name = null;
|
||||||
|
if (fBackend.getSessionType() == SessionType.CORE || "42000".equals(id)) { //$NON-NLS-1$
|
||||||
// For the Core session, the process is no longer running.
|
// For the Core session, the process is no longer running.
|
||||||
// Therefore, we cannot get its name with the -list-thread-groups command
|
// Therefore, we cannot get its name with the -list-thread-groups command.
|
||||||
// Instead, we take it from the binary we are using.
|
// As for id 42000, it is a special id used by GDB to indicate the real proc
|
||||||
String name = fBackend.getProgramPath().lastSegment();
|
// id is not known. This will happen in a Remote session, when we use
|
||||||
// Also, the pid we get from GDB is 1, which is not correct.
|
// -target-select remote instead of -target-select extended-remote.
|
||||||
|
//
|
||||||
|
// So, we take the name from the binary we are using.
|
||||||
|
name = fBackend.getProgramPath().lastSegment();
|
||||||
|
// Also, the pid we get from GDB is 1 or 42000, which is not correct.
|
||||||
// I haven't found a good way to get the pid yet, so let's not show it.
|
// I haven't found a good way to get the pid yet, so let's not show it.
|
||||||
rm.setData(new MIThreadDMData(name, null));
|
id = null;
|
||||||
rm.done();
|
|
||||||
} else {
|
} else {
|
||||||
final String id = ((IMIProcessDMContext)dmc).getProcId();
|
name = fDebuggedProcessNames.get(id);
|
||||||
String name = fProcessNames.get(id);
|
|
||||||
if (name == null) {
|
if (name == null) {
|
||||||
// We don't have the name yet. Maybe we didn't fetch names yet,
|
// We don't have the name in our map. Should not happen.
|
||||||
// or maybe this is a new process
|
name = "Unknown name"; //$NON-NLS-1$
|
||||||
// This is not very efficient, but GDB does not provide a way to get the name
|
|
||||||
// of a single process.
|
|
||||||
ICommandControlDMContext controlDmc = DMContexts.getAncestorOfType(dmc, ICommandControlDMContext.class);
|
|
||||||
fListThreadGroupsAvailableCache.execute(
|
|
||||||
new MIListThreadGroups(controlDmc, true),
|
|
||||||
new DataRequestMonitor<MIListThreadGroupsInfo>(getExecutor(), rm) {
|
|
||||||
@Override
|
|
||||||
protected void handleCompleted() {
|
|
||||||
// We cannot actually cache this command since the process
|
|
||||||
// list may change. But this cache allows to avoid overlapping
|
|
||||||
// sending of this command.
|
|
||||||
fListThreadGroupsAvailableCache.reset();
|
|
||||||
|
|
||||||
String name = null;
|
|
||||||
if (isSuccess()) {
|
|
||||||
for (IThreadGroupInfo groupInfo : getData().getGroupList()) {
|
|
||||||
fProcessNames.put(groupInfo.getPid(), groupInfo.getName());
|
|
||||||
if (groupInfo.getPid().equals(id)) {
|
|
||||||
name = groupInfo.getName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name == null) {
|
|
||||||
// We still don't have the name... weird.
|
|
||||||
// Don't go into an infinite loop by trying again, just give up
|
|
||||||
name = "Unknown name"; //$NON-NLS-1$
|
|
||||||
}
|
|
||||||
rm.setData(new MIThreadDMData(name, id));
|
|
||||||
rm.done();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
} else {
|
|
||||||
rm.setData(new MIThreadDMData(name, id));
|
|
||||||
rm.done();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
rm.setData(new MIThreadDMData(name, id));
|
||||||
|
rm.done();
|
||||||
} else if (dmc instanceof MIThreadDMC) {
|
} else if (dmc instanceof MIThreadDMC) {
|
||||||
final MIThreadDMC threadDmc = (MIThreadDMC)dmc;
|
final MIThreadDMC threadDmc = (MIThreadDMC)dmc;
|
||||||
|
|
||||||
|
@ -741,10 +742,8 @@ public class GDBProcesses_7_0 extends AbstractDsfService
|
||||||
}
|
}
|
||||||
|
|
||||||
private IMIContainerDMContext[] makeContainerDMCs(ICommandControlDMContext controlDmc, IThreadGroupInfo[] groups) {
|
private IMIContainerDMContext[] makeContainerDMCs(ICommandControlDMContext controlDmc, IThreadGroupInfo[] groups) {
|
||||||
IProcessDMContext[] procDmcs = makeProcessDMCs(controlDmc, groups);
|
|
||||||
|
|
||||||
IMIContainerDMContext[] containerDmcs = new IMIContainerDMContext[groups.length];
|
IMIContainerDMContext[] containerDmcs = new IMIContainerDMContext[groups.length];
|
||||||
for (int i = 0; i < procDmcs.length; i++) {
|
for (int i = 0; i < groups.length; i++) {
|
||||||
String groupId = groups[i].getGroupId();
|
String groupId = groups[i].getGroupId();
|
||||||
IProcessDMContext procDmc = createProcessContext(controlDmc, groupId);
|
IProcessDMContext procDmc = createProcessContext(controlDmc, groupId);
|
||||||
containerDmcs[i] = createContainerContext(procDmc, groupId);
|
containerDmcs[i] = createContainerContext(procDmc, groupId);
|
||||||
|
@ -768,10 +767,7 @@ public class GDBProcesses_7_0 extends AbstractDsfService
|
||||||
fListThreadGroupsAvailableCache.reset();
|
fListThreadGroupsAvailableCache.reset();
|
||||||
|
|
||||||
if (isSuccess()) {
|
if (isSuccess()) {
|
||||||
for (IThreadGroupInfo groupInfo : getData().getGroupList()) {
|
rm.setData(makeProcessDMCAndData(controlDmc, getData().getGroupList()));
|
||||||
fProcessNames.put(groupInfo.getPid(), groupInfo.getName());
|
|
||||||
}
|
|
||||||
rm.setData(makeProcessDMCs(controlDmc, getData().getGroupList()));
|
|
||||||
} else {
|
} else {
|
||||||
rm.setData(new IProcessDMContext[0]);
|
rm.setData(new IProcessDMContext[0]);
|
||||||
}
|
}
|
||||||
|
@ -785,10 +781,13 @@ public class GDBProcesses_7_0 extends AbstractDsfService
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private IProcessDMContext[] makeProcessDMCs(ICommandControlDMContext controlDmc, IThreadGroupInfo[] processes) {
|
private MIProcessDMCAndData[] makeProcessDMCAndData(ICommandControlDMContext controlDmc, IThreadGroupInfo[] processes) {
|
||||||
IProcessDMContext[] procDmcs = new IMIProcessDMContext[processes.length];
|
MIProcessDMCAndData[] procDmcs = new MIProcessDMCAndData[processes.length];
|
||||||
for (int i=0; i<procDmcs.length; i++) {
|
for (int i=0; i<procDmcs.length; i++) {
|
||||||
procDmcs[i] = createProcessContext(controlDmc, processes[i].getGroupId());
|
procDmcs[i] = new MIProcessDMCAndData(controlDmc.getSessionId(),
|
||||||
|
controlDmc,
|
||||||
|
processes[i].getGroupId(),
|
||||||
|
processes[i].getName());
|
||||||
}
|
}
|
||||||
return procDmcs;
|
return procDmcs;
|
||||||
}
|
}
|
||||||
|
@ -928,7 +927,29 @@ public class GDBProcesses_7_0 extends AbstractDsfService
|
||||||
}
|
}
|
||||||
|
|
||||||
if (groupId != null) {
|
if (groupId != null) {
|
||||||
if ("thread-group-exited".equals(miEvent)) { //$NON-NLS-1$
|
if ("thread-group-created".equals(miEvent)) { //$NON-NLS-1$
|
||||||
|
// GDB is debugging a new process. Let's fetch its name and remember it.
|
||||||
|
final String finalGroupId = groupId;
|
||||||
|
fListThreadGroupsAvailableCache.execute(
|
||||||
|
new MIListThreadGroups(fCommandControl.getContext(), true),
|
||||||
|
new DataRequestMonitor<MIListThreadGroupsInfo>(getExecutor(), null) {
|
||||||
|
@Override
|
||||||
|
protected void handleCompleted() {
|
||||||
|
// We cannot actually cache this command since the process
|
||||||
|
// list may change. But this cache allows to avoid overlapping
|
||||||
|
// sending of this command.
|
||||||
|
fListThreadGroupsAvailableCache.reset();
|
||||||
|
|
||||||
|
if (isSuccess()) {
|
||||||
|
for (IThreadGroupInfo groupInfo : getData().getGroupList()) {
|
||||||
|
if (groupInfo.getPid().equals(finalGroupId)) {
|
||||||
|
fDebuggedProcessNames.put(groupInfo.getPid(), groupInfo.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if ("thread-group-exited".equals(miEvent)) { //$NON-NLS-1$
|
||||||
// Remove any entries for that group from our thread to group map
|
// 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
|
// When detaching from a group, we won't have received any thread-exited event
|
||||||
// but we don't want to keep those entries.
|
// but we don't want to keep those entries.
|
||||||
|
@ -940,6 +961,9 @@ public class GDBProcesses_7_0 extends AbstractDsfService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GDB is no longer debugging this process. Remove its name.
|
||||||
|
fDebuggedProcessNames.remove(groupId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue