diff options
Diffstat (limited to 'plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/services/TCFDSFNativeProcesses.java')
-rw-r--r-- | plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/services/TCFDSFNativeProcesses.java | 614 |
1 files changed, 614 insertions, 0 deletions
diff --git a/plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/services/TCFDSFNativeProcesses.java b/plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/services/TCFDSFNativeProcesses.java new file mode 100644 index 000000000..b1f66dde4 --- /dev/null +++ b/plugins/org.eclipse.tm.tcf.dsf/src/org/eclipse/tm/internal/tcf/dsf/services/TCFDSFNativeProcesses.java @@ -0,0 +1,614 @@ +/******************************************************************************* + * Copyright (c) 2007, 2008 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.internal.tcf.dsf.services; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Map; +import java.util.Set; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; +import org.eclipse.dd.dsf.datamodel.AbstractDMEvent; +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.datamodel.ServiceDMContext; +import org.eclipse.dd.dsf.debug.service.INativeProcesses; +import org.eclipse.dd.dsf.service.AbstractDsfService; +import org.eclipse.dd.dsf.service.DsfSession; +import org.eclipse.tm.internal.tcf.dsf.Activator; +import org.eclipse.tm.tcf.protocol.IChannel; +import org.eclipse.tm.tcf.protocol.IToken; +import org.eclipse.tm.tcf.services.IProcesses; +import org.eclipse.tm.tcf.services.IRunControl; +import org.eclipse.tm.tcf.services.IProcesses.ProcessContext; +import org.eclipse.tm.tcf.services.IRunControl.RunControlContext; +import org.osgi.framework.BundleContext; + + +public class TCFDSFNativeProcesses extends AbstractDsfService implements INativeProcesses { + + private class ProcessDMC extends TCFDSFProcessDMC implements IProcessDMContext { + + final String id; + + ProcessDMC(String id, IDMContext parent) { + super(TCFDSFNativeProcesses.this, parent != null ? new IDMContext[]{ parent } : new IDMContext[0]); + this.id = id; + } + + @Override + public String toString() { + return baseToString() + ".context[" + id + "]"; //$NON-NLS-1$ //$NON-NLS-2$ + } + + @Override + public boolean equals(Object obj) { + if (!super.baseEquals(obj)) return false; + String obj_id = ((ProcessDMC)obj).id; + if (obj_id == null) return id == null; + return obj_id.equals(id); + } + + @Override + public int hashCode() { + if (id == null) return 0; + return id.hashCode(); + } + } + + private class ThreadDMC extends TCFDSFThreadDMC implements IThreadDMContext { + + final String id; + + ThreadDMC(String id) { + super(TCFDSFNativeProcesses.this, new IDMContext[0]); + this.id = id; + } + + @Override + public String toString() { + return baseToString() + ".context[" + id + "]"; //$NON-NLS-1$ //$NON-NLS-2$ + } + + @Override + public boolean equals(Object obj) { + if (!super.baseEquals(obj)) return false; + String obj_id = ((ThreadDMC)obj).id; + if (obj_id == null) return id == null; + return obj_id.equals(id); + } + + @Override + public int hashCode() { + return id.hashCode(); + } + } + + private class ProcessData implements IProcessDMData { + + private final IProcesses.ProcessContext ctx; + + ProcessData(IProcesses.ProcessContext ctx) { + this.ctx = ctx; + } + + public IDMContext getDebugContext() { + return getServicesTracker().getService(TCFDSFRunControl.class).getContext(ctx.getID()); + } + + public String getId() { + return ctx.getID(); + } + + public String getName() { + return ctx.getName(); + } + + public boolean isDebuggerAttached() { + return ctx.isAttached(); + } + + public boolean isValid() { + return true; + } + } + + private class ThreadData implements IThreadDMData { + + private final TCFDSFExecutionDMC ctx; + + ThreadData(TCFDSFExecutionDMC ctx) { + this.ctx = ctx; + } + + public IDMContext getDebugContext() { + return ctx; + } + + public String getId() { + if (ctx == null) return null; + return ctx.getTcfContextId(); + } + + public String getName() { + // TODO thread name + return ""; + } + + public boolean isDebuggerAttached() { + return true; + } + + public boolean isValid() { + return true; + } + } + + private class ProcessStartedEvent extends AbstractDMEvent<IDMContext> implements IProcessStartedEvent { + + private final IProcessDMContext prs; + + ProcessStartedEvent(IDMContext dmc, IProcessDMContext prs) { + super(dmc); + this.prs = prs; + } + + public IProcessDMContext getProcess() { + return prs; + } + } + + private class ProcessExitedEvent extends AbstractDMEvent<IDMContext> implements IProcessExitedEvent { + + private final IProcessDMContext prs; + + ProcessExitedEvent(IDMContext dmc, IProcessDMContext prs) { + super(dmc); + this.prs = prs; + } + + public IProcessDMContext getProcess() { + return prs; + } + } + + private final org.eclipse.tm.tcf.services.IRunControl.RunControlListener run_listener = + new org.eclipse.tm.tcf.services.IRunControl.RunControlListener() { + + public void containerResumed(String[] context_ids) { + } + + public void containerSuspended(String context, String pc, + String reason, Map<String, Object> params, + String[] suspended_ids) { + } + + public void contextAdded(RunControlContext[] contexts) { + for (RunControlContext ctx : contexts) { + String id = ctx.getID(); + if (id.equals(ctx.getProperties().get(IRunControl.PROP_PROCESS_ID))) { + ProcessDMC dmc = new ProcessDMC(id, root_dmc); + process_cache.put(id, dmc); + getSession().dispatchEvent(new ProcessStartedEvent(root_dmc, dmc), getProperties()); + } + else { + ThreadDMC dmc = new ThreadDMC(id); + thread_cache.put(id, dmc); + } + } + } + + public void contextChanged(RunControlContext[] contexts) { + } + + public void contextException(String context, String msg) { + } + + public void contextRemoved(String[] context_ids) { + for (String id : context_ids) { + ProcessDMC dmc = process_cache.remove(id); + if (dmc != null) { + getSession().dispatchEvent(new ProcessExitedEvent(root_dmc, dmc), getProperties()); + } + else { + thread_cache.remove(id); + } + } + } + + public void contextResumed(String context) { + } + + public void contextSuspended(String context, String pc, + String reason, Map<String, Object> params) { + } + }; + + private final IProcesses tcf_prs_service; + private final org.eclipse.tm.tcf.services.IRunControl tcf_run_service; + private final Map<String,ProcessDMC> process_cache = new HashMap<String,ProcessDMC>(); // all attached processes + private final Map<String,ThreadDMC> thread_cache = new HashMap<String,ThreadDMC>(); // only some of attached threads + private final ProcessDMC root_dmc = new ProcessDMC(null, null); + private IDMContext service_dmc; + + public TCFDSFNativeProcesses(DsfSession session, IChannel channel, final RequestMonitor monitor) { + super(session); + tcf_prs_service = channel.getRemoteService(IProcesses.class); + tcf_run_service = channel.getRemoteService(org.eclipse.tm.tcf.services.IRunControl.class); + if (tcf_run_service != null) tcf_run_service.addListener(run_listener); + service_dmc = new ServiceDMContext(this, "#native_process"); + initialize(new RequestMonitor(getExecutor(), monitor) { + @Override + protected void handleOK() { + String[] class_names = { + INativeProcesses.class.getName(), + TCFDSFNativeProcesses.class.getName() + }; + register(class_names, new Hashtable<String,String>()); + monitor.done(); + } + }); + } + + @Override + public void initialize(final RequestMonitor monitor) { + final Collection<String> list = new ArrayList<String>(); + final Set<IToken> cmds = new HashSet<IToken>(); + final IProcesses.DoneGetChildren done = new IProcesses.DoneGetChildren() { + public void doneGetChildren(IToken token, Exception error, String[] context_ids) { + if (cmds.isEmpty()) return; + assert cmds.contains(token); + cmds.remove(token); + if (error != null) { + for (IToken t : cmds) t.cancel(); + cmds.clear(); + monitor.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID, + REQUEST_FAILED, "Command error", error)); //$NON-NLS-1$ + monitor.done(); + } + else { + for (String id : context_ids) { + list.add(id); + cmds.add(tcf_prs_service.getChildren(id, true, this)); + } + if (cmds.isEmpty()) { + for (String id : list) { + assert id != null; + if (process_cache.get(id) != null) continue; + process_cache.put(id, new ProcessDMC(id, root_dmc)); + } + process_cache.put(null, root_dmc); + TCFDSFNativeProcesses.super.initialize(monitor); + } + } + } + }; + cmds.add(tcf_prs_service.getChildren(null, true, done)); + } + + @Override + public void shutdown(RequestMonitor monitor) { + unregister(); + super.shutdown(monitor); + } + + @Override + protected BundleContext getBundleContext() { + return Activator.getBundleContext(); + } + + public IDMContext getServiceContext() { + return service_dmc; + } + + public boolean isValid() { + return true; + } + + public void attachDebuggerToProcess(IProcessDMContext ctx, final RequestMonitor rm) { + if (tcf_prs_service == null) { + rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID, + REQUEST_FAILED, "Service not available", null)); //$NON-NLS-1$ + rm.done(); + } + else if (ctx instanceof ProcessDMC) { + final ProcessDMC p = (ProcessDMC)ctx; + tcf_prs_service.getContext(p.id, new IProcesses.DoneGetContext() { + public void doneGetContext(IToken token, Exception error, ProcessContext context) { + if (rm.isCanceled()) return; + if (error != null) { + rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID, + REQUEST_FAILED, "Cannot read processs attributes", error)); //$NON-NLS-1$ + rm.done(); + } + else if (context == null) { + rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID, + REQUEST_FAILED, "Invalid processs ID", error)); //$NON-NLS-1$ + rm.done(); + } + else { + context.attach(new IProcesses.DoneCommand() { + public void doneCommand(IToken token, Exception error) { + if (rm.isCanceled()) return; + if (error != null) { + rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID, + REQUEST_FAILED, "Cannot attach a process", error)); //$NON-NLS-1$ + } + assert error != null || process_cache.get(p.id) != null; + rm.done(); + } + }); + } + } + }); + } + else { + rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID, + INVALID_HANDLE, "Unknown DMC type", null)); //$NON-NLS-1$ + rm.done(); + } + } + + public void canTerminate(IDMContext ctx, final DataRequestMonitor<Boolean> rm) { + rm.setData(false); + if (tcf_prs_service == null) { + rm.done(); + } + else if (ctx instanceof ProcessDMC) { + ProcessDMC p = (ProcessDMC)ctx; + tcf_prs_service.getContext(p.id, new IProcesses.DoneGetContext() { + public void doneGetContext(IToken token, Exception error, ProcessContext context) { + if (rm.isCanceled()) return; + if (error != null) { + rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID, + REQUEST_FAILED, "Cannot read processs attributes", error)); //$NON-NLS-1$ + } + else if (context == null) { + rm.setData(false); + } + else { + rm.setData(context.canTerminate()); + } + rm.done(); + } + }); + } + else { + rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID, + INVALID_HANDLE, "Unknown DMC type", null)); //$NON-NLS-1$ + rm.done(); + } + } + + public void terminate(IDMContext ctx, final RequestMonitor rm) { + if (tcf_prs_service == null) { + rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID, + REQUEST_FAILED, "Service not available", null)); //$NON-NLS-1$ + rm.done(); + } + else if (ctx instanceof ProcessDMC) { + ProcessDMC p = (ProcessDMC)ctx; + tcf_prs_service.getContext(p.id, new IProcesses.DoneGetContext() { + public void doneGetContext(IToken token, Exception error, ProcessContext context) { + if (rm.isCanceled()) return; + if (error != null) { + rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID, + REQUEST_FAILED, "Cannot read processs attributes", error)); //$NON-NLS-1$ + rm.done(); + } + else if (context == null) { + rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID, + REQUEST_FAILED, "Invalid processs ID", error)); //$NON-NLS-1$ + rm.done(); + } + else { + context.terminate(new IProcesses.DoneCommand() { + public void doneCommand(IToken token, Exception error) { + if (rm.isCanceled()) return; + if (error != null) { + rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID, + REQUEST_FAILED, "Cannot terminate a process", error)); //$NON-NLS-1$ + } + rm.done(); + } + }); + } + } + }); + } + else { + rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID, + INVALID_HANDLE, "Unknown DMC type", null)); //$NON-NLS-1$ + rm.done(); + } + } + + public void debugNewProcess(String file, final DataRequestMonitor<IProcessDMContext> rm) { + if (tcf_prs_service == null) { + rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID, + REQUEST_FAILED, "Service not available", null)); //$NON-NLS-1$ + rm.done(); + } + else { + tcf_prs_service.start(null, file, null, null, true, new IProcesses.DoneStart() { + public void doneStart(IToken token, Exception error, ProcessContext process) { + if (error != null) { + rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID, + REQUEST_FAILED, "Cannot start a process", error)); //$NON-NLS-1$ + } + else { + ProcessDMC dmc = process_cache.get(process.getID()); + assert dmc != null; + rm.setData(dmc); + } + rm.done(); + } + }); + } + } + + public void runNewProcess(String file, final DataRequestMonitor<IProcessDMContext> rm) { + if (tcf_prs_service == null) { + rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID, + REQUEST_FAILED, "Service not available", null)); //$NON-NLS-1$ + rm.done(); + } + else { + tcf_prs_service.start(null, file, null, null, false, new IProcesses.DoneStart() { + public void doneStart(IToken token, Exception error, ProcessContext process) { + if (error != null) { + rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID, + REQUEST_FAILED, "Cannot start a process", error)); //$NON-NLS-1$ + } + else { + assert process_cache.get(process.getID()) == null; + rm.setData(new ProcessDMC(process.getID(), root_dmc)); + } + rm.done(); + } + }); + } + } + + public IProcessDMContext getProcessForDebugContext(IDMContext ctx) { + if (ctx instanceof IProcessDMContext) { + return (IProcessDMContext)ctx; + } + if (ctx instanceof TCFDSFExecutionDMC) { + String id = ((TCFDSFExecutionDMC)ctx).getTcfContextId(); + return process_cache.get(id); + } + return null; + } + + public IThreadDMContext getThreadForDebugContext(IDMContext ctx) { + if (ctx instanceof IThreadDMContext) { + return (IThreadDMContext)ctx; + } + if (ctx instanceof TCFDSFExecutionDMC) { + String id = ((TCFDSFExecutionDMC)ctx).getTcfContextId(); + ThreadDMC dmc = thread_cache.get(id); + if (dmc == null) dmc = new ThreadDMC(id); + return dmc; + } + return null; + } + + public void getProcessesBeingDebugged(DataRequestMonitor<IProcessDMContext[]> rm) { + rm.setData(process_cache.values().toArray(new IProcessDMContext[process_cache.size()])); + rm.done(); + } + + public void getRunningProcesses(final DataRequestMonitor<IProcessDMContext[]> rm) { + final Collection<String> list = new ArrayList<String>(); + final Set<IToken> cmds = new HashSet<IToken>(); + final IProcesses.DoneGetChildren done = new IProcesses.DoneGetChildren() { + public void doneGetChildren(IToken token, Exception error, String[] context_ids) { + if (cmds.isEmpty()) return; + assert cmds.contains(token); + cmds.remove(token); + if (error != null) { + for (IToken t : cmds) t.cancel(); + cmds.clear(); + rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID, + REQUEST_FAILED, "Command error", error)); //$NON-NLS-1$ + rm.done(); + } + else { + for (String id : context_ids) { + list.add(id); + cmds.add(tcf_prs_service.getChildren(id, false, this)); + } + if (cmds.isEmpty()) { + int cnt = 0; + IProcessDMContext[] data = new IProcessDMContext[list.size()]; + for (String id : list) { + assert id != null; + data[cnt] = process_cache.get(id); + if (data[cnt] == null) data[cnt] = new ProcessDMC(id, root_dmc); + cnt++; + } + rm.setData(data); + rm.done(); + } + } + } + }; + cmds.add(tcf_prs_service.getChildren(null, false, done)); + } + + @SuppressWarnings("unchecked") + public void getModelData(IDMContext dmc, final DataRequestMonitor<?> rm) { + if (dmc instanceof ProcessDMC) { + getProcessData((ProcessDMC)dmc, (DataRequestMonitor<IProcessDMData>)rm); + } + else if (dmc instanceof ThreadDMC) { + getThreadData((ThreadDMC)dmc, (DataRequestMonitor<IThreadDMData>)rm); + } + else if (dmc == service_dmc) { + ((DataRequestMonitor<TCFDSFNativeProcesses>)rm).setData(this); + rm.done(); + } + else { + rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID, + INVALID_HANDLE, "Unknown DMC type", null)); //$NON-NLS-1$ + rm.done(); + } + } + + public void getProcessData(IProcessDMContext dmc, final DataRequestMonitor<IProcessDMData> rm) { + if (dmc instanceof ProcessDMC) { + tcf_prs_service.getContext(((ProcessDMC)dmc).id, new IProcesses.DoneGetContext() { + + @SuppressWarnings("unchecked") + public void doneGetContext(IToken token, Exception error, ProcessContext context) { + if (rm.isCanceled()) return; + if (error != null) { + rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID, + REQUEST_FAILED, "Cannot read processs attributes", error)); //$NON-NLS-1$ + } + else if (context == null) { + rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID, + REQUEST_FAILED, "Invalid processs ID", error)); //$NON-NLS-1$ + } + else { + rm.setData(new ProcessData(context)); + } + rm.done(); + } + }); + } + else { + rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID, + INVALID_HANDLE, "Unknown DMC type", null)); //$NON-NLS-1$ + rm.done(); + } + } + + public void getThreadData(IThreadDMContext dmc, final DataRequestMonitor<IThreadDMData> rm) { + if (dmc instanceof ThreadDMC) { + String id = ((ThreadDMC)dmc).id; + TCFDSFRunControl rc = getServicesTracker().getService(TCFDSFRunControl.class); + rm.setData(new ThreadData(rc.getContext(id))); + rm.done(); + } + else { + rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID, + INVALID_HANDLE, "Unknown DMC type", null)); //$NON-NLS-1$ + rm.done(); + } + } +} |