Skip to content

Commit 5db72cd

Browse files
committed
CorDebug Invocations rewritten to .Net Task API (commit moved from MD repo)
1 parent e9ee3d0 commit 5db72cd

File tree

2 files changed

+105
-84
lines changed

2 files changed

+105
-84
lines changed

Mono.Debugging.Win32/CorDebuggerSession.cs

Lines changed: 19 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,13 @@ public static int EvaluationTimestamp {
111111
get { return evaluationTimestamp; }
112112
}
113113

114+
internal CorProcess Process
115+
{
116+
get
117+
{
118+
return process;
119+
}
120+
}
114121

115122
public override void Dispose ( )
116123
{
@@ -1417,49 +1424,16 @@ public CorValue RuntimeInvoke (CorEvaluationContext ctx, CorFunction function, C
14171424
arguments.CopyTo (args, 1);
14181425
}
14191426

1420-
CorMethodCall mc = new CorMethodCall ();
1421-
CorValue exception = null;
1422-
CorEval eval = ctx.Eval;
1423-
1424-
DebugEventHandler<CorEvalEventArgs> completeHandler = delegate (object o, CorEvalEventArgs eargs) {
1425-
OnEndEvaluating ();
1426-
mc.DoneEvent.Set ();
1427-
eargs.Continue = false;
1428-
};
1429-
1430-
DebugEventHandler<CorEvalEventArgs> exceptionHandler = delegate(object o, CorEvalEventArgs eargs) {
1431-
OnEndEvaluating ();
1432-
exception = eargs.Eval.Result;
1433-
mc.DoneEvent.Set ();
1434-
eargs.Continue = false;
1435-
};
1436-
1437-
process.OnEvalComplete += completeHandler;
1438-
process.OnEvalException += exceptionHandler;
1439-
1440-
mc.OnInvoke = delegate {
1441-
if (function.GetMethodInfo (this).Name == ".ctor")
1442-
eval.NewParameterizedObject (function, typeArgs, args);
1443-
else
1444-
eval.CallParameterizedFunction (function, typeArgs, args);
1445-
process.SetAllThreadsDebugState (CorDebugThreadState.THREAD_SUSPEND, ctx.Thread);
1446-
ClearEvalStatus ();
1447-
OnStartEvaluating ();
1448-
process.Continue (false);
1449-
};
1450-
mc.OnAbort = delegate {
1451-
eval.Abort ();
1452-
};
1453-
mc.OnGetDescription = delegate {
1454-
MethodInfo met = function.GetMethodInfo (ctx.Session);
1455-
if (met != null)
1456-
return met.DeclaringType.FullName + "." + met.Name;
1457-
else
1458-
return "<Unknown>";
1459-
};
1460-
1427+
var methodCall = new CorMethodCall (ctx, function, typeArgs, args);
14611428
try {
1462-
ObjectAdapter.AsyncExecute (mc, ctx.Options.EvaluationTimeout);
1429+
var result = ObjectAdapter.InvokeSync (methodCall, ctx.Options.EvaluationTimeout);
1430+
if (result.ResultIsException) {
1431+
var vref = new CorValRef (result.Result);
1432+
throw new EvaluatorExceptionThrownException (vref, ObjectAdapter.GetValueTypeName (ctx, vref));
1433+
}
1434+
1435+
WaitUntilStopped ();
1436+
return result.Result;
14631437
}
14641438
catch (COMException ex) {
14651439
// eval exception is a 'good' exception that should be shown in value box
@@ -1469,35 +1443,16 @@ public CorValue RuntimeInvoke (CorEvaluationContext ctx, CorFunction function, C
14691443
throw evalException;
14701444
throw;
14711445
}
1472-
finally {
1473-
process.OnEvalComplete -= completeHandler;
1474-
process.OnEvalException -= exceptionHandler;
1475-
}
1476-
1477-
WaitUntilStopped ();
1478-
if (exception != null) {
1479-
/* ValueReference<CorValue, CorType> msg = ctx.Adapter.GetMember (ctx, val, "Message");
1480-
if (msg != null) {
1481-
string s = msg.ObjectValue as string;
1482-
mc.ExceptionMessage = s;
1483-
}
1484-
else
1485-
mc.ExceptionMessage = "Evaluation failed.";*/
1486-
CorValRef vref = new CorValRef (exception);
1487-
throw new EvaluatorException ("Evaluation failed: " + ObjectAdapter.GetValueTypeName (ctx, vref));
1488-
}
1489-
1490-
return eval.Result;
14911446
}
14921447

1493-
void OnStartEvaluating ( )
1448+
internal void OnStartEvaluating ( )
14941449
{
14951450
lock (debugLock) {
14961451
evaluating = true;
14971452
}
14981453
}
14991454

1500-
void OnEndEvaluating ( )
1455+
internal void OnEndEvaluating ( )
15011456
{
15021457
lock (debugLock) {
15031458
evaluating = false;
@@ -1603,7 +1558,7 @@ public void WaitUntilStopped ()
16031558
}
16041559
}
16051560

1606-
void ClearEvalStatus ( )
1561+
internal void ClearEvalStatus ( )
16071562
{
16081563
foreach (CorProcess p in dbg.Processes) {
16091564
if (p.Id == processId) {

Mono.Debugging.Win32/CorMethodCall.cs

Lines changed: 86 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,113 @@
11
using System.Threading;
2+
using System.Threading.Tasks;
3+
using Microsoft.Samples.Debugging.CorDebug;
4+
using Microsoft.Samples.Debugging.CorDebug.NativeApi;
25
using Mono.Debugging.Evaluation;
36

47
namespace Mono.Debugging.Win32
58
{
6-
class CorMethodCall: AsyncOperation
9+
class CorMethodCall: AsyncOperationBase<CorValue>
710
{
8-
public delegate void CallCallback ( );
9-
public delegate string DescriptionCallback ( );
11+
readonly CorEvaluationContext context;
12+
readonly CorFunction function;
13+
readonly CorType[] typeArgs;
14+
readonly CorValue[] args;
1015

11-
public CallCallback OnInvoke;
12-
public CallCallback OnAbort;
13-
public DescriptionCallback OnGetDescription;
16+
readonly CorEval eval;
1417

15-
public ManualResetEvent DoneEvent = new ManualResetEvent (false);
18+
public CorMethodCall (CorEvaluationContext context, CorFunction function, CorType[] typeArgs, CorValue[] args)
19+
{
20+
this.context = context;
21+
this.function = function;
22+
this.typeArgs = typeArgs;
23+
this.args = args;
24+
eval = context.Eval;
25+
}
1626

17-
public override string Description
27+
void ProcessOnEvalComplete (object sender, CorEvalEventArgs evalArgs)
28+
{
29+
DoProcessEvalFinished (evalArgs, false);
30+
}
31+
32+
void ProcessOnEvalException (object sender, CorEvalEventArgs evalArgs)
1833
{
19-
get { return OnGetDescription (); }
34+
DoProcessEvalFinished (evalArgs, true);
2035
}
2136

22-
public override void Invoke ( )
37+
void DoProcessEvalFinished (CorEvalEventArgs evalArgs, bool isException)
2338
{
24-
OnInvoke ();
39+
if (evalArgs.Eval != eval)
40+
return;
41+
context.Session.OnEndEvaluating ();
42+
evalArgs.Continue = false;
43+
tcs.TrySetResult(new OperationResult<CorValue> (evalArgs.Eval.Result, isException));
2544
}
2645

27-
public override void Abort ( )
46+
void SubscribeOnEvals ()
2847
{
29-
OnAbort ();
48+
context.Session.Process.OnEvalComplete += ProcessOnEvalComplete;
49+
context.Session.Process.OnEvalException += ProcessOnEvalException;
3050
}
3151

32-
public override void Shutdown ( )
52+
void UnSubcribeOnEvals ()
53+
{
54+
context.Session.Process.OnEvalComplete -= ProcessOnEvalComplete;
55+
context.Session.Process.OnEvalException -= ProcessOnEvalException;
56+
}
57+
58+
public override string Description
3359
{
34-
try {
35-
Abort ();
60+
get
61+
{
62+
var met = function.GetMethodInfo (context.Session);
63+
if (met == null)
64+
return "<Unknown>";
65+
if (met.DeclaringType == null)
66+
return met.Name;
67+
return met.DeclaringType.FullName + "." + met.Name;
3668
}
37-
catch {
69+
}
70+
71+
readonly TaskCompletionSource<OperationResult<CorValue>> tcs = new TaskCompletionSource<OperationResult<CorValue>> ();
72+
const int DelayAfterAbort = 500;
73+
74+
protected override void AfterCancelledImpl (int elapsedAfterCancelMs)
75+
{
76+
if (tcs.TrySetCanceled ()) {
77+
// really cancelled for the first time not before. so we should check that we awaited necessary amout of time after Abort() call
78+
// else if we return too earle after Abort() the process may be PROCESS_NOT_SYNCHRONIZED
79+
if (elapsedAfterCancelMs < DelayAfterAbort) {
80+
Thread.Sleep (DelayAfterAbort - elapsedAfterCancelMs);
81+
}
3882
}
39-
DoneEvent.Set ();
83+
context.Session.OnEndEvaluating ();
4084
}
4185

42-
public override bool WaitForCompleted (int timeout)
86+
protected override Task<OperationResult<CorValue>> InvokeAsyncImpl (CancellationToken token)
87+
{
88+
SubscribeOnEvals ();
89+
90+
if (function.GetMethodInfo (context.Session).Name == ".ctor")
91+
eval.NewParameterizedObject (function, typeArgs, args);
92+
else
93+
eval.CallParameterizedFunction (function, typeArgs, args);
94+
context.Session.Process.SetAllThreadsDebugState (CorDebugThreadState.THREAD_SUSPEND, context.Thread);
95+
context.Session.ClearEvalStatus ();
96+
context.Session.OnStartEvaluating ();
97+
context.Session.Process.Continue (false);
98+
Task = tcs.Task;
99+
// Don't pass token here, because it causes immediately task cancellation which must be performed by debugger event or real timeout
100+
// ReSharper disable once MethodSupportsCancellation
101+
return Task.ContinueWith (task => {
102+
UnSubcribeOnEvals ();
103+
return task.Result;
104+
});
105+
}
106+
107+
108+
protected override void CancelImpl ( )
43109
{
44-
return DoneEvent.WaitOne (timeout, false);
110+
eval.Abort ();
45111
}
46112
}
47113
}

0 commit comments

Comments
 (0)