Skip to content
This repository has been archived by the owner on Oct 4, 2021. It is now read-only.

Commit

Permalink
[CorDebug] Invocations rewritten to .net Task API
Browse files Browse the repository at this point in the history
  • Loading branch information
nerzhulart committed Dec 21, 2016
1 parent ae4eac9 commit 7a73da3
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 85 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ public static int EvaluationTimestamp {
get { return evaluationTimestamp; }
}

internal CorProcess Process
{
get
{
return process;
}
}

public override void Dispose ( )
{
Expand Down Expand Up @@ -912,6 +919,7 @@ protected override void OnNextLine ( )
void Step (bool into)
{
try {
ObjectAdapter.CancelAsyncOperations ();
if (stepper != null) {
CorFrame frame = activeThread.ActiveFrame;
ISymbolReader reader = GetReaderForModule (frame.Function.Module.Name);
Expand Down Expand Up @@ -955,7 +963,7 @@ void Step (bool into)
process.Continue (false);
}
} catch (Exception e) {
OnDebuggerOutput (true, e.ToString ());
DebuggerLoggingService.LogError ("Exception on Step()", e);
}
}

Expand Down Expand Up @@ -1065,80 +1073,30 @@ public CorValue RuntimeInvoke (CorEvaluationContext ctx, CorFunction function, C
args[0] = thisObj;
arguments.CopyTo (args, 1);
}

CorMethodCall mc = new CorMethodCall ();
CorValue exception = null;
CorEval eval = ctx.Eval;

EvalEventHandler completeHandler = delegate (object o, CorEvalEventArgs eargs) {
OnEndEvaluating ();
mc.DoneEvent.Set ();
eargs.Continue = false;
};

EvalEventHandler exceptionHandler = delegate (object o, CorEvalEventArgs eargs) {
OnEndEvaluating ();
exception = eargs.Eval.Result;
mc.DoneEvent.Set ();
eargs.Continue = false;
};

process.OnEvalComplete += completeHandler;
process.OnEvalException += exceptionHandler;

mc.OnInvoke = delegate {
if (function.GetMethodInfo (this).Name == ".ctor")
eval.NewParameterizedObject (function, typeArgs, args);
else
eval.CallParameterizedFunction (function, typeArgs, args);
process.SetAllThreadsDebugState (CorDebugThreadState.THREAD_SUSPEND, ctx.Thread);
ClearEvalStatus ();
OnStartEvaluating ();
process.Continue (false);
};
mc.OnAbort = delegate {
eval.Abort ();
};
mc.OnGetDescription = delegate {
MethodInfo met = function.GetMethodInfo (ctx.Session);
if (met != null)
return met.DeclaringType.FullName + "." + met.Name;
else
return "<Unknown>";
};

var methodCall = new CorMethodCall (ctx, function, typeArgs, args);
try {
ObjectAdapter.AsyncExecute (mc, ctx.Options.EvaluationTimeout);
}
finally {
process.OnEvalComplete -= completeHandler;
process.OnEvalException -= exceptionHandler;
}

WaitUntilStopped ();
if (exception != null) {
/* ValueReference<CorValue, CorType> msg = ctx.Adapter.GetMember (ctx, val, "Message");
if (msg != null) {
string s = msg.ObjectValue as string;
mc.ExceptionMessage = s;
var result = ObjectAdapter.InvokeSync (methodCall, ctx.Options.EvaluationTimeout);
if (result.ResultIsException) {
var vref = new CorValRef (result.Result);
throw new EvaluatorExceptionThrownException (vref, ObjectAdapter.GetValueTypeName (ctx, vref));
}
else
mc.ExceptionMessage = "Evaluation failed.";*/
CorValRef vref = new CorValRef (exception);
throw new EvaluatorException ("Evaluation failed: " + ObjectAdapter.GetValueTypeName (ctx, vref));
}

return eval.Result;
WaitUntilStopped ();
return result.Result;
}
catch (COMException ex) {
throw new EvaluatorException (ex.Message);
}
}

void OnStartEvaluating ( )
internal void OnStartEvaluating ( )
{
lock (debugLock) {
evaluating = true;
}
}

void OnEndEvaluating ( )
internal void OnEndEvaluating ( )
{
lock (debugLock) {
evaluating = false;
Expand Down Expand Up @@ -1235,7 +1193,7 @@ public void WaitUntilStopped ()
}
}

void ClearEvalStatus ( )
internal void ClearEvalStatus ( )
{
foreach (CorProcess p in dbg.Processes) {
if (p.Id == processId) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,47 +1,113 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Samples.Debugging.CorDebug;
using Microsoft.Samples.Debugging.CorDebug.NativeApi;
using Mono.Debugging.Evaluation;

namespace Mono.Debugging.Win32
{
class CorMethodCall: AsyncOperation
class CorMethodCall: AsyncOperationBase<CorValue>
{
public delegate void CallCallback ( );
public delegate string DescriptionCallback ( );
readonly CorEvaluationContext context;
readonly CorFunction function;
readonly CorType[] typeArgs;
readonly CorValue[] args;

public CallCallback OnInvoke;
public CallCallback OnAbort;
public DescriptionCallback OnGetDescription;
readonly CorEval eval;

public ManualResetEvent DoneEvent = new ManualResetEvent (false);
public CorMethodCall (CorEvaluationContext context, CorFunction function, CorType[] typeArgs, CorValue[] args)
{
this.context = context;
this.function = function;
this.typeArgs = typeArgs;
this.args = args;
eval = context.Eval;
}

public override string Description
void ProcessOnEvalComplete (object sender, CorEvalEventArgs evalArgs)
{
DoProcessEvalFinished (evalArgs, false);
}

void ProcessOnEvalException (object sender, CorEvalEventArgs evalArgs)
{
get { return OnGetDescription (); }
DoProcessEvalFinished (evalArgs, true);
}

public override void Invoke ( )
void DoProcessEvalFinished (CorEvalEventArgs evalArgs, bool isException)
{
OnInvoke ();
if (evalArgs.Eval != eval)
return;
context.Session.OnEndEvaluating ();
evalArgs.Continue = false;
tcs.TrySetResult(new OperationResult<CorValue> (evalArgs.Eval.Result, isException));
}

public override void Abort ( )
void SubscribeOnEvals ()
{
OnAbort ();
context.Session.Process.OnEvalComplete += ProcessOnEvalComplete;
context.Session.Process.OnEvalException += ProcessOnEvalException;
}

public override void Shutdown ( )
void UnSubcribeOnEvals ()
{
context.Session.Process.OnEvalComplete -= ProcessOnEvalComplete;
context.Session.Process.OnEvalException -= ProcessOnEvalException;
}

public override string Description
{
try {
Abort ();
get
{
var met = function.GetMethodInfo (context.Session);
if (met == null)
return "<Unknown>";
if (met.DeclaringType == null)
return met.Name;
return met.DeclaringType.FullName + "." + met.Name;
}
catch {
}

readonly TaskCompletionSource<OperationResult<CorValue>> tcs = new TaskCompletionSource<OperationResult<CorValue>> ();
const int DelayAfterAbort = 500;

protected override void AfterCancelledImpl (int elapsedAfterCancelMs)
{
if (tcs.TrySetCanceled ()) {
// really cancelled for the first time not before. so we should check that we awaited necessary amout of time after Abort() call
// else if we return too earle after Abort() the process may be PROCESS_NOT_SYNCHRONIZED
if (elapsedAfterCancelMs < DelayAfterAbort) {
Thread.Sleep (DelayAfterAbort - elapsedAfterCancelMs);
}
}
DoneEvent.Set ();
context.Session.OnEndEvaluating ();
}

public override bool WaitForCompleted (int timeout)
protected override Task<OperationResult<CorValue>> InvokeAsyncImpl (CancellationToken token)
{
SubscribeOnEvals ();

if (function.GetMethodInfo (context.Session).Name == ".ctor")
eval.NewParameterizedObject (function, typeArgs, args);
else
eval.CallParameterizedFunction (function, typeArgs, args);
context.Session.Process.SetAllThreadsDebugState (CorDebugThreadState.THREAD_SUSPEND, context.Thread);
context.Session.ClearEvalStatus ();
context.Session.OnStartEvaluating ();
context.Session.Process.Continue (false);
Task = tcs.Task;
// Don't pass token here, because it causes immediately task cancellation which must be performed by debugger event or real timeout
// ReSharper disable once MethodSupportsCancellation
return Task.ContinueWith (task => {
UnSubcribeOnEvals ();
return task.Result;
});
}


protected override void CancelImpl ( )
{
return DoneEvent.WaitOne (timeout, false);
eval.Abort ();
}
}
}

0 comments on commit 7a73da3

Please sign in to comment.