Package org.epic.debug.db

Source Code of org.epic.debug.db.PerlDebugThread

package org.epic.debug.db;

import java.io.IOException;

import org.eclipse.core.runtime.*;
import org.eclipse.debug.core.DebugEvent;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.model.*;
import org.eclipse.ui.progress.UIJob;
import org.epic.debug.*;
import org.epic.perleditor.PerlEditorPlugin;
import org.epic.perleditor.preferences.PreferenceConstants;

/**
* This IThread implementation is responsible for processing user
* interface events, coordinating communication with the Perl debugger
* and dispatching debug events. The main role of PerlDebugThread lies
* in delegating work to helper objects at appropriate times:
* PerlThreadStack, PerlThreadBreakpoints and PerlDebugJob.
*
* @author ruehl
* @author jploski
*/
public class PerlDebugThread extends DebugElement implements IThread
{   
    private static final IBreakpoint[] NO_BREAKPOINTS = new IBreakpoint[0];
   
    private final static int INITIALIZING = 0;
    private final static int SUSPENDED = 1;
    private final static int STEPPING = 2;
    private final static int RUNNING = 3;
    private final static int TERMINATING = 4;
    private final static int TERMINATED = 5;

    private final Object LOCK = new Object();
    private final PerlThreadStack stack;
    private final PerlThreadBreakpoints bp;
    private final PerlDebugJob job;
    private final String name;
    private final DebuggerInterface db;

    private int state;

    public PerlDebugThread(
        IDebugTarget debugTarget,
        DebuggerInterface db) throws CoreException
    {
        super(debugTarget);

        this.db = db;
        this.stack = new PerlThreadStack(this);
        this.bp = new PerlThreadBreakpoints(this, db);
        this.state = INITIALIZING;
        this.name = "Main Thread";
        this.job = new PerlDebugJob();

        fireCreationEvent();

        suspended(DebugEvent.BREAKPOINT);
       
        if (!isBreakpointReached() &&
            !PerlEditorPlugin.getDefault().getBooleanPreference(
                PreferenceConstants.DEBUG_SUSPEND_AT_FIRST))
        {
            UIJob resume = new UIJob("PerlDebugThread.resume") {
                public IStatus runInUIThread(IProgressMonitor monitor)
                {
                    try { resume(); }
                    catch (DebugException e)
                    {
                        PerlDebugPlugin.log(e);
                    }
                    return Status.OK_STATUS;
                }
            };
            resume.setSystem(true);
            resume.schedule();
        }
        else fireSuspendEvent(DebugEvent.BREAKPOINT);
    }

    public boolean canResume()
    {
        return isSuspended();
    }

    public boolean canStepInto()
    {
        return isSuspended();
    }

    public boolean canStepOver()
    {
        return isSuspended();
    }

    public boolean canStepReturn()
    {
        return isSuspended();
    }

    public boolean canSuspend()
    {
        return false; // TODO support suspend on demand
    }

    public boolean canTerminate()
    {
        return !isTerminated();
    }
   
    public String evaluateStatement(String text)
        throws DebugException
    {
        try
        {
            String output = db.eval(text);       
            stack.update();
            return output;
        }
        catch (IOException e)
        {
            throwDebugException(e);
            return null;
        }
    }

    public Object getAdapter(Class adapter)
    {
        if (PerlDebugThread.class.isAssignableFrom(adapter))
        {
            return this;
        }
        if (IStackFrame.class.isAssignableFrom(adapter))
        {
            try
            {
                return getTopStackFrame();
            }
            catch (DebugException e)
            {
                // do nothing if not able to get frame
            }
        }
        return super.getAdapter(adapter);
    }

    public IBreakpoint[] getBreakpoints()
    {
        try
        {
            IBreakpoint breakpoint = bp.getCurrentBreakpoint();
            if (breakpoint != null) return new IBreakpoint[] { breakpoint };
            else return NO_BREAKPOINTS;
        }
        catch (CoreException e)
        {
            PerlDebugPlugin.log(e);
            return NO_BREAKPOINTS;
        }
    }

    public String getModelIdentifier()
    {
        return PerlDebugPlugin.getUniqueIdentifier();
    }

    public String getName() throws DebugException
    {
        if (isSuspended()) return "<suspended> " + name;
        else if (!isTerminated()) return "<running> " + name;
        else return name;
    }

    public int getPriority() throws DebugException
    {
        return 0;
    }

    public IStackFrame[] getStackFrames() throws DebugException
    {
        return stack.getFrames();
    }

    public IStackFrame getTopStackFrame() throws DebugException
    {
        IStackFrame[] frames = getStackFrames();
        return frames.length > 0 ? frames[0] : null;
    }

    public boolean hasStackFrames() throws DebugException
    {
        return stack.getFrames().length > 0;
    }

    public boolean isStepping()
    {
        synchronized (LOCK)
        {
            return state == STEPPING;
        }
    }

    public boolean isSuspended()
    {
        synchronized (LOCK)
        {
            return state == SUSPENDED;
        }
    }

    public boolean isTerminated()
    {
        synchronized (LOCK)
        {
            return state == TERMINATED;
        }
    }

    public void resume() throws DebugException
    {
        synchronized (LOCK)
        {
            assertSuspended();           
            state = RUNNING;
            fireResumeEvent(DebugEvent.UNSPECIFIED);
            job.setCommand(new ResumeCommand(this));
            job.schedule();
        }       
    }

    public void stepInto() throws DebugException
    {
        step(DebugEvent.STEP_INTO);
    }

    public void stepOver() throws DebugException
    {
        step(DebugEvent.STEP_OVER);
    }

    public void stepReturn() throws DebugException
    {
        step(DebugEvent.STEP_RETURN);
    }

    public void suspend() throws DebugException
    {
        // TODO support suspend on demand
        throw new DebugException(
            new Status(
                Status.ERROR,
                PerlDebugPlugin.getUniqueIdentifier(),
                Status.OK,
                "Suspend not supported",
                null
                ));
    }

    public void terminate() throws DebugException
    {
        synchronized (LOCK)
        {
            if (isSuspended())
            {
                state = TERMINATING;
                job.setCommand(new TerminateCommand(this));
                job.schedule();
            }
            else
            {
                getDebugTarget().getProcess().terminate();
            }
        }
    }
   
    /**
     * Invoked by DebugCommand on PerlDebugJob's thread to indicate
     * that the command has finished - either because the debugger
     * has suspended or terminated.
     */
    void debugCommandFinished(DebugCommand cmd)
    {
        synchronized (LOCK)
        {
            if (state == TERMINATED) return; // terminated while not suspended
        }
       
        if (cmd.hasSuspended())
        {
            suspended(cmd.getCompletionStatus());
        }
        else // terminated
        {
            terminated();
        }
    }
   
    /**
     * Only for use by DebugCommand.
     */
    DebuggerInterface getDB()
    {
        return db;
    }
   
    IPath getDebuggerPath(IPath epicPath)
    {
        return ((DebugTarget) getDebugTarget()).getPathMapper()
            .getDebuggerPath(epicPath, db);
    }
   
    IPath getEpicPath(IPath dbPath)
    {
        if (!dbPath.isAbsolute())
        {
            try { dbPath = bp.getAbsDBPath(dbPath); }
            catch (CoreException e) { PerlDebugPlugin.log(e); }
        }
       
        return ((DebugTarget) getDebugTarget()).getPathMapper()
            .getEpicPath(dbPath);
    }
   
    void installPendingBreakpoints()
    {
        try
        {
            bp.installPendingBreakpoints();
        }
        catch (CoreException e)
        {
            PerlDebugPlugin.log(e);
        }
    }
   
    boolean isBreakpointReached() throws CoreException
    {
        return bp.getCurrentBreakpoint() != null;
    }
   
    private void assertSuspended() throws DebugException
    {
        if (!isSuspended()) throw new DebugException(
            new Status(
                Status.ERROR,
                PerlDebugPlugin.getUniqueIdentifier(),
                Status.OK,
                "This action only works when the debugger is suspended",
                null
                ));
    }
   
    private void step(int kind) throws DebugException
    {
        synchronized (LOCK)
        {
            assertSuspended();           
            state = STEPPING;
            fireResumeEvent(kind);
           
            DebugCommand cmd;
            switch (kind)
            {
            case DebugEvent.STEP_INTO:
                cmd = new StepIntoCommand(this);
                break;
            case DebugEvent.STEP_OVER:
                cmd = new StepOverCommand(this);
                break;
            case DebugEvent.STEP_RETURN:
                cmd = new StepReturnCommand(this);
                break;
            default:
                assert false : "unrecognized step kind";
                return;
            }
            job.setCommand(cmd);
            job.schedule();
        }
    }
   
    private void suspended(int kind)
    {
        try
        {           
            stack.update();
            bp.installPendingBreakpoints();
        }
        catch (CoreException e)
        {
            PerlDebugPlugin.log(e);
        }
        synchronized (LOCK)
        {
            // Firing a SUSPENDED event causes the workbench to grab
            // focus or pop-up to the front of the window stack.
            // PerlDebugThread calls suspended to complete its
            // initialization, but it might resume right after that,
            // so we don't issue a SUSPENDED event in this case.

            boolean wasInitializing = state == INITIALIZING;
            state = SUSPENDED;
            if (!wasInitializing) fireSuspendEvent(kind);
        }
    }
   
    private void terminated()
    {
        synchronized (LOCK)
        {           
            db.dispose();
            bp.dispose();
            state = TERMINATED;
            fireTerminateEvent();
        }
    }
   
    void throwDebugException(IOException e) throws DebugException
    {
        throw new DebugException(new Status(
            IStatus.ERROR,
            PerlDebugPlugin.getUniqueIdentifier(),
            IStatus.OK,
            "An error occurred during communication with the debugger process",
            e));
    }
   
    void unresolvedDebuggerPath(IPath dbPath)
    {
        PerlDebugPlugin.log(new Status(
            IStatus.WARNING,
            PerlDebugPlugin.getUniqueIdentifier(),
            IStatus.OK,
            "Could not map remote path " + dbPath +
            " to a local path. Some breakpoints may be ignored.",
            null));
    }
   
    void unresolvedEpicPath(IPath epicPath)
    {
        PerlDebugPlugin.log(new Status(
            IStatus.WARNING,
            PerlDebugPlugin.getUniqueIdentifier(),
            IStatus.OK,
            "Could not map local path " + epicPath +
            " to a remote path. Some breakpoints may be ignored.",
            null));
    }
}
TOP

Related Classes of org.epic.debug.db.PerlDebugThread

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.