/*
* #%~
* org.overture.ide.debug
* %%
* Copyright (C) 2008 - 2014 Overture
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #~%
*/
package org.overture.ide.debug.core.model.internal;
import org.eclipse.debug.core.DebugEvent;
import org.eclipse.debug.core.DebugException;
import org.overture.ide.debug.core.VdmDebugPlugin;
import org.overture.ide.debug.core.dbgp.IDbgpStatus;
import org.overture.ide.debug.core.dbgp.IDbgpStatusInterpreterThreadState;
import org.overture.ide.debug.core.dbgp.exceptions.DbgpException;
import org.overture.ide.debug.core.model.internal.operations.DbgpDebugger;
import org.overture.ide.debug.core.model.internal.operations.IDbgpDebuggerFeedback;
public class VdmThreadStateManager implements IDbgpDebuggerFeedback
{
public static interface IStateChangeHandler
{
void handleSuspend(int detail);
void handleResume(int detail);
void handleTermination(DbgpException e);
void setInterpreterState(
IDbgpStatusInterpreterThreadState interpreterThreadState);
}
private IStateChangeHandler handler;
private final DbgpDebugger engine;
// Abilities of debugging engine
// private volatile boolean canSuspend;
// Number of suspends
private volatile int modificationsCount;
// States
private volatile boolean stepping;
private volatile boolean suspended;
private volatile boolean terminated;
private volatile boolean stepIntoState;
private final Object stepIntoLock = new Object();
private boolean errorState = false;
protected void handleStatus(DbgpException exception, IDbgpStatus status,
int suspendDetail)
{
if (exception != null)
{
setTerminated(exception);
}
if (status == null)
{
setTerminated(null);
return;
}
// set internal VDMJ state
if (status.getInterpreterThreadState() != null)
{
handler.setInterpreterState(status.getInterpreterThreadState());
}
// status is break but with an error, f.e. precondition failure
if (status.isBreak() && status.reasonError())
{
errorState = true;
}
if (status.isBreak())
{
setSuspended(true, suspendDetail);
} else if (status.isStopping())
{
// Temporary solution!
try
{
terminate();
} catch (DebugException e)
{
if (VdmDebugPlugin.DEBUG)
{
e.printStackTrace();
}
}
} else if (status.isStopped())
{
setTerminated(null);
}
}
// State management
protected void setSuspended(boolean value, int detail)
{
suspended = value;
if (value)
{
++modificationsCount;
}
if (value)
{
handler.handleSuspend(detail);
} else
{
handler.handleResume(detail);
}
}
private void setTerminated(DbgpException e)
{
if (!terminated)
{
terminated = true;
handler.handleTermination(e);
}
}
private boolean canStep()
{
return !terminated && suspended && !errorState;
}
private void beginStep(int detail)
{
stepping = true;
setSuspended(false, detail);
}
private void endStep(DbgpException execption, IDbgpStatus status)
{
stepping = false;
handleStatus(execption, status, DebugEvent.STEP_END);
}
public VdmThreadStateManager(VdmThread thread)
{
this.handler = thread;
this.engine = new DbgpDebugger(thread, this);
// canSuspend = true; // engine.isSupportsAsync();
this.modificationsCount = 0;
this.suspended = true;
this.terminated = false;
this.stepping = this.suspended;
}
public DbgpDebugger getEngine()
{
return engine;
}
// Stepping
public boolean isStepping()
{
return !terminated && stepping;
}
// StepInto
public boolean canStepInto()
{
return canStep();
}
public void endStepInto(DbgpException e, IDbgpStatus status)
{
endStep(e, status);
}
public void stepInto() throws DebugException
{
beginStep(DebugEvent.STEP_INTO);
synchronized (stepIntoLock)
{
this.stepIntoState = true;
}
engine.stepInto();
}
public boolean isStepInto()
{
synchronized (stepIntoLock)
{
return this.stepIntoState;
}
}
public void setStepInto(boolean state)
{
synchronized (stepIntoLock)
{
this.stepIntoState = state;
}
}
// StepOver
public boolean canStepOver()
{
return canStep();
}
public void endStepOver(DbgpException e, IDbgpStatus status)
{
endStep(e, status);
}
public void stepOver() throws DebugException
{
beginStep(DebugEvent.STEP_OVER);
engine.stepOver();
}
// StepReturn
public boolean canStepReturn()
{
return canStep();
}
public void endStepReturn(DbgpException e, IDbgpStatus status)
{
endStep(e, status);
}
public void stepReturn() throws DebugException
{
beginStep(DebugEvent.STEP_RETURN);
engine.stepReturn();
}
// Suspend
public boolean isSuspended()
{
return suspended;
}
public boolean canSuspend()
{
return false; // FIXME: I believe that the current debugger do not support any comminication while running
// //canSuspend && !terminated && !suspended;
}
public void endSuspend(DbgpException e, IDbgpStatus status)
{
handleStatus(e, status, DebugEvent.CLIENT_REQUEST);
}
public void suspend() throws DebugException
{
engine.suspend();
setSuspended(true, DebugEvent.CLIENT_REQUEST);
}
public int getModificationsCount()
{
return modificationsCount;
}
// Resume
public boolean canResume()
{
return !terminated && suspended && !errorState;
}
public void endResume(DbgpException e, IDbgpStatus status)
{
handleStatus(e, status, DebugEvent.BREAKPOINT);
}
public void resume() throws DebugException
{
setSuspended(false, DebugEvent.CLIENT_REQUEST);
engine.resume();
}
// Terminate
public boolean isTerminated()
{
return terminated;
}
public boolean canTerminate()
{
return !terminated;
}
public void endTerminate(DbgpException e, IDbgpStatus status)
{
handleStatus(e, status, DebugEvent.CLIENT_REQUEST);
}
public void terminate() throws DebugException
{
engine.terminate();
}
public void notifyModified()
{
modificationsCount++;
}
}