From 87515ad676ff7a0957fdf54dc0bee192cc5d1bd8 Mon Sep 17 00:00:00 2001 From: Marc Khouzam Date: Thu, 10 Mar 2011 21:28:59 +0000 Subject: [PATCH] Bug 237306: Support for Multi-Process debugging. Add a "New..." button to the "Attach dialog" to allow creating a new process from a running session. --- .../ui/actions/GdbConnectCommand.java | 52 ++++++++++++++----- .../ui/launching/LaunchUIMessages.properties | 5 ++ .../ui/launching/ProcessPrompter.java | 37 +++++++++---- .../ui/launching/ProcessPrompterDialog.java | 46 ++++++++++++++++ 4 files changed, 118 insertions(+), 22 deletions(-) create mode 100644 dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/launching/ProcessPrompterDialog.java diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/actions/GdbConnectCommand.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/actions/GdbConnectCommand.java index a9efcf9ad8f..b6a45f8f4ce 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/actions/GdbConnectCommand.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/actions/GdbConnectCommand.java @@ -11,6 +11,7 @@ package org.eclipse.cdt.dsf.gdb.internal.ui.actions; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.RejectedExecutionException; @@ -19,6 +20,7 @@ import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor; import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; import org.eclipse.cdt.dsf.concurrent.DsfExecutor; import org.eclipse.cdt.dsf.concurrent.DsfRunnable; +import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants; import org.eclipse.cdt.dsf.concurrent.Query; import org.eclipse.cdt.dsf.concurrent.RequestMonitor; import org.eclipse.cdt.dsf.datamodel.IDMContext; @@ -29,6 +31,7 @@ import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService; import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext; import org.eclipse.cdt.dsf.gdb.actions.IConnect; import org.eclipse.cdt.dsf.gdb.internal.ui.GdbUIPlugin; +import org.eclipse.cdt.dsf.gdb.internal.ui.launching.ProcessPrompter.PrompterInfo; import org.eclipse.cdt.dsf.gdb.launching.IProcessExtendedInfo; import org.eclipse.cdt.dsf.gdb.launching.LaunchMessages; import org.eclipse.cdt.dsf.gdb.service.IGDBProcesses.IGdbThreadDMData; @@ -85,14 +88,16 @@ public class GdbConnectCommand implements IConnect { } // Need a job because prompter.handleStatus will block - class PromptForPidJob extends Job { + protected class PromptForPidJob extends Job { // The list of processes used in the case of an ATTACH session IProcessExtendedInfo[] fProcessList = null; - DataRequestMonitor fRequestMonitor; + DataRequestMonitor fRequestMonitor; + boolean fNewProcessSupported; - public PromptForPidJob(String name, IProcessExtendedInfo[] procs, DataRequestMonitor rm) { + public PromptForPidJob(String name, boolean newProcessSupported, IProcessExtendedInfo[] procs, DataRequestMonitor rm) { super(name); + fNewProcessSupported = newProcessSupported; fProcessList = procs; fRequestMonitor = rm; } @@ -115,10 +120,11 @@ public class GdbConnectCommand implements IConnect { } try { - Object result = prompter.handleStatus(processPromptStatus, fProcessList); - if (result instanceof Integer) { - fRequestMonitor.setData((Integer)result); - } else { + PrompterInfo info = new PrompterInfo(fNewProcessSupported, fProcessList); + Object result = prompter.handleStatus(processPromptStatus, info); + if (result instanceof Integer || result instanceof String) { + fRequestMonitor.setData(result); + } else { fRequestMonitor.setStatus(NO_PID_STATUS); } } catch (CoreException e) { @@ -151,7 +157,12 @@ public class GdbConnectCommand implements IConnect { ICommandControlService commandControl = fTracker.getService(ICommandControlService.class); if (procService != null && commandControl != null) { - final ICommandControlDMContext controlCtx = commandControl.getContext(); + final ICommandControlDMContext controlCtx = commandControl.getContext(); + procService.isDebugNewProcessSupported(controlCtx, new DataRequestMonitor(fExecutor, null) { + @Override + protected void handleCompleted() { + final boolean newProcessSupported = isSuccess() && getData(); + procService.getRunningProcesses( controlCtx, new DataRequestMonitor(fExecutor, rm) { @@ -165,16 +176,29 @@ public class GdbConnectCommand implements IConnect { @Override protected void handleSuccess() { new PromptForPidJob( - "Prompt for Process", procInfoList.toArray(new IProcessExtendedInfo[0]), //$NON-NLS-1$ - new DataRequestMonitor(fExecutor, rm) { + "Prompt for Process", newProcessSupported, procInfoList.toArray(new IProcessExtendedInfo[0]), //$NON-NLS-1$ + new DataRequestMonitor(fExecutor, rm) { @Override protected void handleSuccess() { // New cycle, look for service again final IMIProcesses procService = fTracker.getService(IMIProcesses.class); if (procService != null) { - IProcessDMContext procDmc = procService.createProcessContext(controlCtx, - Integer.toString(getData())); - procService.attachDebuggerToProcess(procDmc, new DataRequestMonitor(fExecutor, rm)); + Object data = getData(); + if (data instanceof String) { + // User wants to start a new process + String binaryPath = (String)data; + procService.debugNewProcess( + controlCtx, binaryPath, + // khouzam, maybe we should at least pass stopOnMain? + new HashMap(), new DataRequestMonitor(fExecutor, rm)); + } else if (data instanceof Integer) { + IProcessDMContext procDmc = procService.createProcessContext(controlCtx, + Integer.toString((Integer)getData())); + procService.attachDebuggerToProcess(procDmc, new DataRequestMonitor(fExecutor, rm)); + } else { + rm.setStatus(new Status(IStatus.ERROR, GdbUIPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, "Invalid return type for process prompter", null)); //$NON-NLS-1$ + rm.done(); + } } } }).schedule(); @@ -246,6 +270,8 @@ public class GdbConnectCommand implements IConnect { } } }); + } + }); } else { rm.done(); } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/launching/LaunchUIMessages.properties b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/launching/LaunchUIMessages.properties index 139d2cf857a..01ff2183232 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/launching/LaunchUIMessages.properties +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/launching/LaunchUIMessages.properties @@ -222,3 +222,8 @@ LocalCDILaunchDelegate.7=Core file does not exist or is not readable. LocalCDILaunchDelegate.8=Error starting process. LocalCDILaunchDelegate.9=Eclipse runtime does not support working directory. LocalCDILaunchDelegate.10=Failed to set program arguments, environment or working directory. + +ProcessPrompter.Core=core +ProcessPrompter.Cores=cores +ProcessPrompterDialog.New=New... + diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/launching/ProcessPrompter.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/launching/ProcessPrompter.java index 81298f4c769..8d75ccf1ba5 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/launching/ProcessPrompter.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/launching/ProcessPrompter.java @@ -28,17 +28,26 @@ import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.window.Window; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Shell; -import org.eclipse.ui.dialogs.TwoPaneElementSelector; public class ProcessPrompter implements IStatusHandler { + public static class PrompterInfo { + public boolean supportsNewProcess; + public IProcessExtendedInfo[] processList; + + public PrompterInfo(boolean supportsNew, IProcessExtendedInfo[] list) { + supportsNewProcess = supportsNew; + processList = list; + } + } + /* * (non-Javadoc) * * @see org.eclipse.debug.core.IStatusHandler#handleStatus(org.eclipse.core.runtime.IStatus, * java.lang.Object) */ - public Object handleStatus(IStatus status, Object processList) throws CoreException { + public Object handleStatus(IStatus status, Object info) throws CoreException { Shell shell = GdbUIPlugin.getShell(); if (shell == null) { IStatus error = new Status(IStatus.ERROR, GdbUIPlugin.getUniqueIdentifier(), @@ -47,7 +56,8 @@ public class ProcessPrompter implements IStatusHandler { throw new CoreException(error); } - IProcessExtendedInfo[] plist = (IProcessExtendedInfo[])processList; + PrompterInfo prompterInfo = (PrompterInfo) info; + IProcessExtendedInfo[] plist = prompterInfo.processList; if (plist == null) { MessageDialog.openError( shell, @@ -91,11 +101,14 @@ public class ProcessPrompter implements IStatusHandler { String[] cores = info.getCores(); if (cores != null && cores.length > 0) { + String coreStr; if (cores.length == 1) { - text.append(" [core: "); + coreStr = LaunchUIMessages.getString("ProcessPrompter.Core"); //$NON-NLS-1$ } else { - text.append(" [cores: "); + coreStr = LaunchUIMessages.getString("ProcessPrompter.Cores"); //$NON-NLS-1$ } + text.append(" [" + coreStr + ": "); //$NON-NLS-1$//$NON-NLS-2$ + for (String core : cores) { text.append(core + ", "); //$NON-NLS-1$ } @@ -133,15 +146,21 @@ public class ProcessPrompter implements IStatusHandler { }; // Display the list of processes and have the user choose - TwoPaneElementSelector dialog = new TwoPaneElementSelector(shell, provider, qprovider); + ProcessPrompterDialog dialog = new ProcessPrompterDialog(shell, provider, qprovider, prompterInfo.supportsNewProcess); dialog.setTitle(LaunchMessages.getString("LocalAttachLaunchDelegate.Select_Process")); //$NON-NLS-1$ dialog.setMessage(LaunchMessages.getString("LocalAttachLaunchDelegate.Select_Process_to_attach_debugger_to")); //$NON-NLS-1$ dialog.setElements(plist); if (dialog.open() == Window.OK) { - IProcessExtendedInfo info = (IProcessExtendedInfo)dialog.getFirstResult(); - if (info != null) { - return new Integer(info.getPid()); + // First check if the user pressed the New button + String binaryPath = dialog.getBinaryPath(); + if (binaryPath != null) { + return binaryPath; + } + + IProcessExtendedInfo processInfo = (IProcessExtendedInfo)dialog.getFirstResult(); + if (processInfo != null) { + return new Integer(processInfo.getPid()); } } } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/launching/ProcessPrompterDialog.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/launching/ProcessPrompterDialog.java new file mode 100644 index 00000000000..9e5dbb6111c --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/launching/ProcessPrompterDialog.java @@ -0,0 +1,46 @@ +package org.eclipse.cdt.dsf.gdb.internal.ui.launching; + +import org.eclipse.jface.viewers.ILabelProvider; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.FileDialog; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.dialogs.TwoPaneElementSelector; + +public class ProcessPrompterDialog extends TwoPaneElementSelector { + private static final int NEW_BUTTON_ID = 9876; + private String fBinaryPath; + private boolean fSupportsNewProcess; + + public ProcessPrompterDialog(Shell parent, ILabelProvider elementRenderer, + ILabelProvider qualifierRenderer, boolean supportsNewProcess) { + super(parent, elementRenderer, qualifierRenderer); + fSupportsNewProcess = supportsNewProcess; + } + + @Override + protected void createButtonsForButtonBar(Composite parent) { + Button newButton = createButton( + parent, NEW_BUTTON_ID, LaunchUIMessages.getString("ProcessPrompterDialog.New"), false); //$NON-NLS-1$ + newButton.setEnabled(fSupportsNewProcess); + super.createButtonsForButtonBar(parent); + } + + @Override + protected void buttonPressed(int buttonId) { + if (buttonId == NEW_BUTTON_ID) { + FileDialog fd = new FileDialog(getShell(), SWT.SAVE); + fBinaryPath = fd.open(); + + setReturnCode(OK); + close(); + } + super.buttonPressed(buttonId); + } + + public String getBinaryPath() { + return fBinaryPath; + } + +}