From: wonhyoung2.park Date: Mon, 12 Dec 2011 08:17:55 +0000 (+0900) Subject: [TITLE] profile stop routine modify X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=166cc0ec497cbebca61fdeb3d71e718b1e029434;p=sdk%2Fide%2Fprofiler-eplugin.git [TITLE] profile stop routine modify [Type] [Module] Profiler [Priority] [CQ#] [Redmine#] [Problem] [Cause] [Solution] [TestCase] --- diff --git a/org.eclipse.linuxtools.oprofile.launch.exe/src/com/samsung/tizen/oprofile/launch/OprofileDebugPlugin.java b/org.eclipse.linuxtools.oprofile.launch.exe/src/com/samsung/tizen/oprofile/launch/OprofileDebugPlugin.java new file mode 100644 index 0000000..7d873ee --- /dev/null +++ b/org.eclipse.linuxtools.oprofile.launch.exe/src/com/samsung/tizen/oprofile/launch/OprofileDebugPlugin.java @@ -0,0 +1,1596 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package com.samsung.tizen.oprofile.launch; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.FactoryConfigurationError; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.TransformerException; + +import org.eclipse.core.resources.ISaveContext; +import org.eclipse.core.resources.ISaveParticipant; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IAdapterManager; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExtensionPoint; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.ISafeRunnable; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.ListenerList; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.PlatformObject; +import org.eclipse.core.runtime.Plugin; +import org.eclipse.core.runtime.SafeRunner; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.debug.core.DebugEvent; +import org.eclipse.debug.core.IBreakpointManager; +import org.eclipse.debug.core.IDebugEventFilter; +import org.eclipse.debug.core.IDebugEventSetListener; +import org.eclipse.debug.core.IExpressionManager; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.ILaunchManager; +import org.eclipse.debug.core.ILogicalStructureType; +import org.eclipse.debug.core.IMemoryBlockManager; +import org.eclipse.debug.core.IProcessFactory; +import org.eclipse.debug.core.IStatusHandler; +import org.eclipse.debug.core.model.IDebugElement; +import org.eclipse.debug.core.model.IDisconnect; +import org.eclipse.debug.core.model.IDropToFrame; +import org.eclipse.debug.core.model.IProcess; +import org.eclipse.debug.core.model.IStep; +import org.eclipse.debug.core.model.IStepFilters; +import org.eclipse.debug.core.model.ISuspendResume; +import org.eclipse.debug.core.model.ITerminate; +import org.eclipse.debug.core.model.IValue; +import org.eclipse.debug.core.model.RuntimeProcess; +import org.eclipse.debug.internal.core.BreakpointManager; +import org.eclipse.debug.internal.core.DebugCoreMessages; +import org.eclipse.debug.internal.core.DebugOptions; +import org.eclipse.debug.internal.core.ExpressionManager; +import org.eclipse.debug.internal.core.IConfigurationElementConstants; +import org.eclipse.debug.internal.core.IInternalDebugCoreConstants; +import org.eclipse.debug.internal.core.LaunchManager; +import org.eclipse.debug.internal.core.LogicalStructureManager; +import org.eclipse.debug.internal.core.MemoryBlockManager; +import org.eclipse.debug.internal.core.Preferences; +import org.eclipse.debug.internal.core.StepFilterManager; +import org.eclipse.debug.internal.core.commands.CommandAdapterFactory; +import org.eclipse.debug.internal.core.sourcelookup.SourceLookupUtils; +import org.eclipse.osgi.service.environment.Constants; +import org.osgi.framework.BundleContext; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +/** + * There is one instance of the debug plug-in available from + * DebugPlugin.getDefault(). The debug plug-in provides: + * + * + * @noinstantiate This class is not intended to be instantiated by clients. + * @noextend This class is not intended to be subclassed by clients. + */ +public class OprofileDebugPlugin extends Plugin { + + /** + * Unique identifier constant (value "org.eclipse.debug.core") + * for the Debug Core plug-in. + */ + private static final String PI_DEBUG_CORE = "org.eclipse.debug.core"; //$NON-NLS-1$ + + /** + * Simple identifier constant (value "launchConfigurationTypes" + * ) for the launch configuration types extension point. + * + * @since 2.0 + */ + public static final String EXTENSION_POINT_LAUNCH_CONFIGURATION_TYPES = "launchConfigurationTypes"; //$NON-NLS-1$ + + /** + * Simple identifier constant (value + * "launchConfigurationComparators") for the launch + * configuration comparators extension point. + * + * @since 2.0 + */ + public static final String EXTENSION_POINT_LAUNCH_CONFIGURATION_COMPARATORS = "launchConfigurationComparators"; //$NON-NLS-1$ + + /** + * Simple identifier constant (value "breakpoints") for the + * breakpoints extension point. + * + * @since 2.0 + */ + public static final String EXTENSION_POINT_BREAKPOINTS = "breakpoints"; //$NON-NLS-1$ + + /** + * Simple identifier constant (value "statusHandlers") for the + * status handlers extension point. + * + * @since 2.0 + */ + public static final String EXTENSION_POINT_STATUS_HANDLERS = "statusHandlers"; //$NON-NLS-1$ + + /** + * Simple identifier constant (value "sourceLocators") for the + * source locators extension point. + * + * @since 2.0 + */ + public static final String EXTENSION_POINT_SOURCE_LOCATORS = "sourceLocators"; //$NON-NLS-1$ + + /** + * Simple identifier constant (value "launchModes") for the + * source modes extension point. + * + * @since 3.0 + */ + public static final String EXTENSION_POINT_LAUNCH_MODES = "launchModes"; //$NON-NLS-1$ + + /** + * Simple identifier constant (value "launchDelegates") for the + * launch delegates extension point. + * + * @since 3.0 + */ + public static final String EXTENSION_POINT_LAUNCH_DELEGATES = "launchDelegates"; //$NON-NLS-1$ + + /** + * Simple identifier constant (value "processFactories") for + * the process factories extension point. + * + * @since 3.0 + */ + public static final String EXTENSION_POINT_PROCESS_FACTORIES = "processFactories"; //$NON-NLS-1$ + + /** + * Simple identifier constant (value "logicalStructureTypes") + * for the logical structure types extension point. + * + * @since 3.0 + */ + public static final String EXTENSION_POINT_LOGICAL_STRUCTURE_TYPES = "logicalStructureTypes"; //$NON-NLS-1$ + + /** + * Simple identifier constant (value + * "logicalStructureProviders") for the logical structure types + * extension point. + * + * @since 3.1 + */ + public static final String EXTENSION_POINT_LOGICAL_STRUCTURE_PROVIDERS = "logicalStructureProviders"; //$NON-NLS-1$ + + /** + * Simple identifier constant (value "sourceContainerTypes") + * for the source container types extension point. + * + * @since 3.0 + */ + public static final String EXTENSION_POINT_SOURCE_CONTAINER_TYPES = "sourceContainerTypes"; //$NON-NLS-1$ + + /** + * Simple identifier constant (value "sourcePathComputers") for + * the source path computers extension point. + * + * @since 3.0 + */ + public static final String EXTENSION_POINT_SOURCE_PATH_COMPUTERS = "sourcePathComputers"; //$NON-NLS-1$ + + /** + * Simple identifier constant for the launch options extension point + * + * @since 3.3 + */ + public static final String EXTENSION_POINT_LAUNCH_OPTIONS = "launchOptions"; //$NON-NLS-1$ + + /** + * Simple identifier constant for the breakpoint import participant + * extension point + * + * @since 3.5 + */ + public static final String EXTENSION_POINT_BREAKPOINT_IMPORT_PARTICIPANTS = "breakpointImportParticipants"; //$NON-NLS-1$ + + /** + * Status code indicating an unexpected error. + * + * @since 3.4 + */ + public static final int ERROR = 125; + + /** + * Status code indicating an unexpected internal error. Internal errors + * should never be displayed to the user in dialogs or status text. Internal + * error messages are not translated. + */ + public static final int INTERNAL_ERROR = 120; + + /** + * Status code indicating that the Eclipse runtime does not support + * launching a program with a working directory. This feature is only + * available if Eclipse is run on a 1.3 runtime or higher. + *

+ * A status handler may be registered for this error condition, and should + * return a Boolean indicating whether the program should be + * re-launched with the default working directory. + *

+ */ + public static final int ERR_WORKING_DIRECTORY_NOT_SUPPORTED = 115; + + /** + * The launch configuration attribute that designates the process factory ID + * for the process factory to be used when creating a new process as a + * result of launching the launch configuration. + * + * @since 3.0 + */ + public static final String ATTR_PROCESS_FACTORY_ID = "process_factory_id"; //$NON-NLS-1$ + + /** + * The launch attribute that designates whether or not it's associated + * launch should capture output. Value is a string representing a boolean - + * true or false. When unspecified, the default + * value is considered true. + * + * @since 3.1 + */ + public static final String ATTR_CAPTURE_OUTPUT = PI_DEBUG_CORE + + ".capture_output"; //$NON-NLS-1$ + + /** + * The launch attribute that stores the time stamp of when a launch + * configuration was launched. Value is {@link Long#toString(long)} of + * {@link System#currentTimeMillis()}. + * + * @since 3.6 + */ + public static final String ATTR_LAUNCH_TIMESTAMP = PI_DEBUG_CORE + + ".launch.timestamp"; //$NON-NLS-1$ + + /** + * This launch attribute designates the encoding to be used by the console + * associated with the launch. + *

+ * For release 3.3, the system encoding is used when unspecified. Since 3.4, + * the inherited encoding is used when unspecified. See + * {@link ILaunchManager} for a description in + * getEncoding(ILaunchConfiguration). + *

+ *

+ * Value of this constant is the same as the value of the old + * IDebugUIConstants.ATTR_CONSOLE_ENCODING constant for + * backward compatibility. + *

+ * + * @since 3.3 + */ + public static final String ATTR_CONSOLE_ENCODING = "org.eclipse.debug.ui.ATTR_CONSOLE_ENCODING"; //$NON-NLS-1$ + + /** + * Boolean preference key (value + * org.eclipse.debug.core.PREF_DELETE_CONFIGS_ON_PROJECT_DELETE + * ) that controls whether to delete associated configurations when a + * project is deleted. Default value is false. + * + * @since 3.7 + */ + public static final String PREF_DELETE_CONFIGS_ON_PROJECT_DELETE = OprofileDebugPlugin + .getUniqueIdentifier() + ".PREF_DELETE_CONFIGS_ON_PROJECT_DELETE"; //$NON-NLS-1$ + + /** + * Deleted breakpoint marker attribute (value + * "org.eclipse.debug.core.breakpointIsDeleted"). The attribute + * is a boolean corresponding to the deleted state of a + * breakpoint. + * + * @see org.eclipse.core.resources.IMarker#getAttribute(String, boolean) + * @since 3.7 + */ + public static final String ATTR_BREAKPOINT_IS_DELETED = OprofileDebugPlugin + .getUniqueIdentifier() + ".breakpointIsDeleted"; //$NON-NLS-1$ + + /** + * The singleton debug plug-in instance. + */ + private static OprofileDebugPlugin fgDebugPlugin = null; + + /** + * The singleton breakpoint manager. + */ + private BreakpointManager fBreakpointManager; + + /** + * The singleton expression manager. + */ + private ExpressionManager fExpressionManager; + + /** + * The singleton launch manager. + */ + private LaunchManager fLaunchManager; + + /** + * The singleton memory block manager. + * + * @since 3.1 + */ + private MemoryBlockManager fMemoryBlockManager; + + /** + * The collection of debug event listeners. + */ + private ListenerList fEventListeners = new ListenerList(); + + /** + * Event filters, or null if none. + */ + private ListenerList fEventFilters = new ListenerList(); + + /** + * Whether this plug-in is in the process of shutting down. + */ + private boolean fShuttingDown = false; + + /** + * Table of status handlers. Keys are {plug-in identifier, status code} + * pairs, and values are associated IConfigurationElements. + */ + private HashMap fStatusHandlers = null; + + /** + * Map of process factories. Keys are process factory IDs and values are + * associated IConfigurationElements. + * + * @since 3.0 + */ + private HashMap fProcessFactories = null; + + /** + * Mode constants for the event notifier + */ + private static final int NOTIFY_FILTERS = 0; + private static final int NOTIFY_EVENTS = 1; + + /** + * Queue of debug events to fire to listeners and asynchronous runnables to + * execute in the order received. + * + * @since 3.1 + */ + private List fEventQueue = new ArrayList(); + + /** + * Job to fire events to listeners. + * + * @since 3.1 + */ + private EventDispatchJob fEventDispatchJob = new EventDispatchJob(); + + /** + * Event dispatch job. Processes event queue of debug events and runnables. + * + * @since 3.1 + */ + class EventDispatchJob extends Job { + + EventNotifier fNotifier = new EventNotifier(); + AsynchRunner fRunner = new AsynchRunner(); + + /** + * Creates a new event dispatch job. + */ + public EventDispatchJob() { + super(DebugCoreMessages.DebugPlugin_1); + setPriority(Job.INTERACTIVE); + setSystem(true); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime. + * IProgressMonitor) + */ + protected IStatus run(IProgressMonitor monitor) { + + while (!fEventQueue.isEmpty()) { + Object next = null; + synchronized (fEventQueue) { + if (!fEventQueue.isEmpty()) { + next = fEventQueue.remove(0); + } + } + if (next instanceof Runnable) { + fRunner.async((Runnable) next); + } else if (next != null) { + fNotifier.dispatch((DebugEvent[]) next); + } + } + return Status.OK_STATUS; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.jobs.Job#shouldRun() + */ + public boolean shouldRun() { + return shouldSchedule(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.internal.jobs.InternalJob#shouldSchedule() + */ + public boolean shouldSchedule() { + return !(isShuttingDown() || fEventListeners.isEmpty()); + } + + } + + /** + * Returns the singleton instance of the debug plug-in. + * + * @return the debug plug-in + */ + public static OprofileDebugPlugin getDefault() { + return fgDebugPlugin; + } + + /** + * Sets the singleton instance of the debug plug-in. + * + * @param plugin + * the debug plug-in, or null when shutting down + */ + private static void setDefault(OprofileDebugPlugin plugin) { + fgDebugPlugin = plugin; + } + + /** + * Convenience method which returns the unique identifier of this plug-in. + * + * @return debug plug-in identifier + */ + public static String getUniqueIdentifier() { + return PI_DEBUG_CORE; + } + + /** + * Constructs the debug plug-in. + *

+ * An instance of this plug-in runtime class is automatically created when + * the facilities provided by this plug-in are required. Clients must + * never explicitly instantiate a plug-in runtime class. + *

+ */ + public OprofileDebugPlugin() { + super(); + setDefault(this); + } + + /** + * Adds the given listener to the collection of registered debug event + * listeners. Has no effect if an identical listener is already registered. + * + * @param listener + * the listener to add + * @since 2.0 + */ + public void addDebugEventListener(IDebugEventSetListener listener) { + fEventListeners.add(listener); + } + + /** + * Notifies all registered debug event set listeners of the given debug + * events. Events which are filtered by a registered debug event filter are + * not fired. + * + * @param events + * array of debug events to fire + * @see IDebugEventFilter + * @see IDebugEventSetListener + * @since 2.0 + */ + public void fireDebugEventSet(DebugEvent[] events) { + if (isShuttingDown() || events == null || fEventListeners.isEmpty()) + return; + synchronized (fEventQueue) { + fEventQueue.add(events); + } + fEventDispatchJob.schedule(); + } + + /** + * Asynchronously executes the given runnable in a separate thread, after + * debug event dispatch has completed. If debug events are not currently + * being dispatched, the runnable is scheduled to run in a separate thread + * immediately. + * + * @param r + * runnable to execute asynchronously + * @since 2.1 + */ + public void asyncExec(Runnable r) { + synchronized (fEventQueue) { + fEventQueue.add(r); + } + fEventDispatchJob.schedule(); + } + + /** + * Returns the breakpoint manager. + * + * @return the breakpoint manager + * @see IBreakpointManager + */ + public synchronized IBreakpointManager getBreakpointManager() { + if (fBreakpointManager == null) { + fBreakpointManager = new BreakpointManager(); + } + return fBreakpointManager; + } + + /** + * Returns the launch manager. + * + * @return the launch manager + * @see ILaunchManager + */ + public synchronized ILaunchManager getLaunchManager() { + if (fLaunchManager == null) { + fLaunchManager = new LaunchManager(); + } + return fLaunchManager; + } + + /** + * Returns the memory block manager. + * + * @return the memory block manager. + * @see IMemoryBlockManager + * @since 3.1 + */ + public synchronized IMemoryBlockManager getMemoryBlockManager() { + if (fMemoryBlockManager == null) { + fMemoryBlockManager = new MemoryBlockManager(); + } + return fMemoryBlockManager; + } + + /** + * Returns the status handler registered for the given status, or + * null if none. + * + * @param status + * status for which a status handler has been requested + * @return the status handler registered for the given status, or + * null if none + * @since 2.0 + */ + public IStatusHandler getStatusHandler(IStatus status) { + boolean enabled = Platform.getPreferencesService().getBoolean( + OprofileDebugPlugin.getUniqueIdentifier(), + IInternalDebugCoreConstants.PREF_ENABLE_STATUS_HANDLERS, true, + null); + if (!enabled) { + return null; + } + StatusHandlerKey key = new StatusHandlerKey(status.getPlugin(), + status.getCode()); + if (fStatusHandlers == null) { + initializeStatusHandlers(); + } + IConfigurationElement config = (IConfigurationElement) fStatusHandlers + .get(key); + if (config != null) { + try { + Object handler = config + .createExecutableExtension(IConfigurationElementConstants.CLASS); + if (handler instanceof IStatusHandler) { + return (IStatusHandler) handler; + } + invalidStatusHandler( + null, + MessageFormat + .format("Registered status handler {0} does not implement required interface IStatusHandler.", new String[] { config.getDeclaringExtension().getUniqueIdentifier() })); //$NON-NLS-1$ + } catch (CoreException e) { + log(e); + } + } + return null; + } + + /** + * Returns the expression manager. + * + * @return the expression manager + * @see IExpressionManager + * @since 2.0 + */ + public synchronized IExpressionManager getExpressionManager() { + if (fExpressionManager == null) { + fExpressionManager = new ExpressionManager(); + } + return fExpressionManager; + } + + /** + * Removes the given listener from the collection of registered debug event + * listeners. Has no effect if an identical listener is not already + * registered. + * + * @param listener + * the listener to remove + * @since 2.0 + */ + public void removeDebugEventListener(IDebugEventSetListener listener) { + fEventListeners.remove(listener); + } + + /* + * (non-Javadoc) + * + * @see + * org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext context) throws Exception { + try { + setShuttingDown(true); + + if (fLaunchManager != null) { + fLaunchManager.shutdown(); + } + if (fBreakpointManager != null) { + fBreakpointManager.shutdown(); + } + if (fMemoryBlockManager != null) { + fMemoryBlockManager.shutdown(); + } + + fEventListeners.clear(); + fEventFilters.clear(); + + SourceLookupUtils.shutdown(); + Preferences.savePreferences(OprofileDebugPlugin + .getUniqueIdentifier()); + ResourcesPlugin.getWorkspace().removeSaveParticipant( + getUniqueIdentifier()); + } finally { + super.stop(context); + setDefault(null); + } + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.core.runtime.Plugin#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext context) throws Exception { + super.start(context); + DebugOptions.initDebugOptions(); + ResourcesPlugin.getWorkspace().addSaveParticipant( + getUniqueIdentifier(), new ISaveParticipant() { + public void saving(ISaveContext saveContext) + throws CoreException { + if (fExpressionManager != null) { + fExpressionManager.storeWatchExpressions(); + } + Preferences.savePreferences(OprofileDebugPlugin + .getUniqueIdentifier()); + } + + public void rollback(ISaveContext saveContext) { + } + + public void prepareToSave(ISaveContext saveContext) + throws CoreException { + } + + public void doneSaving(ISaveContext saveContext) { + } + }); + // command adapters + IAdapterManager manager = Platform.getAdapterManager(); + CommandAdapterFactory actionFactory = new CommandAdapterFactory(); + manager.registerAdapters(actionFactory, IDisconnect.class); + manager.registerAdapters(actionFactory, IDropToFrame.class); + manager.registerAdapters(actionFactory, IStep.class); + manager.registerAdapters(actionFactory, IStepFilters.class); + manager.registerAdapters(actionFactory, ISuspendResume.class); + manager.registerAdapters(actionFactory, ITerminate.class); + manager.registerAdapters(actionFactory, ILaunch.class); + manager.registerAdapters(actionFactory, IProcess.class); + manager.registerAdapters(actionFactory, IDebugElement.class); + } + + /** + * Creates and returns a new process representing the given + * java.lang.Process. A streams proxy is created for the I/O + * streams in the system process. The process is added to the given launch. + *

+ * If the launch configuration associated with the given launch specifies a + * process factory, it will be used to instantiate the new process. + *

+ * + * @param launch + * the launch the process is contained in + * @param process + * the system process to wrap + * @param label + * the label assigned to the process + * @return the process + * @see IProcess + * @see IProcessFactory + */ + public static IProcess newProcess(ILaunch launch, Process process, + String label) { + return newProcess(launch, process, label, null); + } + + /** + * Creates and returns a new process representing the given + * java.lang.Process. A streams proxy is created for the I/O + * streams in the system process. The process is added to the given launch, + * and the process is initialized with the given attribute map. + *

+ * If the launch configuration associated with the given launch specifies a + * process factory, it will be used to instantiate the new process. + *

+ * + * @param launch + * the launch the process is contained in + * @param process + * the system process to wrap + * @param label + * the label assigned to the process + * @param attributes + * initial values for the attribute map + * @return the process null can be returned if errors occur + * dealing with the process factory designated to create the + * process. + * @see IProcess + * @see IProcessFactory + * @since 2.1 + */ + public static IProcess newProcess(ILaunch launch, Process process, + String label, Map attributes) { + ILaunchConfiguration config = launch.getLaunchConfiguration(); + String processFactoryID = null; + if (config != null) { + try { + processFactoryID = config.getAttribute(ATTR_PROCESS_FACTORY_ID, + (String) null); + } catch (CoreException e) { + } + } + if (processFactoryID != null) { + OprofileDebugPlugin plugin = OprofileDebugPlugin.getDefault(); + if (plugin.fProcessFactories == null) { + plugin.initializeProcessFactories(); + } + IConfigurationElement element = (IConfigurationElement) plugin.fProcessFactories + .get(processFactoryID); + if (element == null) { + return null; + } + IProcessFactory processFactory = null; + try { + processFactory = (IProcessFactory) element + .createExecutableExtension(IConfigurationElementConstants.CLASS); + } catch (CoreException exception) { + log(exception); + return null; + } + return processFactory + .newProcess(launch, process, label, attributes); + } + return new OprofileRuntimeProcess(launch, process, label, attributes); + } + + /** + * Returns any logical structure types that have been contributed for the + * given value. + * + * @param value + * the value for which logical structure types have been + * requested + * @return logical structure types that have been contributed for the given + * value, possibly an empty collection + * + * @since 3.0 + */ + public static ILogicalStructureType[] getLogicalStructureTypes(IValue value) { + return LogicalStructureManager.getDefault().getLogicalStructureTypes( + value); + } + + /** + * Returns the default logical structure type among the given combination of + * logical structure types, or null if none. When the given + * combination of logical structure type is applicable for a value, the + * default logical structure type is used to display a value. + * + * @param types + * a combination of structures applicable to a value + * @return the default structure that should be used to display the value or + * null if none + * + * @since 3.1 + */ + public static ILogicalStructureType getDefaultStructureType( + ILogicalStructureType[] types) { + return LogicalStructureManager.getDefault().getSelectedStructureType( + types); + } + + /** + * Sets the default logical structure type among the given combination of + * logical structure types. The logical structure types provided should all + * be applicable to a single value. Specifying null indicates + * there is no default logical structure for the given combination of types. + * + * @param types + * a combination of logical structure types applicable to a value + * @param def + * the default logical structure among the given combination of + * types or null if none + * + * @since 3.1 + */ + public static void setDefaultStructureType(ILogicalStructureType[] types, + ILogicalStructureType def) { + LogicalStructureManager.getDefault().setEnabledType(types, def); + } + + /** + * Convenience method that performs a runtime exec on the given command line + * in the context of the specified working directory, and returns the + * resulting process. If the current runtime does not support the + * specification of a working directory, the status handler for error code + * ERR_WORKING_DIRECTORY_NOT_SUPPORTED is queried to see if the + * exec should be re-executed without specifying a working directory. + * + * @param cmdLine + * the command line + * @param workingDirectory + * the working directory, or null + * @return the resulting process or null if the exec is + * canceled + * @exception CoreException + * if the exec fails + * @see Runtime + * + * @since 2.1 + */ + public static Process exec(String[] cmdLine, File workingDirectory) + throws CoreException { + return exec(cmdLine, workingDirectory, null); + } + + /** + * Convenience method that performs a runtime exec on the given command line + * in the context of the specified working directory, and returns the + * resulting process. If the current runtime does not support the + * specification of a working directory, the status handler for error code + * ERR_WORKING_DIRECTORY_NOT_SUPPORTED is queried to see if the + * exec should be re-executed without specifying a working directory. + * + * @param cmdLine + * the command line + * @param workingDirectory + * the working directory, or null + * @param envp + * the environment variables set in the process, or + * null + * @return the resulting process or null if the exec is + * canceled + * @exception CoreException + * if the exec fails + * @see Runtime + * + * @since 3.0 + */ + public static Process exec(String[] cmdLine, File workingDirectory, + String[] envp) throws CoreException { + Process p = null; + try { + if (workingDirectory == null) { + p = Runtime.getRuntime().exec(cmdLine, envp); + } else { + p = Runtime.getRuntime().exec(cmdLine, envp, workingDirectory); + } + } catch (IOException e) { + Status status = new Status(IStatus.ERROR, getUniqueIdentifier(), + ERROR, DebugCoreMessages.DebugPlugin_0, e); + throw new CoreException(status); + } catch (NoSuchMethodError e) { + // attempting launches on 1.2.* - no ability to set working + // directory + IStatus status = new Status( + IStatus.ERROR, + getUniqueIdentifier(), + ERR_WORKING_DIRECTORY_NOT_SUPPORTED, + DebugCoreMessages.DebugPlugin_Eclipse_runtime_does_not_support_working_directory_2, + e); + IStatusHandler handler = OprofileDebugPlugin.getDefault() + .getStatusHandler(status); + + if (handler != null) { + Object result = handler.handleStatus(status, null); + if (result instanceof Boolean + && ((Boolean) result).booleanValue()) { + p = exec(cmdLine, null); + } + } + } + return p; + } + + /** + * Returns whether this plug-in is in the process of being shutdown. + * + * @return whether this plug-in is in the process of being shutdown + */ + private boolean isShuttingDown() { + return fShuttingDown; + } + + /** + * Sets whether this plug-in is in the process of being shutdown. + * + * @param value + * whether this plug-in is in the process of being shutdown + */ + private void setShuttingDown(boolean value) { + fShuttingDown = value; + } + + /** + * Returns the collection of debug event listeners registered with this + * plug-in. + * + * @return list of registered debug event listeners, instances of + * IDebugEventSetListeners + */ + private Object[] getEventListeners() { + return fEventListeners.getListeners(); + } + + /** + * Adds the given debug event filter to the registered event filters. Has no + * effect if an identical filter is already registered. + * + * @param filter + * debug event filter + * @since 2.0 + */ + public void addDebugEventFilter(IDebugEventFilter filter) { + fEventFilters.add(filter); + } + + /** + * Removes the given debug event filter from the registered event filters. + * Has no effect if an identical filter is not already registered. + * + * @param filter + * debug event filter + * @since 2.0 + */ + public void removeDebugEventFilter(IDebugEventFilter filter) { + fEventFilters.remove(filter); + } + + /** + * Logs the given message if in debug mode. + * + * @param message + * the message to log + * @since 2.0 + */ + public static void logDebugMessage(String message) { + if (getDefault().isDebugging()) { + // this message is intentionally not externalized, as an exception + // may + // be due to the resource bundle itself + log(new Status(IStatus.ERROR, getUniqueIdentifier(), ERROR, + MessageFormat.format(DebugCoreMessages.DebugPlugin_2, + new String[] { message }), null)); + } + } + + /** + * Logs the given message with this plug-in's log and the given throwable or + * null if none. + * + * @param message + * the message to log + * @param throwable + * the exception that occurred or null if none + */ + public static void logMessage(String message, Throwable throwable) { + log(new Status(IStatus.ERROR, getUniqueIdentifier(), ERROR, message, + throwable)); + } + + /** + * Logs the specified status with this plug-in's log. + * + * @param status + * status to log + * @since 2.0 + */ + public static void log(IStatus status) { + getDefault().getLog().log(status); + } + + /** + * Logs the specified throwable with this plug-in's log. + * + * @param t + * throwable to log + * @since 2.0 + */ + public static void log(Throwable t) { + IStatus status = new Status(IStatus.ERROR, getUniqueIdentifier(), + ERROR, DebugCoreMessages.DebugPlugin_3, t); + log(status); + } + + /** + * Register status handlers. + * + */ + private void initializeStatusHandlers() { + IExtensionPoint extensionPoint = Platform.getExtensionRegistry() + .getExtensionPoint(OprofileDebugPlugin.PI_DEBUG_CORE, + EXTENSION_POINT_STATUS_HANDLERS); + IConfigurationElement[] infos = extensionPoint + .getConfigurationElements(); + fStatusHandlers = new HashMap(infos.length); + for (int i = 0; i < infos.length; i++) { + IConfigurationElement configurationElement = infos[i]; + String id = configurationElement.getAttribute("plugin"); //$NON-NLS-1$ + String code = configurationElement.getAttribute("code"); //$NON-NLS-1$ + + if (id != null && code != null) { + try { + StatusHandlerKey key = new StatusHandlerKey(id, + Integer.parseInt(code)); + fStatusHandlers.put(key, configurationElement); + } catch (NumberFormatException e) { + // invalid status handler + invalidStatusHandler(e, + configurationElement.getAttribute("id")); //$NON-NLS-1$ + } + } else { + // invalid status handler + invalidStatusHandler(null, + configurationElement.getAttribute("id")); //$NON-NLS-1$ + } + } + } + + /** + * Register process factories. + * + */ + private void initializeProcessFactories() { + IExtensionPoint extensionPoint = Platform.getExtensionRegistry() + .getExtensionPoint(OprofileDebugPlugin.PI_DEBUG_CORE, + EXTENSION_POINT_PROCESS_FACTORIES); + IConfigurationElement[] infos = extensionPoint + .getConfigurationElements(); + fProcessFactories = new HashMap(infos.length); + for (int i = 0; i < infos.length; i++) { + IConfigurationElement configurationElement = infos[i]; + String id = configurationElement.getAttribute("id"); //$NON-NLS-1$ + String clss = configurationElement.getAttribute("class"); //$NON-NLS-1$ + if (id != null && clss != null) { + fProcessFactories.put(id, configurationElement); + } else { + // invalid process factory + String badDefiner = infos[i].getContributor().getName(); + log(new Status(IStatus.ERROR, + OprofileDebugPlugin.PI_DEBUG_CORE, ERROR, + MessageFormat.format(DebugCoreMessages.DebugPlugin_4, + new String[] { badDefiner, id }), null)); + } + } + } + + private void invalidStatusHandler(Exception e, String id) { + log(new Status(IStatus.ERROR, OprofileDebugPlugin.PI_DEBUG_CORE, ERROR, + MessageFormat.format(DebugCoreMessages.DebugPlugin_5, + new String[] { id }), e)); + } + + /** + * Key for status handler extensions - a plug-in identifier/code pair + */ + class StatusHandlerKey { + + String fPluginId; + int fCode; + + StatusHandlerKey(String pluginId, int code) { + fPluginId = pluginId; + fCode = code; + } + + public int hashCode() { + return fPluginId.hashCode() + fCode; + } + + public boolean equals(Object obj) { + if (obj instanceof StatusHandlerKey) { + StatusHandlerKey s = (StatusHandlerKey) obj; + return fCode == s.fCode && fPluginId.equals(s.fPluginId); + } + return false; + } + } + + /** + * Executes runnables after event dispatch is complete. + * + * @since 3.0 + */ + class AsynchRunner implements ISafeRunnable { + + private Runnable fRunnable = null; + + void async(Runnable runnable) { + fRunnable = runnable; + SafeRunner.run(this); + fRunnable = null; + + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.core.runtime.ISafeRunnable#handleException(java.lang. + * Throwable) + */ + public void handleException(Throwable exception) { + IStatus status = new Status(IStatus.ERROR, getUniqueIdentifier(), + ERROR, DebugCoreMessages.DebugPlugin_6, exception); + log(status); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.ISafeRunnable#run() + */ + public void run() throws Exception { + fRunnable.run(); + } + + } + + /** + * Filters and dispatches events in a safe runnable to handle any + * exceptions. + */ + class EventNotifier implements ISafeRunnable { + + private DebugEvent[] fEvents; + private IDebugEventSetListener fListener; + private IDebugEventFilter fFilter; + private int fMode; + + /** + * @see org.eclipse.core.runtime.ISafeRunnable#handleException(java.lang.Throwable) + */ + public void handleException(Throwable exception) { + switch (fMode) { + case NOTIFY_FILTERS: + IStatus status = new Status(IStatus.ERROR, + getUniqueIdentifier(), ERROR, + DebugCoreMessages.DebugPlugin_7, exception); + log(status); + break; + case NOTIFY_EVENTS: + status = new Status(IStatus.ERROR, getUniqueIdentifier(), + ERROR, DebugCoreMessages.DebugPlugin_8, exception); + log(status); + break; + } + } + + /** + * @see org.eclipse.core.runtime.ISafeRunnable#run() + */ + public void run() throws Exception { + switch (fMode) { + case NOTIFY_FILTERS: + fEvents = fFilter.filterDebugEvents(fEvents); + break; + case NOTIFY_EVENTS: + fListener.handleDebugEvents(fEvents); + break; + } + } + + /** + * Filter and dispatch the given events. If an exception occurs in one + * listener, events are still fired to subsequent listeners. + * + * @param events + * debug events + */ + void dispatch(DebugEvent[] events) { + fEvents = events; + Object[] filters = fEventFilters.getListeners(); + if (filters.length > 0) { + fMode = NOTIFY_FILTERS; + for (int i = 0; i < filters.length; i++) { + fFilter = (IDebugEventFilter) filters[i]; + SafeRunner.run(this); + if (fEvents == null || fEvents.length == 0) { + return; + } + } + } + + fMode = NOTIFY_EVENTS; + Object[] listeners = getEventListeners(); + if (DebugOptions.DEBUG_EVENTS) { + for (int i = 0; i < fEvents.length; i++) { + System.out.println(fEvents[i]); + } + } + for (int i = 0; i < listeners.length; i++) { + fListener = (IDebugEventSetListener) listeners[i]; + SafeRunner.run(this); + } + fEvents = null; + fFilter = null; + fListener = null; + } + + } + + /** + * Creates and returns a new XML document. + * + * @return a new XML document + * @throws CoreException + * if unable to create a new document + * @since 3.0 + */ + public static Document newDocument() throws CoreException { + try { + return LaunchManager.getDocument(); + } catch (ParserConfigurationException e) { + abort("Unable to create new XML document.", e); //$NON-NLS-1$ + } + return null; + } + + /** + * Serializes the given XML document into a string. + * + * @param document + * XML document to serialize + * @return a string representing the given document + * @throws CoreException + * if unable to serialize the document + * @since 3.0 + */ + public static String serializeDocument(Document document) + throws CoreException { + try { + return LaunchManager.serializeDocument(document); + } catch (TransformerException e) { + abort("Unable to serialize XML document.", e); //$NON-NLS-1$ + } catch (IOException e) { + abort("Unable to serialize XML document.", e); //$NON-NLS-1$ + } + return null; + } + + /** + * Parses the given string representing an XML document, returning its root + * element. + * + * @param document + * XML document as a string + * @return the document's root element + * @throws CoreException + * if unable to parse the document + * @since 3.0 + */ + public static Element parseDocument(String document) throws CoreException { + Element root = null; + InputStream stream = null; + try { + DocumentBuilder parser = DocumentBuilderFactory.newInstance() + .newDocumentBuilder(); + parser.setErrorHandler(new DefaultHandler()); + stream = new ByteArrayInputStream(document.getBytes("UTF8")); //$NON-NLS-1$ + root = parser.parse(stream).getDocumentElement(); + } catch (ParserConfigurationException e) { + abort("Unable to parse XML document.", e); //$NON-NLS-1$ + } catch (FactoryConfigurationError e) { + abort("Unable to parse XML document.", e); //$NON-NLS-1$ + } catch (SAXException e) { + abort("Unable to parse XML document.", e); //$NON-NLS-1$ + } catch (IOException e) { + abort("Unable to parse XML document.", e); //$NON-NLS-1$ + } finally { + try { + if (stream != null) { + stream.close(); + } + } catch (IOException e) { + abort("Unable to parse XML document.", e); //$NON-NLS-1$ + } + } + return root; + } + + /** + * Throws an exception with the given message and underlying exception. + * + * @param message + * error message + * @param exception + * underlying exception, or null + * @throws CoreException + */ + private static void abort(String message, Throwable exception) + throws CoreException { + IStatus status = new Status(IStatus.ERROR, + OprofileDebugPlugin.getUniqueIdentifier(), + OprofileDebugPlugin.ERROR, message, exception); + throw new CoreException(status); + } + + /** + * Utility class to parse command line arguments. + * + * @since 3.1 + */ + private static class ArgumentParser { + private String fArgs; + private int fIndex = 0; + private int ch = -1; + + public ArgumentParser(String args) { + fArgs = args; + } + + public String[] parseArguments() { + List v = new ArrayList(); + + ch = getNext(); + while (ch > 0) { + if (Character.isWhitespace((char) ch)) { + ch = getNext(); + } else { + if (ch == '"') { + StringBuffer buf = new StringBuffer(); + buf.append(parseString()); + if (buf.length() == 0 + && Platform.getOS().equals(Constants.OS_WIN32)) { + // empty string on windows platform + buf.append("\"\""); //$NON-NLS-1$ + } + v.add(buf.toString()); + } else { + v.add(parseToken()); + } + } + } + + String[] result = new String[v.size()]; + v.toArray(result); + return result; + } + + private int getNext() { + if (fIndex < fArgs.length()) + return fArgs.charAt(fIndex++); + return -1; + } + + private String parseString() { + ch = getNext(); + if (ch == '"') { + ch = getNext(); + return ""; //$NON-NLS-1$ + } + StringBuffer buf = new StringBuffer(); + while (ch > 0 && ch != '"') { + if (ch == '\\') { + ch = getNext(); + if (ch != '"') { // Only escape double quotes + buf.append('\\'); + } else { + if (Platform.getOS().equals(Constants.OS_WIN32)) { + // @see Bug 26870. Windows requires an extra escape + // for embedded strings + buf.append('\\'); + } + } + } + if (ch > 0) { + buf.append((char) ch); + ch = getNext(); + } + } + ch = getNext(); + return buf.toString(); + } + + private String parseToken() { + StringBuffer buf = new StringBuffer(); + + while (ch > 0 && !Character.isWhitespace((char) ch)) { + if (ch == '\\') { + ch = getNext(); + if (Character.isWhitespace((char) ch)) { + // end of token, don't lose trailing backslash + buf.append('\\'); + return buf.toString(); + } + if (ch > 0) { + if (ch != '"') { // Only escape double quotes + buf.append('\\'); + } else { + if (Platform.getOS().equals(Constants.OS_WIN32)) { + // @see Bug 26870. Windows requires an extra + // escape for embedded strings + buf.append('\\'); + } + } + buf.append((char) ch); + ch = getNext(); + } else if (ch == -1) { // Don't lose a trailing backslash + buf.append('\\'); + } + } else if (ch == '"') { + buf.append(parseString()); + } else { + buf.append((char) ch); + ch = getNext(); + } + } + return buf.toString(); + } + } + + /** + * Parses the given command line into separate arguments that can be passed + * to DebugPlugin.exec(String[], File). Embedded quotes and + * slashes are escaped. + * + * @param args + * command line arguments as a single string + * @return individual arguments + * @since 3.1 + */ + public static String[] parseArguments(String args) { + if (args == null) + return new String[0]; + ArgumentParser parser = new ArgumentParser(args); + String[] res = parser.parseArguments(); + + return res; + } + + /** + * Sets whether step filters should be applied to step commands. This + * setting is a global option applied to all registered debug targets. + * + * @param useStepFilters + * whether step filters should be applied to step commands + * @since 3.3 + * @see org.eclipse.debug.core.model.IStepFilters + */ + public static void setUseStepFilters(boolean useStepFilters) { + getStepFilterManager().setUseStepFilters(useStepFilters); + } + + /** + * Returns whether step filters are applied to step commands. + * + * @return whether step filters are applied to step commands + * @since 3.3 + * @see org.eclipse.debug.core.model.IStepFilters + * @see org.eclipse.debug.core.commands.IStepFiltersHandler + */ + public static boolean isUseStepFilters() { + return getStepFilterManager().isUseStepFilters(); + } + + /** + * Returns the step filter manager. + * + * @return step filter manager + */ + private static StepFilterManager getStepFilterManager() { + return ((LaunchManager) getDefault().getLaunchManager()) + .getStepFilterManager(); + } + + /** + * Returns an adapter of the specified type for the given object or + * null if none. The object itself is returned if it is an + * instance of the specified type. If the object is adaptable and does not + * subclass PlatformObject, and does not provide the specified + * adapter directly, the platform's adapter manager is consulted for an + * adapter. + * + * @param element + * element to retrieve adapter for + * @param type + * adapter type + * @return adapter or null + * @since 3.4 + */ + public static Object getAdapter(Object element, Class type) { + Object adapter = null; + if (element != null) { + if (type.isInstance(element)) { + return element; + } else { + if (element instanceof IAdaptable) { + adapter = ((IAdaptable) element).getAdapter(type); + } + // for objects that don't subclass PlatformObject, check the + // platform's adapter manager + if (adapter == null && !(element instanceof PlatformObject)) { + adapter = Platform.getAdapterManager().getAdapter(element, + type); + } + // force load the adapter in case it really is available + if (adapter == null) { + adapter = Platform.getAdapterManager().loadAdapter(element, + type.getName()); + } + } + } + return adapter; + } + +} diff --git a/org.eclipse.linuxtools.oprofile.launch.exe/src/com/samsung/tizen/oprofile/launch/OprofileRuntimeProcess.java b/org.eclipse.linuxtools.oprofile.launch.exe/src/com/samsung/tizen/oprofile/launch/OprofileRuntimeProcess.java new file mode 100644 index 0000000..1ee7ed7 --- /dev/null +++ b/org.eclipse.linuxtools.oprofile.launch.exe/src/com/samsung/tizen/oprofile/launch/OprofileRuntimeProcess.java @@ -0,0 +1,475 @@ +/******************************************************************************* + * Copyright (c) 2000, 2010 IBM Corporation 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package com.samsung.tizen.oprofile.launch; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.PlatformObject; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugEvent; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.model.IDebugTarget; +import org.eclipse.debug.core.model.IProcess; +import org.eclipse.debug.core.model.IStreamsProxy; +import org.eclipse.debug.internal.core.DebugCoreMessages; +import org.eclipse.debug.internal.core.NullStreamsProxy; +import org.eclipse.debug.internal.core.StreamsProxy; + +import com.samsung.tizen.common.connection.ConnectionPlugin; +import com.samsung.tizen.sdblib.SdbCommandRejectedException; + +/** + * Standard implementation of an IProcess that wrappers a system + * process (java.lang.Process). + *

+ * Clients may subclass this class. Clients that need to replace the + * implementation of a streams proxy associated with an IProcess + * should subclass this class. Generally clients should not instantiate this + * class directly, but should instead call + * DebugPlugin.newProcess(...), which can delegate to an + * IProcessFactory if one is referenced by the associated launch + * configuration. + *

+ * + * @see org.eclipse.debug.core.model.IProcess + * @see org.eclipse.debug.core.IProcessFactory + * @since 3.0 + */ +public class OprofileRuntimeProcess extends PlatformObject implements IProcess { + + private static final int MAX_WAIT_FOR_DEATH_ATTEMPTS = 10; + private static final int TIME_TO_WAIT_FOR_THREAD_DEATH = 500; // ms + + /** + * The launch this process is contained in + */ + private ILaunch fLaunch; + + /** + * The system process represented by this IProcess + */ + private Process fProcess; + + /** + * This process's exit value + */ + private int fExitValue; + + /** + * The monitor which listens for this runtime process' system process to + * terminate. + */ + private ProcessMonitorThread fMonitor; + + /** + * The streams proxy for this process + */ + private IStreamsProxy fStreamsProxy; + + /** + * The name of the process + */ + private String fName; + + /** + * Whether this process has been terminated + */ + private boolean fTerminated; + + /** + * Table of client defined attributes + */ + private Map fAttributes; + + /** + * Whether output from the process should be captured or swallowed + */ + private boolean fCaptureOutput = true; + + /** + * Constructs a RuntimeProcess on the given system process with the given + * name, adding this process to the given launch. + * + * @param launch + * the parent launch of this process + * @param process + * underlying system process + * @param name + * the label used for this process + * @param attributes + * map of attributes used to initialize the attributes of this + * process, or null if none + */ + public OprofileRuntimeProcess(ILaunch launch, Process process, String name, + Map attributes) { + setLaunch(launch); + initializeAttributes(attributes); + fProcess = process; + fName = name; + fTerminated = true; + try { + fExitValue = process.exitValue(); + } catch (IllegalThreadStateException e) { + fTerminated = false; + } + + String captureOutput = launch + .getAttribute(DebugPlugin.ATTR_CAPTURE_OUTPUT); + fCaptureOutput = !("false".equals(captureOutput)); //$NON-NLS-1$ + + fStreamsProxy = createStreamsProxy(); + fMonitor = new ProcessMonitorThread(this); + fMonitor.start(); + launch.addProcess(this); + fireCreationEvent(); + } + + /** + * Initialize the attributes of this process to those in the given map. + * + * @param attributes + * attribute map or null if none + */ + private void initializeAttributes(Map attributes) { + if (attributes != null) { + Iterator keys = attributes.keySet().iterator(); + while (keys.hasNext()) { + String key = (String) keys.next(); + setAttribute(key, (String) attributes.get(key)); + } + } + } + + /** + * @see ITerminate#canTerminate() + */ + public synchronized boolean canTerminate() { + return !fTerminated; + } + + /** + * @see IProcess#getLabel() + */ + public String getLabel() { + return fName; + } + + /** + * Sets the launch this process is contained in + * + * @param launch + * the launch this process is contained in + */ + protected void setLaunch(ILaunch launch) { + fLaunch = launch; + } + + /** + * @see IProcess#getLaunch() + */ + public ILaunch getLaunch() { + return fLaunch; + } + + /** + * Returns the underlying system process associated with this process. + * + * @return system process + */ + protected Process getSystemProcess() { + return fProcess; + } + + /** + * @see ITerminate#isTerminated() + */ + public synchronized boolean isTerminated() { + return fTerminated; + } + + public static void runCommand(String command) { + + try { + ConnectionPlugin.getDefault().getCurrentDevice() + .executeShellCommand(command); + } catch (SdbCommandRejectedException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * @see ITerminate#terminate() + */ + public void terminate() throws DebugException { + // String tool = null; + // if (TizenOprofileLaunchDelegate.getToolID().endsWith("memcheck")) { + // tool = "memcheck"; + // } else { + // tool = "massif"; + // } + String app = TizenOprofileLaunchDelegate.getAppName(); + app = app.substring(app.lastIndexOf("/") + 1, app.length()); + runCommand("pkill -3 " + app); + } + + /** + * Notification that the system process associated with this process has + * terminated. + */ + protected void terminated() { + if (fStreamsProxy instanceof StreamsProxy) { + ((StreamsProxy) fStreamsProxy).close(); + } + + // Avoid calling IProcess.exitValue() inside a sync section (Bug + // 311813). + int exitValue = -1; + boolean running = false; + try { + exitValue = fProcess.exitValue(); + } catch (IllegalThreadStateException ie) { + running = true; + } + + synchronized (this) { + fTerminated = true; + if (!running) { + fExitValue = exitValue; + } + fProcess = null; + } + fireTerminateEvent(); + } + + /** + * @see IProcess#getStreamsProxy() + */ + public IStreamsProxy getStreamsProxy() { + if (!fCaptureOutput) { + return null; + } + return fStreamsProxy; + } + + /** + * Creates and returns the streams proxy associated with this process. + * + * @return streams proxy + */ + protected IStreamsProxy createStreamsProxy() { + if (!fCaptureOutput) { + return new NullStreamsProxy(getSystemProcess()); + } + String encoding = getLaunch().getAttribute( + DebugPlugin.ATTR_CONSOLE_ENCODING); + return new StreamsProxy(getSystemProcess(), encoding); + } + + /** + * Fires a creation event. + */ + protected void fireCreationEvent() { + fireEvent(new DebugEvent(this, DebugEvent.CREATE)); + } + + /** + * Fires the given debug event. + * + * @param event + * debug event to fire + */ + protected void fireEvent(DebugEvent event) { + DebugPlugin manager = DebugPlugin.getDefault(); + if (manager != null) { + manager.fireDebugEventSet(new DebugEvent[] { event }); + } + } + + /** + * Fires a terminate event. + */ + protected void fireTerminateEvent() { + fireEvent(new DebugEvent(this, DebugEvent.TERMINATE)); + } + + /** + * Fires a change event. + */ + protected void fireChangeEvent() { + fireEvent(new DebugEvent(this, DebugEvent.CHANGE)); + } + + /** + * @see IProcess#setAttribute(String, String) + */ + public void setAttribute(String key, String value) { + if (fAttributes == null) { + fAttributes = new HashMap(5); + } + Object origVal = fAttributes.get(key); + if (origVal != null && origVal.equals(value)) { + return; // nothing changed. + } + + fAttributes.put(key, value); + fireChangeEvent(); + } + + /** + * @see IProcess#getAttribute(String) + */ + public String getAttribute(String key) { + if (fAttributes == null) { + return null; + } + return (String) fAttributes.get(key); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class) + */ + public Object getAdapter(Class adapter) { + if (adapter.equals(IProcess.class)) { + return this; + } + if (adapter.equals(IDebugTarget.class)) { + ILaunch launch = getLaunch(); + IDebugTarget[] targets = launch.getDebugTargets(); + for (int i = 0; i < targets.length; i++) { + if (this.equals(targets[i].getProcess())) { + return targets[i]; + } + } + return null; + } + if (adapter.equals(ILaunch.class)) { + return getLaunch(); + } + // CONTEXTLAUNCHING + if (adapter.equals(ILaunchConfiguration.class)) { + return getLaunch().getLaunchConfiguration(); + } + return super.getAdapter(adapter); + } + + /** + * @see IProcess#getExitValue() + */ + public synchronized int getExitValue() throws DebugException { + if (isTerminated()) { + return fExitValue; + } + throw new DebugException( + new Status( + IStatus.ERROR, + DebugPlugin.getUniqueIdentifier(), + DebugException.TARGET_REQUEST_FAILED, + DebugCoreMessages.RuntimeProcess_Exit_value_not_available_until_process_terminates__1, + null)); + } + + /** + * Monitors a system process, waiting for it to terminate, and then notifies + * the associated runtime process. + */ + class ProcessMonitorThread extends Thread { + + /** + * Whether the thread has been told to exit. + */ + protected boolean fExit; + /** + * The underlying java.lang.Process being monitored. + */ + protected Process fOSProcess; + /** + * The IProcess which will be informed when this monitor + * detects that the underlying process has terminated. + */ + protected OprofileRuntimeProcess fRuntimeProcess; + + /** + * The Thread which is monitoring the underlying process. + */ + protected Thread fThread; + + /** + * A lock protecting access to fThread. + */ + private final Object fThreadLock = new Object(); + + /** + * @see Thread#run() + */ + public void run() { + synchronized (fThreadLock) { + if (fExit) { + return; + } + fThread = Thread.currentThread(); + } + while (fOSProcess != null) { + try { + fOSProcess.waitFor(); + } catch (InterruptedException ie) { + // clear interrupted state + Thread.interrupted(); + } finally { + fOSProcess = null; + fRuntimeProcess.terminated(); + } + } + fThread = null; + } + + /** + * Creates a new process monitor and starts monitoring the process for + * termination. + * + * @param process + * process to monitor for termination + */ + public ProcessMonitorThread(OprofileRuntimeProcess process) { + super(DebugCoreMessages.ProcessMonitorJob_0); + setDaemon(true); + fRuntimeProcess = process; + fOSProcess = process.getSystemProcess(); + } + + /** + * Kills the monitoring thread. + * + * This method is to be useful for dealing with the error case of an + * underlying process which has not informed this monitor of its + * termination. + */ + protected void killThread() { + synchronized (fThreadLock) { + if (fThread == null) { + fExit = true; + } else { + fThread.interrupt(); + } + } + } + } +} diff --git a/org.eclipse.linuxtools.oprofile.launch.exe/src/com/samsung/tizen/oprofile/launch/TizenOprofileLaunchDelegate.java b/org.eclipse.linuxtools.oprofile.launch.exe/src/com/samsung/tizen/oprofile/launch/TizenOprofileLaunchDelegate.java index fc10564..7963136 100644 --- a/org.eclipse.linuxtools.oprofile.launch.exe/src/com/samsung/tizen/oprofile/launch/TizenOprofileLaunchDelegate.java +++ b/org.eclipse.linuxtools.oprofile.launch.exe/src/com/samsung/tizen/oprofile/launch/TizenOprofileLaunchDelegate.java @@ -67,6 +67,16 @@ public class TizenOprofileLaunchDelegate extends TizenLaunchDelegate { protected static final String PACKAGE_NAME = "oprofile"; protected static final String PACKAGE_FILENAME_ARM = "oprofile_armel.deb"; + + protected static String appName = null; + + public static String getAppName() { + return appName; + } + + public static void setAppName(String appName) { + TizenOprofileLaunchDelegate.appName = appName; + } @Override public void launch(ILaunchConfiguration config, String mode, @@ -142,6 +152,7 @@ public class TizenOprofileLaunchDelegate extends TizenLaunchDelegate { ICDTLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS, ""); cmd = remoteExePath.trim(); + appName = remoteExePath; if (arguments != null && !arguments.equals("")) cmd += " " + arguments; @@ -170,7 +181,7 @@ public class TizenOprofileLaunchDelegate extends TizenLaunchDelegate { IPath exeFile = null; try { exeFile = CDebugUtils.verifyProgramPath(config); - DebugPlugin.newProcess(launch, oprofileProc, exeFile.toFile() + OprofileDebugPlugin.newProcess(launch, oprofileProc, exeFile.toFile() .getName()); BufferedReader br = new BufferedReader(new InputStreamReader( oprofileProc.getInputStream())); diff --git a/org.eclipse.linuxtools.valgrind.launch.exe/src/org/eclipse/linuxtools/valgrind/launch/TizenValgrindLaunchDelegate.java b/org.eclipse.linuxtools.valgrind.launch.exe/src/org/eclipse/linuxtools/valgrind/launch/TizenValgrindLaunchDelegate.java index de7886f..8415f5d 100644 --- a/org.eclipse.linuxtools.valgrind.launch.exe/src/org/eclipse/linuxtools/valgrind/launch/TizenValgrindLaunchDelegate.java +++ b/org.eclipse.linuxtools.valgrind.launch.exe/src/org/eclipse/linuxtools/valgrind/launch/TizenValgrindLaunchDelegate.java @@ -61,7 +61,6 @@ public class TizenValgrindLaunchDelegate extends TizenLaunchDelegate { protected IValgrindLaunchDelegate dynamicDelegate; protected ValgrindCommand command; - protected String toolID; protected static final String EQUALS = "="; protected static final String EMPTY_STRING = ""; @@ -71,6 +70,8 @@ public class TizenValgrindLaunchDelegate extends TizenLaunchDelegate { protected static final String PACKAGE_NAME = "valgrind"; protected static final String PACKAGE_FILENAME_ARM = "valgrind_armel.deb"; + + protected String toolID; @Override public void launch(ILaunchConfiguration config, String mode, @@ -252,7 +253,7 @@ public class TizenValgrindLaunchDelegate extends TizenLaunchDelegate { IPath exeFile = null; try { exeFile = CDebugUtils.verifyProgramPath(config); - DebugPlugin.newProcess(launch, oprofileProc, exeFile.toFile() + ValgrindDebugPlugin.newProcess(launch, oprofileProc, exeFile.toFile() .getName()); BufferedReader br = new BufferedReader(new InputStreamReader( oprofileProc.getInputStream())); @@ -505,5 +506,4 @@ public class TizenValgrindLaunchDelegate extends TizenLaunchDelegate { monitor.done(); } } - } diff --git a/org.eclipse.linuxtools.valgrind.launch.exe/src/org/eclipse/linuxtools/valgrind/launch/ValgrindDebugPlugin.java b/org.eclipse.linuxtools.valgrind.launch.exe/src/org/eclipse/linuxtools/valgrind/launch/ValgrindDebugPlugin.java new file mode 100644 index 0000000..df3e9a3 --- /dev/null +++ b/org.eclipse.linuxtools.valgrind.launch.exe/src/org/eclipse/linuxtools/valgrind/launch/ValgrindDebugPlugin.java @@ -0,0 +1,1596 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.linuxtools.valgrind.launch; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.FactoryConfigurationError; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.TransformerException; + +import org.eclipse.core.resources.ISaveContext; +import org.eclipse.core.resources.ISaveParticipant; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IAdapterManager; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExtensionPoint; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.ISafeRunnable; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.ListenerList; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.PlatformObject; +import org.eclipse.core.runtime.Plugin; +import org.eclipse.core.runtime.SafeRunner; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.debug.core.DebugEvent; +import org.eclipse.debug.core.IBreakpointManager; +import org.eclipse.debug.core.IDebugEventFilter; +import org.eclipse.debug.core.IDebugEventSetListener; +import org.eclipse.debug.core.IExpressionManager; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.ILaunchManager; +import org.eclipse.debug.core.ILogicalStructureType; +import org.eclipse.debug.core.IMemoryBlockManager; +import org.eclipse.debug.core.IProcessFactory; +import org.eclipse.debug.core.IStatusHandler; +import org.eclipse.debug.core.model.IDebugElement; +import org.eclipse.debug.core.model.IDisconnect; +import org.eclipse.debug.core.model.IDropToFrame; +import org.eclipse.debug.core.model.IProcess; +import org.eclipse.debug.core.model.IStep; +import org.eclipse.debug.core.model.IStepFilters; +import org.eclipse.debug.core.model.ISuspendResume; +import org.eclipse.debug.core.model.ITerminate; +import org.eclipse.debug.core.model.IValue; +import org.eclipse.debug.core.model.RuntimeProcess; +import org.eclipse.debug.internal.core.BreakpointManager; +import org.eclipse.debug.internal.core.DebugCoreMessages; +import org.eclipse.debug.internal.core.DebugOptions; +import org.eclipse.debug.internal.core.ExpressionManager; +import org.eclipse.debug.internal.core.IConfigurationElementConstants; +import org.eclipse.debug.internal.core.IInternalDebugCoreConstants; +import org.eclipse.debug.internal.core.LaunchManager; +import org.eclipse.debug.internal.core.LogicalStructureManager; +import org.eclipse.debug.internal.core.MemoryBlockManager; +import org.eclipse.debug.internal.core.Preferences; +import org.eclipse.debug.internal.core.StepFilterManager; +import org.eclipse.debug.internal.core.commands.CommandAdapterFactory; +import org.eclipse.debug.internal.core.sourcelookup.SourceLookupUtils; +import org.eclipse.osgi.service.environment.Constants; +import org.osgi.framework.BundleContext; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +/** + * There is one instance of the debug plug-in available from + * DebugPlugin.getDefault(). The debug plug-in provides: + * + * + * @noinstantiate This class is not intended to be instantiated by clients. + * @noextend This class is not intended to be subclassed by clients. + */ +public class ValgrindDebugPlugin extends Plugin { + + /** + * Unique identifier constant (value "org.eclipse.debug.core") + * for the Debug Core plug-in. + */ + private static final String PI_DEBUG_CORE = "org.eclipse.debug.core"; //$NON-NLS-1$ + + /** + * Simple identifier constant (value "launchConfigurationTypes" + * ) for the launch configuration types extension point. + * + * @since 2.0 + */ + public static final String EXTENSION_POINT_LAUNCH_CONFIGURATION_TYPES = "launchConfigurationTypes"; //$NON-NLS-1$ + + /** + * Simple identifier constant (value + * "launchConfigurationComparators") for the launch + * configuration comparators extension point. + * + * @since 2.0 + */ + public static final String EXTENSION_POINT_LAUNCH_CONFIGURATION_COMPARATORS = "launchConfigurationComparators"; //$NON-NLS-1$ + + /** + * Simple identifier constant (value "breakpoints") for the + * breakpoints extension point. + * + * @since 2.0 + */ + public static final String EXTENSION_POINT_BREAKPOINTS = "breakpoints"; //$NON-NLS-1$ + + /** + * Simple identifier constant (value "statusHandlers") for the + * status handlers extension point. + * + * @since 2.0 + */ + public static final String EXTENSION_POINT_STATUS_HANDLERS = "statusHandlers"; //$NON-NLS-1$ + + /** + * Simple identifier constant (value "sourceLocators") for the + * source locators extension point. + * + * @since 2.0 + */ + public static final String EXTENSION_POINT_SOURCE_LOCATORS = "sourceLocators"; //$NON-NLS-1$ + + /** + * Simple identifier constant (value "launchModes") for the + * source modes extension point. + * + * @since 3.0 + */ + public static final String EXTENSION_POINT_LAUNCH_MODES = "launchModes"; //$NON-NLS-1$ + + /** + * Simple identifier constant (value "launchDelegates") for the + * launch delegates extension point. + * + * @since 3.0 + */ + public static final String EXTENSION_POINT_LAUNCH_DELEGATES = "launchDelegates"; //$NON-NLS-1$ + + /** + * Simple identifier constant (value "processFactories") for + * the process factories extension point. + * + * @since 3.0 + */ + public static final String EXTENSION_POINT_PROCESS_FACTORIES = "processFactories"; //$NON-NLS-1$ + + /** + * Simple identifier constant (value "logicalStructureTypes") + * for the logical structure types extension point. + * + * @since 3.0 + */ + public static final String EXTENSION_POINT_LOGICAL_STRUCTURE_TYPES = "logicalStructureTypes"; //$NON-NLS-1$ + + /** + * Simple identifier constant (value + * "logicalStructureProviders") for the logical structure types + * extension point. + * + * @since 3.1 + */ + public static final String EXTENSION_POINT_LOGICAL_STRUCTURE_PROVIDERS = "logicalStructureProviders"; //$NON-NLS-1$ + + /** + * Simple identifier constant (value "sourceContainerTypes") + * for the source container types extension point. + * + * @since 3.0 + */ + public static final String EXTENSION_POINT_SOURCE_CONTAINER_TYPES = "sourceContainerTypes"; //$NON-NLS-1$ + + /** + * Simple identifier constant (value "sourcePathComputers") for + * the source path computers extension point. + * + * @since 3.0 + */ + public static final String EXTENSION_POINT_SOURCE_PATH_COMPUTERS = "sourcePathComputers"; //$NON-NLS-1$ + + /** + * Simple identifier constant for the launch options extension point + * + * @since 3.3 + */ + public static final String EXTENSION_POINT_LAUNCH_OPTIONS = "launchOptions"; //$NON-NLS-1$ + + /** + * Simple identifier constant for the breakpoint import participant + * extension point + * + * @since 3.5 + */ + public static final String EXTENSION_POINT_BREAKPOINT_IMPORT_PARTICIPANTS = "breakpointImportParticipants"; //$NON-NLS-1$ + + /** + * Status code indicating an unexpected error. + * + * @since 3.4 + */ + public static final int ERROR = 125; + + /** + * Status code indicating an unexpected internal error. Internal errors + * should never be displayed to the user in dialogs or status text. Internal + * error messages are not translated. + */ + public static final int INTERNAL_ERROR = 120; + + /** + * Status code indicating that the Eclipse runtime does not support + * launching a program with a working directory. This feature is only + * available if Eclipse is run on a 1.3 runtime or higher. + *

+ * A status handler may be registered for this error condition, and should + * return a Boolean indicating whether the program should be + * re-launched with the default working directory. + *

+ */ + public static final int ERR_WORKING_DIRECTORY_NOT_SUPPORTED = 115; + + /** + * The launch configuration attribute that designates the process factory ID + * for the process factory to be used when creating a new process as a + * result of launching the launch configuration. + * + * @since 3.0 + */ + public static final String ATTR_PROCESS_FACTORY_ID = "process_factory_id"; //$NON-NLS-1$ + + /** + * The launch attribute that designates whether or not it's associated + * launch should capture output. Value is a string representing a boolean - + * true or false. When unspecified, the default + * value is considered true. + * + * @since 3.1 + */ + public static final String ATTR_CAPTURE_OUTPUT = PI_DEBUG_CORE + + ".capture_output"; //$NON-NLS-1$ + + /** + * The launch attribute that stores the time stamp of when a launch + * configuration was launched. Value is {@link Long#toString(long)} of + * {@link System#currentTimeMillis()}. + * + * @since 3.6 + */ + public static final String ATTR_LAUNCH_TIMESTAMP = PI_DEBUG_CORE + + ".launch.timestamp"; //$NON-NLS-1$ + + /** + * This launch attribute designates the encoding to be used by the console + * associated with the launch. + *

+ * For release 3.3, the system encoding is used when unspecified. Since 3.4, + * the inherited encoding is used when unspecified. See + * {@link ILaunchManager} for a description in + * getEncoding(ILaunchConfiguration). + *

+ *

+ * Value of this constant is the same as the value of the old + * IDebugUIConstants.ATTR_CONSOLE_ENCODING constant for + * backward compatibility. + *

+ * + * @since 3.3 + */ + public static final String ATTR_CONSOLE_ENCODING = "org.eclipse.debug.ui.ATTR_CONSOLE_ENCODING"; //$NON-NLS-1$ + + /** + * Boolean preference key (value + * org.eclipse.debug.core.PREF_DELETE_CONFIGS_ON_PROJECT_DELETE + * ) that controls whether to delete associated configurations when a + * project is deleted. Default value is false. + * + * @since 3.7 + */ + public static final String PREF_DELETE_CONFIGS_ON_PROJECT_DELETE = ValgrindDebugPlugin + .getUniqueIdentifier() + ".PREF_DELETE_CONFIGS_ON_PROJECT_DELETE"; //$NON-NLS-1$ + + /** + * Deleted breakpoint marker attribute (value + * "org.eclipse.debug.core.breakpointIsDeleted"). The attribute + * is a boolean corresponding to the deleted state of a + * breakpoint. + * + * @see org.eclipse.core.resources.IMarker#getAttribute(String, boolean) + * @since 3.7 + */ + public static final String ATTR_BREAKPOINT_IS_DELETED = ValgrindDebugPlugin + .getUniqueIdentifier() + ".breakpointIsDeleted"; //$NON-NLS-1$ + + /** + * The singleton debug plug-in instance. + */ + private static ValgrindDebugPlugin fgDebugPlugin = null; + + /** + * The singleton breakpoint manager. + */ + private BreakpointManager fBreakpointManager; + + /** + * The singleton expression manager. + */ + private ExpressionManager fExpressionManager; + + /** + * The singleton launch manager. + */ + private LaunchManager fLaunchManager; + + /** + * The singleton memory block manager. + * + * @since 3.1 + */ + private MemoryBlockManager fMemoryBlockManager; + + /** + * The collection of debug event listeners. + */ + private ListenerList fEventListeners = new ListenerList(); + + /** + * Event filters, or null if none. + */ + private ListenerList fEventFilters = new ListenerList(); + + /** + * Whether this plug-in is in the process of shutting down. + */ + private boolean fShuttingDown = false; + + /** + * Table of status handlers. Keys are {plug-in identifier, status code} + * pairs, and values are associated IConfigurationElements. + */ + private HashMap fStatusHandlers = null; + + /** + * Map of process factories. Keys are process factory IDs and values are + * associated IConfigurationElements. + * + * @since 3.0 + */ + private HashMap fProcessFactories = null; + + /** + * Mode constants for the event notifier + */ + private static final int NOTIFY_FILTERS = 0; + private static final int NOTIFY_EVENTS = 1; + + /** + * Queue of debug events to fire to listeners and asynchronous runnables to + * execute in the order received. + * + * @since 3.1 + */ + private List fEventQueue = new ArrayList(); + + /** + * Job to fire events to listeners. + * + * @since 3.1 + */ + private EventDispatchJob fEventDispatchJob = new EventDispatchJob(); + + /** + * Event dispatch job. Processes event queue of debug events and runnables. + * + * @since 3.1 + */ + class EventDispatchJob extends Job { + + EventNotifier fNotifier = new EventNotifier(); + AsynchRunner fRunner = new AsynchRunner(); + + /** + * Creates a new event dispatch job. + */ + public EventDispatchJob() { + super(DebugCoreMessages.DebugPlugin_1); + setPriority(Job.INTERACTIVE); + setSystem(true); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime. + * IProgressMonitor) + */ + protected IStatus run(IProgressMonitor monitor) { + + while (!fEventQueue.isEmpty()) { + Object next = null; + synchronized (fEventQueue) { + if (!fEventQueue.isEmpty()) { + next = fEventQueue.remove(0); + } + } + if (next instanceof Runnable) { + fRunner.async((Runnable) next); + } else if (next != null) { + fNotifier.dispatch((DebugEvent[]) next); + } + } + return Status.OK_STATUS; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.jobs.Job#shouldRun() + */ + public boolean shouldRun() { + return shouldSchedule(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.internal.jobs.InternalJob#shouldSchedule() + */ + public boolean shouldSchedule() { + return !(isShuttingDown() || fEventListeners.isEmpty()); + } + + } + + /** + * Returns the singleton instance of the debug plug-in. + * + * @return the debug plug-in + */ + public static ValgrindDebugPlugin getDefault() { + return fgDebugPlugin; + } + + /** + * Sets the singleton instance of the debug plug-in. + * + * @param plugin + * the debug plug-in, or null when shutting down + */ + private static void setDefault(ValgrindDebugPlugin plugin) { + fgDebugPlugin = plugin; + } + + /** + * Convenience method which returns the unique identifier of this plug-in. + * + * @return debug plug-in identifier + */ + public static String getUniqueIdentifier() { + return PI_DEBUG_CORE; + } + + /** + * Constructs the debug plug-in. + *

+ * An instance of this plug-in runtime class is automatically created when + * the facilities provided by this plug-in are required. Clients must + * never explicitly instantiate a plug-in runtime class. + *

+ */ + public ValgrindDebugPlugin() { + super(); + setDefault(this); + } + + /** + * Adds the given listener to the collection of registered debug event + * listeners. Has no effect if an identical listener is already registered. + * + * @param listener + * the listener to add + * @since 2.0 + */ + public void addDebugEventListener(IDebugEventSetListener listener) { + fEventListeners.add(listener); + } + + /** + * Notifies all registered debug event set listeners of the given debug + * events. Events which are filtered by a registered debug event filter are + * not fired. + * + * @param events + * array of debug events to fire + * @see IDebugEventFilter + * @see IDebugEventSetListener + * @since 2.0 + */ + public void fireDebugEventSet(DebugEvent[] events) { + if (isShuttingDown() || events == null || fEventListeners.isEmpty()) + return; + synchronized (fEventQueue) { + fEventQueue.add(events); + } + fEventDispatchJob.schedule(); + } + + /** + * Asynchronously executes the given runnable in a separate thread, after + * debug event dispatch has completed. If debug events are not currently + * being dispatched, the runnable is scheduled to run in a separate thread + * immediately. + * + * @param r + * runnable to execute asynchronously + * @since 2.1 + */ + public void asyncExec(Runnable r) { + synchronized (fEventQueue) { + fEventQueue.add(r); + } + fEventDispatchJob.schedule(); + } + + /** + * Returns the breakpoint manager. + * + * @return the breakpoint manager + * @see IBreakpointManager + */ + public synchronized IBreakpointManager getBreakpointManager() { + if (fBreakpointManager == null) { + fBreakpointManager = new BreakpointManager(); + } + return fBreakpointManager; + } + + /** + * Returns the launch manager. + * + * @return the launch manager + * @see ILaunchManager + */ + public synchronized ILaunchManager getLaunchManager() { + if (fLaunchManager == null) { + fLaunchManager = new LaunchManager(); + } + return fLaunchManager; + } + + /** + * Returns the memory block manager. + * + * @return the memory block manager. + * @see IMemoryBlockManager + * @since 3.1 + */ + public synchronized IMemoryBlockManager getMemoryBlockManager() { + if (fMemoryBlockManager == null) { + fMemoryBlockManager = new MemoryBlockManager(); + } + return fMemoryBlockManager; + } + + /** + * Returns the status handler registered for the given status, or + * null if none. + * + * @param status + * status for which a status handler has been requested + * @return the status handler registered for the given status, or + * null if none + * @since 2.0 + */ + public IStatusHandler getStatusHandler(IStatus status) { + boolean enabled = Platform.getPreferencesService().getBoolean( + ValgrindDebugPlugin.getUniqueIdentifier(), + IInternalDebugCoreConstants.PREF_ENABLE_STATUS_HANDLERS, true, + null); + if (!enabled) { + return null; + } + StatusHandlerKey key = new StatusHandlerKey(status.getPlugin(), + status.getCode()); + if (fStatusHandlers == null) { + initializeStatusHandlers(); + } + IConfigurationElement config = (IConfigurationElement) fStatusHandlers + .get(key); + if (config != null) { + try { + Object handler = config + .createExecutableExtension(IConfigurationElementConstants.CLASS); + if (handler instanceof IStatusHandler) { + return (IStatusHandler) handler; + } + invalidStatusHandler( + null, + MessageFormat + .format("Registered status handler {0} does not implement required interface IStatusHandler.", new String[] { config.getDeclaringExtension().getUniqueIdentifier() })); //$NON-NLS-1$ + } catch (CoreException e) { + log(e); + } + } + return null; + } + + /** + * Returns the expression manager. + * + * @return the expression manager + * @see IExpressionManager + * @since 2.0 + */ + public synchronized IExpressionManager getExpressionManager() { + if (fExpressionManager == null) { + fExpressionManager = new ExpressionManager(); + } + return fExpressionManager; + } + + /** + * Removes the given listener from the collection of registered debug event + * listeners. Has no effect if an identical listener is not already + * registered. + * + * @param listener + * the listener to remove + * @since 2.0 + */ + public void removeDebugEventListener(IDebugEventSetListener listener) { + fEventListeners.remove(listener); + } + + /* + * (non-Javadoc) + * + * @see + * org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext context) throws Exception { + try { + setShuttingDown(true); + + if (fLaunchManager != null) { + fLaunchManager.shutdown(); + } + if (fBreakpointManager != null) { + fBreakpointManager.shutdown(); + } + if (fMemoryBlockManager != null) { + fMemoryBlockManager.shutdown(); + } + + fEventListeners.clear(); + fEventFilters.clear(); + + SourceLookupUtils.shutdown(); + Preferences.savePreferences(ValgrindDebugPlugin + .getUniqueIdentifier()); + ResourcesPlugin.getWorkspace().removeSaveParticipant( + getUniqueIdentifier()); + } finally { + super.stop(context); + setDefault(null); + } + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.core.runtime.Plugin#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext context) throws Exception { + super.start(context); + DebugOptions.initDebugOptions(); + ResourcesPlugin.getWorkspace().addSaveParticipant( + getUniqueIdentifier(), new ISaveParticipant() { + public void saving(ISaveContext saveContext) + throws CoreException { + if (fExpressionManager != null) { + fExpressionManager.storeWatchExpressions(); + } + Preferences.savePreferences(ValgrindDebugPlugin + .getUniqueIdentifier()); + } + + public void rollback(ISaveContext saveContext) { + } + + public void prepareToSave(ISaveContext saveContext) + throws CoreException { + } + + public void doneSaving(ISaveContext saveContext) { + } + }); + // command adapters + IAdapterManager manager = Platform.getAdapterManager(); + CommandAdapterFactory actionFactory = new CommandAdapterFactory(); + manager.registerAdapters(actionFactory, IDisconnect.class); + manager.registerAdapters(actionFactory, IDropToFrame.class); + manager.registerAdapters(actionFactory, IStep.class); + manager.registerAdapters(actionFactory, IStepFilters.class); + manager.registerAdapters(actionFactory, ISuspendResume.class); + manager.registerAdapters(actionFactory, ITerminate.class); + manager.registerAdapters(actionFactory, ILaunch.class); + manager.registerAdapters(actionFactory, IProcess.class); + manager.registerAdapters(actionFactory, IDebugElement.class); + } + + /** + * Creates and returns a new process representing the given + * java.lang.Process. A streams proxy is created for the I/O + * streams in the system process. The process is added to the given launch. + *

+ * If the launch configuration associated with the given launch specifies a + * process factory, it will be used to instantiate the new process. + *

+ * + * @param launch + * the launch the process is contained in + * @param process + * the system process to wrap + * @param label + * the label assigned to the process + * @return the process + * @see IProcess + * @see IProcessFactory + */ + public static IProcess newProcess(ILaunch launch, Process process, + String label) { + return newProcess(launch, process, label, null); + } + + /** + * Creates and returns a new process representing the given + * java.lang.Process. A streams proxy is created for the I/O + * streams in the system process. The process is added to the given launch, + * and the process is initialized with the given attribute map. + *

+ * If the launch configuration associated with the given launch specifies a + * process factory, it will be used to instantiate the new process. + *

+ * + * @param launch + * the launch the process is contained in + * @param process + * the system process to wrap + * @param label + * the label assigned to the process + * @param attributes + * initial values for the attribute map + * @return the process null can be returned if errors occur + * dealing with the process factory designated to create the + * process. + * @see IProcess + * @see IProcessFactory + * @since 2.1 + */ + public static IProcess newProcess(ILaunch launch, Process process, + String label, Map attributes) { + ILaunchConfiguration config = launch.getLaunchConfiguration(); + String processFactoryID = null; + if (config != null) { + try { + processFactoryID = config.getAttribute(ATTR_PROCESS_FACTORY_ID, + (String) null); + } catch (CoreException e) { + } + } + if (processFactoryID != null) { + ValgrindDebugPlugin plugin = ValgrindDebugPlugin.getDefault(); + if (plugin.fProcessFactories == null) { + plugin.initializeProcessFactories(); + } + IConfigurationElement element = (IConfigurationElement) plugin.fProcessFactories + .get(processFactoryID); + if (element == null) { + return null; + } + IProcessFactory processFactory = null; + try { + processFactory = (IProcessFactory) element + .createExecutableExtension(IConfigurationElementConstants.CLASS); + } catch (CoreException exception) { + log(exception); + return null; + } + return processFactory + .newProcess(launch, process, label, attributes); + } + return new ValgrindRuntimeProcess(launch, process, label, attributes); + } + + /** + * Returns any logical structure types that have been contributed for the + * given value. + * + * @param value + * the value for which logical structure types have been + * requested + * @return logical structure types that have been contributed for the given + * value, possibly an empty collection + * + * @since 3.0 + */ + public static ILogicalStructureType[] getLogicalStructureTypes(IValue value) { + return LogicalStructureManager.getDefault().getLogicalStructureTypes( + value); + } + + /** + * Returns the default logical structure type among the given combination of + * logical structure types, or null if none. When the given + * combination of logical structure type is applicable for a value, the + * default logical structure type is used to display a value. + * + * @param types + * a combination of structures applicable to a value + * @return the default structure that should be used to display the value or + * null if none + * + * @since 3.1 + */ + public static ILogicalStructureType getDefaultStructureType( + ILogicalStructureType[] types) { + return LogicalStructureManager.getDefault().getSelectedStructureType( + types); + } + + /** + * Sets the default logical structure type among the given combination of + * logical structure types. The logical structure types provided should all + * be applicable to a single value. Specifying null indicates + * there is no default logical structure for the given combination of types. + * + * @param types + * a combination of logical structure types applicable to a value + * @param def + * the default logical structure among the given combination of + * types or null if none + * + * @since 3.1 + */ + public static void setDefaultStructureType(ILogicalStructureType[] types, + ILogicalStructureType def) { + LogicalStructureManager.getDefault().setEnabledType(types, def); + } + + /** + * Convenience method that performs a runtime exec on the given command line + * in the context of the specified working directory, and returns the + * resulting process. If the current runtime does not support the + * specification of a working directory, the status handler for error code + * ERR_WORKING_DIRECTORY_NOT_SUPPORTED is queried to see if the + * exec should be re-executed without specifying a working directory. + * + * @param cmdLine + * the command line + * @param workingDirectory + * the working directory, or null + * @return the resulting process or null if the exec is + * canceled + * @exception CoreException + * if the exec fails + * @see Runtime + * + * @since 2.1 + */ + public static Process exec(String[] cmdLine, File workingDirectory) + throws CoreException { + return exec(cmdLine, workingDirectory, null); + } + + /** + * Convenience method that performs a runtime exec on the given command line + * in the context of the specified working directory, and returns the + * resulting process. If the current runtime does not support the + * specification of a working directory, the status handler for error code + * ERR_WORKING_DIRECTORY_NOT_SUPPORTED is queried to see if the + * exec should be re-executed without specifying a working directory. + * + * @param cmdLine + * the command line + * @param workingDirectory + * the working directory, or null + * @param envp + * the environment variables set in the process, or + * null + * @return the resulting process or null if the exec is + * canceled + * @exception CoreException + * if the exec fails + * @see Runtime + * + * @since 3.0 + */ + public static Process exec(String[] cmdLine, File workingDirectory, + String[] envp) throws CoreException { + Process p = null; + try { + if (workingDirectory == null) { + p = Runtime.getRuntime().exec(cmdLine, envp); + } else { + p = Runtime.getRuntime().exec(cmdLine, envp, workingDirectory); + } + } catch (IOException e) { + Status status = new Status(IStatus.ERROR, getUniqueIdentifier(), + ERROR, DebugCoreMessages.DebugPlugin_0, e); + throw new CoreException(status); + } catch (NoSuchMethodError e) { + // attempting launches on 1.2.* - no ability to set working + // directory + IStatus status = new Status( + IStatus.ERROR, + getUniqueIdentifier(), + ERR_WORKING_DIRECTORY_NOT_SUPPORTED, + DebugCoreMessages.DebugPlugin_Eclipse_runtime_does_not_support_working_directory_2, + e); + IStatusHandler handler = ValgrindDebugPlugin.getDefault() + .getStatusHandler(status); + + if (handler != null) { + Object result = handler.handleStatus(status, null); + if (result instanceof Boolean + && ((Boolean) result).booleanValue()) { + p = exec(cmdLine, null); + } + } + } + return p; + } + + /** + * Returns whether this plug-in is in the process of being shutdown. + * + * @return whether this plug-in is in the process of being shutdown + */ + private boolean isShuttingDown() { + return fShuttingDown; + } + + /** + * Sets whether this plug-in is in the process of being shutdown. + * + * @param value + * whether this plug-in is in the process of being shutdown + */ + private void setShuttingDown(boolean value) { + fShuttingDown = value; + } + + /** + * Returns the collection of debug event listeners registered with this + * plug-in. + * + * @return list of registered debug event listeners, instances of + * IDebugEventSetListeners + */ + private Object[] getEventListeners() { + return fEventListeners.getListeners(); + } + + /** + * Adds the given debug event filter to the registered event filters. Has no + * effect if an identical filter is already registered. + * + * @param filter + * debug event filter + * @since 2.0 + */ + public void addDebugEventFilter(IDebugEventFilter filter) { + fEventFilters.add(filter); + } + + /** + * Removes the given debug event filter from the registered event filters. + * Has no effect if an identical filter is not already registered. + * + * @param filter + * debug event filter + * @since 2.0 + */ + public void removeDebugEventFilter(IDebugEventFilter filter) { + fEventFilters.remove(filter); + } + + /** + * Logs the given message if in debug mode. + * + * @param message + * the message to log + * @since 2.0 + */ + public static void logDebugMessage(String message) { + if (getDefault().isDebugging()) { + // this message is intentionally not externalized, as an exception + // may + // be due to the resource bundle itself + log(new Status(IStatus.ERROR, getUniqueIdentifier(), ERROR, + MessageFormat.format(DebugCoreMessages.DebugPlugin_2, + new String[] { message }), null)); + } + } + + /** + * Logs the given message with this plug-in's log and the given throwable or + * null if none. + * + * @param message + * the message to log + * @param throwable + * the exception that occurred or null if none + */ + public static void logMessage(String message, Throwable throwable) { + log(new Status(IStatus.ERROR, getUniqueIdentifier(), ERROR, message, + throwable)); + } + + /** + * Logs the specified status with this plug-in's log. + * + * @param status + * status to log + * @since 2.0 + */ + public static void log(IStatus status) { + getDefault().getLog().log(status); + } + + /** + * Logs the specified throwable with this plug-in's log. + * + * @param t + * throwable to log + * @since 2.0 + */ + public static void log(Throwable t) { + IStatus status = new Status(IStatus.ERROR, getUniqueIdentifier(), + ERROR, DebugCoreMessages.DebugPlugin_3, t); + log(status); + } + + /** + * Register status handlers. + * + */ + private void initializeStatusHandlers() { + IExtensionPoint extensionPoint = Platform.getExtensionRegistry() + .getExtensionPoint(ValgrindDebugPlugin.PI_DEBUG_CORE, + EXTENSION_POINT_STATUS_HANDLERS); + IConfigurationElement[] infos = extensionPoint + .getConfigurationElements(); + fStatusHandlers = new HashMap(infos.length); + for (int i = 0; i < infos.length; i++) { + IConfigurationElement configurationElement = infos[i]; + String id = configurationElement.getAttribute("plugin"); //$NON-NLS-1$ + String code = configurationElement.getAttribute("code"); //$NON-NLS-1$ + + if (id != null && code != null) { + try { + StatusHandlerKey key = new StatusHandlerKey(id, + Integer.parseInt(code)); + fStatusHandlers.put(key, configurationElement); + } catch (NumberFormatException e) { + // invalid status handler + invalidStatusHandler(e, + configurationElement.getAttribute("id")); //$NON-NLS-1$ + } + } else { + // invalid status handler + invalidStatusHandler(null, + configurationElement.getAttribute("id")); //$NON-NLS-1$ + } + } + } + + /** + * Register process factories. + * + */ + private void initializeProcessFactories() { + IExtensionPoint extensionPoint = Platform.getExtensionRegistry() + .getExtensionPoint(ValgrindDebugPlugin.PI_DEBUG_CORE, + EXTENSION_POINT_PROCESS_FACTORIES); + IConfigurationElement[] infos = extensionPoint + .getConfigurationElements(); + fProcessFactories = new HashMap(infos.length); + for (int i = 0; i < infos.length; i++) { + IConfigurationElement configurationElement = infos[i]; + String id = configurationElement.getAttribute("id"); //$NON-NLS-1$ + String clss = configurationElement.getAttribute("class"); //$NON-NLS-1$ + if (id != null && clss != null) { + fProcessFactories.put(id, configurationElement); + } else { + // invalid process factory + String badDefiner = infos[i].getContributor().getName(); + log(new Status(IStatus.ERROR, + ValgrindDebugPlugin.PI_DEBUG_CORE, ERROR, + MessageFormat.format(DebugCoreMessages.DebugPlugin_4, + new String[] { badDefiner, id }), null)); + } + } + } + + private void invalidStatusHandler(Exception e, String id) { + log(new Status(IStatus.ERROR, ValgrindDebugPlugin.PI_DEBUG_CORE, ERROR, + MessageFormat.format(DebugCoreMessages.DebugPlugin_5, + new String[] { id }), e)); + } + + /** + * Key for status handler extensions - a plug-in identifier/code pair + */ + class StatusHandlerKey { + + String fPluginId; + int fCode; + + StatusHandlerKey(String pluginId, int code) { + fPluginId = pluginId; + fCode = code; + } + + public int hashCode() { + return fPluginId.hashCode() + fCode; + } + + public boolean equals(Object obj) { + if (obj instanceof StatusHandlerKey) { + StatusHandlerKey s = (StatusHandlerKey) obj; + return fCode == s.fCode && fPluginId.equals(s.fPluginId); + } + return false; + } + } + + /** + * Executes runnables after event dispatch is complete. + * + * @since 3.0 + */ + class AsynchRunner implements ISafeRunnable { + + private Runnable fRunnable = null; + + void async(Runnable runnable) { + fRunnable = runnable; + SafeRunner.run(this); + fRunnable = null; + + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.core.runtime.ISafeRunnable#handleException(java.lang. + * Throwable) + */ + public void handleException(Throwable exception) { + IStatus status = new Status(IStatus.ERROR, getUniqueIdentifier(), + ERROR, DebugCoreMessages.DebugPlugin_6, exception); + log(status); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.ISafeRunnable#run() + */ + public void run() throws Exception { + fRunnable.run(); + } + + } + + /** + * Filters and dispatches events in a safe runnable to handle any + * exceptions. + */ + class EventNotifier implements ISafeRunnable { + + private DebugEvent[] fEvents; + private IDebugEventSetListener fListener; + private IDebugEventFilter fFilter; + private int fMode; + + /** + * @see org.eclipse.core.runtime.ISafeRunnable#handleException(java.lang.Throwable) + */ + public void handleException(Throwable exception) { + switch (fMode) { + case NOTIFY_FILTERS: + IStatus status = new Status(IStatus.ERROR, + getUniqueIdentifier(), ERROR, + DebugCoreMessages.DebugPlugin_7, exception); + log(status); + break; + case NOTIFY_EVENTS: + status = new Status(IStatus.ERROR, getUniqueIdentifier(), + ERROR, DebugCoreMessages.DebugPlugin_8, exception); + log(status); + break; + } + } + + /** + * @see org.eclipse.core.runtime.ISafeRunnable#run() + */ + public void run() throws Exception { + switch (fMode) { + case NOTIFY_FILTERS: + fEvents = fFilter.filterDebugEvents(fEvents); + break; + case NOTIFY_EVENTS: + fListener.handleDebugEvents(fEvents); + break; + } + } + + /** + * Filter and dispatch the given events. If an exception occurs in one + * listener, events are still fired to subsequent listeners. + * + * @param events + * debug events + */ + void dispatch(DebugEvent[] events) { + fEvents = events; + Object[] filters = fEventFilters.getListeners(); + if (filters.length > 0) { + fMode = NOTIFY_FILTERS; + for (int i = 0; i < filters.length; i++) { + fFilter = (IDebugEventFilter) filters[i]; + SafeRunner.run(this); + if (fEvents == null || fEvents.length == 0) { + return; + } + } + } + + fMode = NOTIFY_EVENTS; + Object[] listeners = getEventListeners(); + if (DebugOptions.DEBUG_EVENTS) { + for (int i = 0; i < fEvents.length; i++) { + System.out.println(fEvents[i]); + } + } + for (int i = 0; i < listeners.length; i++) { + fListener = (IDebugEventSetListener) listeners[i]; + SafeRunner.run(this); + } + fEvents = null; + fFilter = null; + fListener = null; + } + + } + + /** + * Creates and returns a new XML document. + * + * @return a new XML document + * @throws CoreException + * if unable to create a new document + * @since 3.0 + */ + public static Document newDocument() throws CoreException { + try { + return LaunchManager.getDocument(); + } catch (ParserConfigurationException e) { + abort("Unable to create new XML document.", e); //$NON-NLS-1$ + } + return null; + } + + /** + * Serializes the given XML document into a string. + * + * @param document + * XML document to serialize + * @return a string representing the given document + * @throws CoreException + * if unable to serialize the document + * @since 3.0 + */ + public static String serializeDocument(Document document) + throws CoreException { + try { + return LaunchManager.serializeDocument(document); + } catch (TransformerException e) { + abort("Unable to serialize XML document.", e); //$NON-NLS-1$ + } catch (IOException e) { + abort("Unable to serialize XML document.", e); //$NON-NLS-1$ + } + return null; + } + + /** + * Parses the given string representing an XML document, returning its root + * element. + * + * @param document + * XML document as a string + * @return the document's root element + * @throws CoreException + * if unable to parse the document + * @since 3.0 + */ + public static Element parseDocument(String document) throws CoreException { + Element root = null; + InputStream stream = null; + try { + DocumentBuilder parser = DocumentBuilderFactory.newInstance() + .newDocumentBuilder(); + parser.setErrorHandler(new DefaultHandler()); + stream = new ByteArrayInputStream(document.getBytes("UTF8")); //$NON-NLS-1$ + root = parser.parse(stream).getDocumentElement(); + } catch (ParserConfigurationException e) { + abort("Unable to parse XML document.", e); //$NON-NLS-1$ + } catch (FactoryConfigurationError e) { + abort("Unable to parse XML document.", e); //$NON-NLS-1$ + } catch (SAXException e) { + abort("Unable to parse XML document.", e); //$NON-NLS-1$ + } catch (IOException e) { + abort("Unable to parse XML document.", e); //$NON-NLS-1$ + } finally { + try { + if (stream != null) { + stream.close(); + } + } catch (IOException e) { + abort("Unable to parse XML document.", e); //$NON-NLS-1$ + } + } + return root; + } + + /** + * Throws an exception with the given message and underlying exception. + * + * @param message + * error message + * @param exception + * underlying exception, or null + * @throws CoreException + */ + private static void abort(String message, Throwable exception) + throws CoreException { + IStatus status = new Status(IStatus.ERROR, + ValgrindDebugPlugin.getUniqueIdentifier(), + ValgrindDebugPlugin.ERROR, message, exception); + throw new CoreException(status); + } + + /** + * Utility class to parse command line arguments. + * + * @since 3.1 + */ + private static class ArgumentParser { + private String fArgs; + private int fIndex = 0; + private int ch = -1; + + public ArgumentParser(String args) { + fArgs = args; + } + + public String[] parseArguments() { + List v = new ArrayList(); + + ch = getNext(); + while (ch > 0) { + if (Character.isWhitespace((char) ch)) { + ch = getNext(); + } else { + if (ch == '"') { + StringBuffer buf = new StringBuffer(); + buf.append(parseString()); + if (buf.length() == 0 + && Platform.getOS().equals(Constants.OS_WIN32)) { + // empty string on windows platform + buf.append("\"\""); //$NON-NLS-1$ + } + v.add(buf.toString()); + } else { + v.add(parseToken()); + } + } + } + + String[] result = new String[v.size()]; + v.toArray(result); + return result; + } + + private int getNext() { + if (fIndex < fArgs.length()) + return fArgs.charAt(fIndex++); + return -1; + } + + private String parseString() { + ch = getNext(); + if (ch == '"') { + ch = getNext(); + return ""; //$NON-NLS-1$ + } + StringBuffer buf = new StringBuffer(); + while (ch > 0 && ch != '"') { + if (ch == '\\') { + ch = getNext(); + if (ch != '"') { // Only escape double quotes + buf.append('\\'); + } else { + if (Platform.getOS().equals(Constants.OS_WIN32)) { + // @see Bug 26870. Windows requires an extra escape + // for embedded strings + buf.append('\\'); + } + } + } + if (ch > 0) { + buf.append((char) ch); + ch = getNext(); + } + } + ch = getNext(); + return buf.toString(); + } + + private String parseToken() { + StringBuffer buf = new StringBuffer(); + + while (ch > 0 && !Character.isWhitespace((char) ch)) { + if (ch == '\\') { + ch = getNext(); + if (Character.isWhitespace((char) ch)) { + // end of token, don't lose trailing backslash + buf.append('\\'); + return buf.toString(); + } + if (ch > 0) { + if (ch != '"') { // Only escape double quotes + buf.append('\\'); + } else { + if (Platform.getOS().equals(Constants.OS_WIN32)) { + // @see Bug 26870. Windows requires an extra + // escape for embedded strings + buf.append('\\'); + } + } + buf.append((char) ch); + ch = getNext(); + } else if (ch == -1) { // Don't lose a trailing backslash + buf.append('\\'); + } + } else if (ch == '"') { + buf.append(parseString()); + } else { + buf.append((char) ch); + ch = getNext(); + } + } + return buf.toString(); + } + } + + /** + * Parses the given command line into separate arguments that can be passed + * to DebugPlugin.exec(String[], File). Embedded quotes and + * slashes are escaped. + * + * @param args + * command line arguments as a single string + * @return individual arguments + * @since 3.1 + */ + public static String[] parseArguments(String args) { + if (args == null) + return new String[0]; + ArgumentParser parser = new ArgumentParser(args); + String[] res = parser.parseArguments(); + + return res; + } + + /** + * Sets whether step filters should be applied to step commands. This + * setting is a global option applied to all registered debug targets. + * + * @param useStepFilters + * whether step filters should be applied to step commands + * @since 3.3 + * @see org.eclipse.debug.core.model.IStepFilters + */ + public static void setUseStepFilters(boolean useStepFilters) { + getStepFilterManager().setUseStepFilters(useStepFilters); + } + + /** + * Returns whether step filters are applied to step commands. + * + * @return whether step filters are applied to step commands + * @since 3.3 + * @see org.eclipse.debug.core.model.IStepFilters + * @see org.eclipse.debug.core.commands.IStepFiltersHandler + */ + public static boolean isUseStepFilters() { + return getStepFilterManager().isUseStepFilters(); + } + + /** + * Returns the step filter manager. + * + * @return step filter manager + */ + private static StepFilterManager getStepFilterManager() { + return ((LaunchManager) getDefault().getLaunchManager()) + .getStepFilterManager(); + } + + /** + * Returns an adapter of the specified type for the given object or + * null if none. The object itself is returned if it is an + * instance of the specified type. If the object is adaptable and does not + * subclass PlatformObject, and does not provide the specified + * adapter directly, the platform's adapter manager is consulted for an + * adapter. + * + * @param element + * element to retrieve adapter for + * @param type + * adapter type + * @return adapter or null + * @since 3.4 + */ + public static Object getAdapter(Object element, Class type) { + Object adapter = null; + if (element != null) { + if (type.isInstance(element)) { + return element; + } else { + if (element instanceof IAdaptable) { + adapter = ((IAdaptable) element).getAdapter(type); + } + // for objects that don't subclass PlatformObject, check the + // platform's adapter manager + if (adapter == null && !(element instanceof PlatformObject)) { + adapter = Platform.getAdapterManager().getAdapter(element, + type); + } + // force load the adapter in case it really is available + if (adapter == null) { + adapter = Platform.getAdapterManager().loadAdapter(element, + type.getName()); + } + } + } + return adapter; + } + +} diff --git a/org.eclipse.linuxtools.valgrind.launch.exe/src/org/eclipse/linuxtools/valgrind/launch/ValgrindRuntimeProcess.java b/org.eclipse.linuxtools.valgrind.launch.exe/src/org/eclipse/linuxtools/valgrind/launch/ValgrindRuntimeProcess.java new file mode 100644 index 0000000..2a3b1af --- /dev/null +++ b/org.eclipse.linuxtools.valgrind.launch.exe/src/org/eclipse/linuxtools/valgrind/launch/ValgrindRuntimeProcess.java @@ -0,0 +1,467 @@ +/******************************************************************************* + * Copyright (c) 2000, 2010 IBM Corporation 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: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.linuxtools.valgrind.launch; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.PlatformObject; +import org.eclipse.core.runtime.Status; +import org.eclipse.debug.core.DebugEvent; +import org.eclipse.debug.core.DebugException; +import org.eclipse.debug.core.DebugPlugin; +import org.eclipse.debug.core.ILaunch; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.model.IDebugTarget; +import org.eclipse.debug.core.model.IProcess; +import org.eclipse.debug.core.model.IStreamsProxy; +import org.eclipse.debug.internal.core.DebugCoreMessages; +import org.eclipse.debug.internal.core.NullStreamsProxy; +import org.eclipse.debug.internal.core.StreamsProxy; + +import com.samsung.tizen.common.connection.ConnectionPlugin; +import com.samsung.tizen.sdblib.SdbCommandRejectedException; + +/** + * Standard implementation of an IProcess that wrappers a system + * process (java.lang.Process). + *

+ * Clients may subclass this class. Clients that need to replace the + * implementation of a streams proxy associated with an IProcess + * should subclass this class. Generally clients should not instantiate this + * class directly, but should instead call + * DebugPlugin.newProcess(...), which can delegate to an + * IProcessFactory if one is referenced by the associated launch + * configuration. + *

+ * + * @see org.eclipse.debug.core.model.IProcess + * @see org.eclipse.debug.core.IProcessFactory + * @since 3.0 + */ +public class ValgrindRuntimeProcess extends PlatformObject implements IProcess { + + private static final int MAX_WAIT_FOR_DEATH_ATTEMPTS = 10; + private static final int TIME_TO_WAIT_FOR_THREAD_DEATH = 500; // ms + + /** + * The launch this process is contained in + */ + private ILaunch fLaunch; + + /** + * The system process represented by this IProcess + */ + private Process fProcess; + + /** + * This process's exit value + */ + private int fExitValue; + + /** + * The monitor which listens for this runtime process' system process to + * terminate. + */ + private ProcessMonitorThread fMonitor; + + /** + * The streams proxy for this process + */ + private IStreamsProxy fStreamsProxy; + + /** + * The name of the process + */ + private String fName; + + /** + * Whether this process has been terminated + */ + private boolean fTerminated; + + /** + * Table of client defined attributes + */ + private Map fAttributes; + + /** + * Whether output from the process should be captured or swallowed + */ + private boolean fCaptureOutput = true; + + /** + * Constructs a RuntimeProcess on the given system process with the given + * name, adding this process to the given launch. + * + * @param launch + * the parent launch of this process + * @param process + * underlying system process + * @param name + * the label used for this process + * @param attributes + * map of attributes used to initialize the attributes of this + * process, or null if none + */ + public ValgrindRuntimeProcess(ILaunch launch, Process process, String name, + Map attributes) { + setLaunch(launch); + initializeAttributes(attributes); + fProcess = process; + fName = name; + fTerminated = true; + try { + fExitValue = process.exitValue(); + } catch (IllegalThreadStateException e) { + fTerminated = false; + } + + String captureOutput = launch + .getAttribute(DebugPlugin.ATTR_CAPTURE_OUTPUT); + fCaptureOutput = !("false".equals(captureOutput)); //$NON-NLS-1$ + + fStreamsProxy = createStreamsProxy(); + fMonitor = new ProcessMonitorThread(this); + fMonitor.start(); + launch.addProcess(this); + fireCreationEvent(); + } + + /** + * Initialize the attributes of this process to those in the given map. + * + * @param attributes + * attribute map or null if none + */ + private void initializeAttributes(Map attributes) { + if (attributes != null) { + Iterator keys = attributes.keySet().iterator(); + while (keys.hasNext()) { + String key = (String) keys.next(); + setAttribute(key, (String) attributes.get(key)); + } + } + } + + /** + * @see ITerminate#canTerminate() + */ + public synchronized boolean canTerminate() { + return !fTerminated; + } + + /** + * @see IProcess#getLabel() + */ + public String getLabel() { + return fName; + } + + /** + * Sets the launch this process is contained in + * + * @param launch + * the launch this process is contained in + */ + protected void setLaunch(ILaunch launch) { + fLaunch = launch; + } + + /** + * @see IProcess#getLaunch() + */ + public ILaunch getLaunch() { + return fLaunch; + } + + /** + * Returns the underlying system process associated with this process. + * + * @return system process + */ + protected Process getSystemProcess() { + return fProcess; + } + + /** + * @see ITerminate#isTerminated() + */ + public synchronized boolean isTerminated() { + return fTerminated; + } + + public static void runCommand(String command) { + + try { + ConnectionPlugin.getDefault().getCurrentDevice() + .executeShellCommand(command); + } catch (SdbCommandRejectedException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * @see ITerminate#terminate() + */ + public void terminate() throws DebugException { + runCommand("ps -ef | grep valgrind | grep -v grep | awk '{print \"kill -3 \" $2}' | sh"); + } + + /** + * Notification that the system process associated with this process has + * terminated. + */ + protected void terminated() { + if (fStreamsProxy instanceof StreamsProxy) { + ((StreamsProxy) fStreamsProxy).close(); + } + + // Avoid calling IProcess.exitValue() inside a sync section (Bug + // 311813). + int exitValue = -1; + boolean running = false; + try { + exitValue = fProcess.exitValue(); + } catch (IllegalThreadStateException ie) { + running = true; + } + + synchronized (this) { + fTerminated = true; + if (!running) { + fExitValue = exitValue; + } + fProcess = null; + } + fireTerminateEvent(); + } + + /** + * @see IProcess#getStreamsProxy() + */ + public IStreamsProxy getStreamsProxy() { + if (!fCaptureOutput) { + return null; + } + return fStreamsProxy; + } + + /** + * Creates and returns the streams proxy associated with this process. + * + * @return streams proxy + */ + protected IStreamsProxy createStreamsProxy() { + if (!fCaptureOutput) { + return new NullStreamsProxy(getSystemProcess()); + } + String encoding = getLaunch().getAttribute( + DebugPlugin.ATTR_CONSOLE_ENCODING); + return new StreamsProxy(getSystemProcess(), encoding); + } + + /** + * Fires a creation event. + */ + protected void fireCreationEvent() { + fireEvent(new DebugEvent(this, DebugEvent.CREATE)); + } + + /** + * Fires the given debug event. + * + * @param event + * debug event to fire + */ + protected void fireEvent(DebugEvent event) { + DebugPlugin manager = DebugPlugin.getDefault(); + if (manager != null) { + manager.fireDebugEventSet(new DebugEvent[] { event }); + } + } + + /** + * Fires a terminate event. + */ + protected void fireTerminateEvent() { + fireEvent(new DebugEvent(this, DebugEvent.TERMINATE)); + } + + /** + * Fires a change event. + */ + protected void fireChangeEvent() { + fireEvent(new DebugEvent(this, DebugEvent.CHANGE)); + } + + /** + * @see IProcess#setAttribute(String, String) + */ + public void setAttribute(String key, String value) { + if (fAttributes == null) { + fAttributes = new HashMap(5); + } + Object origVal = fAttributes.get(key); + if (origVal != null && origVal.equals(value)) { + return; // nothing changed. + } + + fAttributes.put(key, value); + fireChangeEvent(); + } + + /** + * @see IProcess#getAttribute(String) + */ + public String getAttribute(String key) { + if (fAttributes == null) { + return null; + } + return (String) fAttributes.get(key); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class) + */ + public Object getAdapter(Class adapter) { + if (adapter.equals(IProcess.class)) { + return this; + } + if (adapter.equals(IDebugTarget.class)) { + ILaunch launch = getLaunch(); + IDebugTarget[] targets = launch.getDebugTargets(); + for (int i = 0; i < targets.length; i++) { + if (this.equals(targets[i].getProcess())) { + return targets[i]; + } + } + return null; + } + if (adapter.equals(ILaunch.class)) { + return getLaunch(); + } + // CONTEXTLAUNCHING + if (adapter.equals(ILaunchConfiguration.class)) { + return getLaunch().getLaunchConfiguration(); + } + return super.getAdapter(adapter); + } + + /** + * @see IProcess#getExitValue() + */ + public synchronized int getExitValue() throws DebugException { + if (isTerminated()) { + return fExitValue; + } + throw new DebugException( + new Status( + IStatus.ERROR, + DebugPlugin.getUniqueIdentifier(), + DebugException.TARGET_REQUEST_FAILED, + DebugCoreMessages.RuntimeProcess_Exit_value_not_available_until_process_terminates__1, + null)); + } + + /** + * Monitors a system process, waiting for it to terminate, and then notifies + * the associated runtime process. + */ + class ProcessMonitorThread extends Thread { + + /** + * Whether the thread has been told to exit. + */ + protected boolean fExit; + /** + * The underlying java.lang.Process being monitored. + */ + protected Process fOSProcess; + /** + * The IProcess which will be informed when this monitor + * detects that the underlying process has terminated. + */ + protected ValgrindRuntimeProcess fRuntimeProcess; + + /** + * The Thread which is monitoring the underlying process. + */ + protected Thread fThread; + + /** + * A lock protecting access to fThread. + */ + private final Object fThreadLock = new Object(); + + /** + * @see Thread#run() + */ + public void run() { + synchronized (fThreadLock) { + if (fExit) { + return; + } + fThread = Thread.currentThread(); + } + while (fOSProcess != null) { + try { + fOSProcess.waitFor(); + } catch (InterruptedException ie) { + // clear interrupted state + Thread.interrupted(); + } finally { + fOSProcess = null; + fRuntimeProcess.terminated(); + } + } + fThread = null; + } + + /** + * Creates a new process monitor and starts monitoring the process for + * termination. + * + * @param process + * process to monitor for termination + */ + public ProcessMonitorThread(ValgrindRuntimeProcess process) { + super(DebugCoreMessages.ProcessMonitorJob_0); + setDaemon(true); + fRuntimeProcess = process; + fOSProcess = process.getSystemProcess(); + } + + /** + * Kills the monitoring thread. + * + * This method is to be useful for dealing with the error case of an + * underlying process which has not informed this monitor of its + * termination. + */ + protected void killThread() { + synchronized (fThreadLock) { + if (fThread == null) { + fExit = true; + } else { + fThread.interrupt(); + } + } + } + } +}