From 25a42fbdce188bcfbb60f1207807f9067f232677 Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Fri, 8 Jul 2016 17:13:59 -0400 Subject: [PATCH] Bug 497592 - Wait for request to GDB for inferior name to be completed GDBProcesses_7_0 would fetch the name of a process as soon as it learned of the process through the =thread-group-started event; however, if there was a call to IProcesses.getExecutionData() before the name was received, the service would return the wrong name. This commit fetches the name when IProcesses.getExecutionData() and uses a CommandCache to do it. That way, if a call to IProcesses.getExecutionData() is made before the name is received, the request will be cached until the name is available. Furthermore, the cache allows to handle the case where the target is unavailable, which can happen in all-stop mode and we disabled stopping at main. Change-Id: Ia75d3c677e189f87e9ec2864c744a870a0a18407 --- .../cdt/dsf/gdb/service/GDBProcesses_7_0.java | 147 +++++++++++------- 1 file changed, 88 insertions(+), 59 deletions(-) diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses_7_0.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses_7_0.java index 8af114956c7..18db6225464 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses_7_0.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBProcesses_7_0.java @@ -575,7 +575,8 @@ public class GDBProcesses_7_0 extends AbstractDsfService // change at any time. However, it is inefficient to send more than one of this command at // the same time. This cache will help us avoid that. The idea is that we cache the command, // but as soon as it returns, we clear the cache. So the cache will only trigger for those - // overlapping situations. + // overlapping situations. Using this cache also allows to handle the all-stop case + // when the target can be unavailable and instead of hanging, the cache will return an error. private CommandCache fListThreadGroupsAvailableCache; // A map of process id to process names. A name is fetched whenever we start @@ -960,19 +961,85 @@ public class GDBProcesses_7_0 extends AbstractDsfService // I haven't found a good way to get the pid yet, so let's not show it. id = null; } else { - name = fDebuggedProcessesAndNames.get(id); - if (name == null) { + if (fDebuggedProcessesAndNames.containsKey(id)) { + name = fDebuggedProcessesAndNames.get(id); + assert name != null; + if (name == null) { + // Should not happen, but just in case...use the + // binary file name (absolute path) + name = fBackend.getProgramPath().toOSString(); + fDebuggedProcessesAndNames.put(id, name); + } else if (name.isEmpty()) { + // We know of the process but haven't fetched its name yet. + // Let's fetch it now. + // GDB is debugging a new process. Let's fetch its + // name and remember it. In order to get the name, + // we have to request all running processes, not + // just the ones being debugged. We got a lot more + // information when we request all processes. + final String finalPId = id; + fListThreadGroupsAvailableCache.execute( + fCommandFactory.createMIListThreadGroups(fCommandControl.getContext(), true), + new DataRequestMonitor(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 and proper handling if the target is + // unavailable. + fListThreadGroupsAvailableCache.reset(); + + // Note that the output of the "-list-thread-groups --available" command + // still shows the pid as a groupId, even for GDB 7.2. + String name = null; + if (isSuccess()) { + for (IThreadGroupInfo groupInfo : getData().getGroupList()) { + if (groupInfo.getPid().equals(finalPId)) { + name = groupInfo.getName(); + fDebuggedProcessesAndNames.put(finalPId, name); + break; + } + } + } else { + // Looks like this gdb doesn't truly support + // "-list-thread-groups --available". Get the + // process list natively if we're debugging locally + if (fBackend.getSessionType() == SessionType.LOCAL) { + try { + IProcessList list = CCorePlugin.getDefault().getProcessList(); + if (list != null) { + int pId_int = Integer.parseInt(finalPId); + for (IProcessInfo procInfo : list.getProcessList()) { + if (procInfo.getPid() == pId_int) { + name = procInfo.getName(); + fDebuggedProcessesAndNames.put(finalPId, name); + break; + } + } + } + } catch (Exception e) { + rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, "Could not get process name", e)); //$NON-NLS-1$ + } + } + } + + if (name == null) { + // No way to get the name right now, so use the binary file name (absolute path) + name = fBackend.getProgramPath().toOSString(); + fDebuggedProcessesAndNames.put(finalPId, name); + } + rm.done(new MIThreadDMData(name, finalPId)); + } + }); + return; + } + } else { // We don't have the name in our map. This could happen // if a process has terminated but the // debug session is not terminated because the preference // to keep GDB running has been selected or because there // are other processes part of that session. - name = "Unknown name"; //$NON-NLS-1$ - } else if (name.length() == 0) { - // Probably will not happen, but just in case...use the - // binary file name (absolute path) - name = fBackend.getProgramPath().toOSString(); - fDebuggedProcessesAndNames.put(id, name); + name = "Unknown name"; //$NON-NLS-1$ } } rm.setData(new MIThreadDMData(name, id)); @@ -1733,6 +1800,7 @@ public class GDBProcesses_7_0 extends AbstractDsfService // This will happen in all-stop mode fContainerCommandCache.setContextAvailable(e.getDMContext(), false); fThreadCommandCache.setContextAvailable(e.getDMContext(), false); + fListThreadGroupsAvailableCache.setContextAvailable(e.getDMContext(), false); } else { // This will happen in non-stop mode // Keep target available for Container commands @@ -1746,6 +1814,7 @@ public class GDBProcesses_7_0 extends AbstractDsfService // This will happen in all-stop mode fContainerCommandCache.setContextAvailable(fCommandControl.getContext(), true); fThreadCommandCache.setContextAvailable(fCommandControl.getContext(), true); + fListThreadGroupsAvailableCache.setContextAvailable(fCommandControl.getContext(), true); } else { // This will happen in non-stop mode } @@ -1806,6 +1875,11 @@ public class GDBProcesses_7_0 extends AbstractDsfService public void flushCache(IDMContext context) { fContainerCommandCache.reset(context); fThreadCommandCache.reset(context); + // Not technically needed since we are supposed to have + // cleared this cache as soon as the it gets the answer + // from GDB; but to be more future-proof, might as well + // clear it here also. + fListThreadGroupsAvailableCache.reset(context); } /* @@ -1870,57 +1944,12 @@ public class GDBProcesses_7_0 extends AbstractDsfService } if (groupId != null) { - getGroupToPidMap().put(groupId, pId); - - fDebuggedProcessesAndNames.put(pId, ""); //$NON-NLS-1$ - - // GDB is debugging a new process. Let's fetch its - // name and remember it. In order to get the name, - // we have to request all running processes, not - // just the ones being debugged. We got a lot more - // information when we request all processes. - final String finalPId = pId; - fListThreadGroupsAvailableCache.execute( - fCommandFactory.createMIListThreadGroups(fCommandControl.getContext(), true), - new DataRequestMonitor(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(); + getGroupToPidMap().put(groupId, pId); - // Note that the output of the "-list-thread-groups --available" command - // still shows the pid as a groupId, even for GDB 7.2. - if (isSuccess()) { - for (IThreadGroupInfo groupInfo : getData().getGroupList()) { - if (groupInfo.getPid().equals(finalPId)) { - fDebuggedProcessesAndNames.put(finalPId, groupInfo.getName()); - } - } - } - else { - // Looks like this gdb doesn't truly support - // "-list-thread-groups --available". Get the - // process list natively if we're debugging locally - if (fBackend.getSessionType() == SessionType.LOCAL) { - IProcessList list = null; - try { - list = CCorePlugin.getDefault().getProcessList(); - int pId_int = Integer.parseInt(finalPId); - for (IProcessInfo procInfo : list.getProcessList()) { - if (procInfo.getPid() == pId_int) { - fDebuggedProcessesAndNames.put(finalPId, procInfo.getName()); - break; - } - } - } catch (CoreException e) { - } - } - } - } - }); - } + // Mark that we know this new process, but don't fetch its + // name until it is requested. + fDebuggedProcessesAndNames.put(pId, ""); //$NON-NLS-1$ + } } else if ("thread-group-exited".equals(miEvent)) { //$NON-NLS-1$ String groupId = null;