Skip to content

Commit 8eba0ab

Browse files
committed
Async operations rewritten to Tasks
1 parent 73bcf8c commit 8eba0ab

File tree

8 files changed

+312
-288
lines changed

8 files changed

+312
-288
lines changed

Mono.Debugging.Soft/SoftDebuggerAdaptor.cs

Lines changed: 59 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
using System.Collections.Generic;
3434
using System.Runtime.CompilerServices;
3535
using System.Threading;
36-
36+
using System.Threading.Tasks;
3737
using Mono.Debugger.Soft;
3838
using Mono.Debugging.Evaluation;
3939
using Mono.Debugging.Client;
@@ -2166,30 +2166,36 @@ static string MirrorStringToString (EvaluationContext ctx, StringMirror mirror)
21662166
}
21672167
}
21682168

2169-
class MethodCall: AsyncOperation
2169+
internal class SoftOperationResult : OperationResult<Value>
21702170
{
2171-
readonly InvokeOptions options = InvokeOptions.DisableBreakpoints | InvokeOptions.SingleThreaded;
2171+
public SoftOperationResult (Value result, bool resultIsException, Value[] outArgs) : base (result, resultIsException)
2172+
{
2173+
OutArgs = outArgs;
2174+
}
2175+
2176+
public Value[] OutArgs { get; private set; }
2177+
}
21722178

2173-
readonly ManualResetEvent shutdownEvent = new ManualResetEvent (false);
2179+
internal class SoftMethodCall: AsyncOperationBase<Value>
2180+
{
2181+
readonly InvokeOptions options = InvokeOptions.DisableBreakpoints | InvokeOptions.SingleThreaded;
21742182
readonly SoftEvaluationContext ctx;
21752183
readonly MethodMirror function;
21762184
readonly Value[] args;
2177-
readonly object obj;
2178-
IAsyncResult handle;
2179-
Exception exception;
2180-
IInvokeResult result;
2181-
2182-
public MethodCall (SoftEvaluationContext ctx, MethodMirror function, object obj, Value[] args, bool enableOutArgs)
2185+
readonly IInvocableMethodOwnerMirror obj;
2186+
IInvokeAsyncResult invokeAsyncResult;
2187+
2188+
public SoftMethodCall (SoftEvaluationContext ctx, MethodMirror function, IInvocableMethodOwnerMirror obj, Value[] args, bool enableOutArgs)
21832189
{
21842190
this.ctx = ctx;
21852191
this.function = function;
21862192
this.obj = obj;
21872193
this.args = args;
21882194
if (enableOutArgs) {
2189-
this.options |= InvokeOptions.ReturnOutArgs;
2195+
options |= InvokeOptions.ReturnOutArgs;
21902196
}
21912197
if (function.VirtualMachine.Version.AtLeast (2, 40)) {
2192-
this.options |= InvokeOptions.Virtual;
2198+
options |= InvokeOptions.Virtual;
21932199
}
21942200
}
21952201

@@ -2199,113 +2205,60 @@ public override string Description {
21992205
}
22002206
}
22012207

2202-
public override void Invoke ()
2208+
protected override void AfterCancelledImpl (int elapsedAfterCancelMs)
22032209
{
2204-
try {
2205-
var invocableMirror = obj as IInvocableMethodOwnerMirror;
2206-
if (invocableMirror != null) {
2207-
var optionsToInvoke = options;
2208-
if (obj is StructMirror) {
2209-
optionsToInvoke |= InvokeOptions.ReturnOutThis;
2210-
}
2211-
handle = invocableMirror.BeginInvokeMethod (ctx.Thread, function, args, optionsToInvoke, null, null);
2212-
}
2213-
else
2214-
throw new ArgumentException ("Soft debugger method calls cannot be invoked on objects of type " + obj.GetType ().Name);
2215-
} catch (InvocationException ex) {
2216-
ctx.Session.StackVersion++;
2217-
exception = ex;
2218-
} catch (Exception ex) {
2219-
ctx.Session.StackVersion++;
2220-
DebuggerLoggingService.LogError ("Error in soft debugger method call thread on " + GetInfo (), ex);
2221-
exception = ex;
2222-
}
22232210
}
22242211

2225-
public override void Abort ()
2226-
{
2227-
if (handle is IInvokeAsyncResult) {
2228-
var info = GetInfo ();
2229-
DebuggerLoggingService.LogMessage ("Aborting invocation of " + info);
2230-
((IInvokeAsyncResult) handle).Abort ();
2231-
// Don't wait for the abort to finish. The engine will do it.
2232-
} else {
2233-
throw new NotSupportedException ();
2234-
}
2235-
}
2236-
2237-
public override void Shutdown ()
2238-
{
2239-
shutdownEvent.Set ();
2240-
}
2241-
2242-
void EndInvoke ()
2212+
protected override Task<OperationResult<Value>> InvokeAsyncImpl (CancellationToken token)
22432213
{
22442214
try {
2245-
result = ((IInvocableMethodOwnerMirror) obj).EndInvokeMethodWithResult (handle);
2246-
} catch (InvocationException ex) {
2247-
if (!Aborting && ex.Exception != null) {
2248-
string ename = ctx.Adapter.GetValueTypeName (ctx, ex.Exception);
2249-
var vref = ctx.Adapter.GetMember (ctx, null, ex.Exception, "Message");
2250-
2251-
exception = vref != null ? new Exception (ename + ": " + (string) vref.ObjectValue) : new Exception (ename);
2252-
return;
2215+
var optionsToInvoke = options;
2216+
if (obj is StructMirror) {
2217+
optionsToInvoke |= InvokeOptions.ReturnOutThis;
22532218
}
2254-
exception = ex;
2255-
} catch (Exception ex) {
2256-
DebuggerLoggingService.LogError ("Error in soft debugger method call thread on " + GetInfo (), ex);
2257-
exception = ex;
2258-
} finally {
2259-
ctx.Session.StackVersion++;
2260-
}
2261-
}
2262-
2263-
string GetInfo ()
2264-
{
2265-
try {
2266-
TypeMirror type = null;
2267-
if (obj is ObjectMirror)
2268-
type = ((ObjectMirror)obj).Type;
2269-
else if (obj is TypeMirror)
2270-
type = (TypeMirror)obj;
2271-
else if (obj is StructMirror)
2272-
type = ((StructMirror)obj).Type;
2273-
return string.Format ("method {0} on object {1}",
2274-
function == null? "[null]" : function.FullName,
2275-
type == null? "[null]" : type.FullName);
2276-
} catch (Exception ex) {
2277-
DebuggerLoggingService.LogError ("Error getting info for SDB MethodCall", ex);
2278-
return "";
2219+
var tcs = new TaskCompletionSource<OperationResult<Value>> ();
2220+
invokeAsyncResult = (IInvokeAsyncResult)obj.BeginInvokeMethod (ctx.Thread, function, args, optionsToInvoke, ar => {
2221+
try {
2222+
var endInvokeResult = obj.EndInvokeMethodWithResult (ar);
2223+
token.ThrowIfCancellationRequested ();
2224+
tcs.SetResult (new SoftOperationResult (endInvokeResult.Result, false, endInvokeResult.OutArgs));
2225+
}
2226+
catch (InvocationException ex) {
2227+
// throw OCE if cancelled
2228+
token.ThrowIfCancellationRequested ();
2229+
if (ex.Exception != null) {
2230+
tcs.SetResult (new SoftOperationResult (ex.Exception, true, null));
2231+
}
2232+
else {
2233+
tcs.SetException (new EvaluatorException ("Target method has thrown an exception but the exception object is inaccessible"));
2234+
}
2235+
}
2236+
catch (Exception e) {
2237+
tcs.SetException (e);
2238+
}
2239+
finally {
2240+
UpdateSessionState ();
2241+
}
2242+
}, null);
2243+
return tcs.Task;
2244+
} catch (Exception) {
2245+
UpdateSessionState ();
2246+
throw;
22792247
}
22802248
}
22812249

2282-
public override bool WaitForCompleted (int timeout)
2250+
void UpdateSessionState ()
22832251
{
2284-
if (handle == null)
2285-
return true;
2286-
int res = WaitHandle.WaitAny (new WaitHandle[] { handle.AsyncWaitHandle, shutdownEvent }, timeout);
2287-
if (res == 0) {
2288-
EndInvoke ();
2289-
return true;
2290-
}
2291-
// Return true if shut down.
2292-
return res == 1;
2252+
ctx.Session.StackVersion++;
22932253
}
22942254

2295-
public Value ReturnValue {
2296-
get {
2297-
if (exception != null)
2298-
throw new EvaluatorException (exception.Message);
2299-
return result.Result;
2300-
}
2301-
}
2302-
2303-
public Value[] OutArgs {
2304-
get {
2305-
if (exception != null)
2306-
throw new EvaluatorException (exception.Message);
2307-
return result.OutArgs;
2255+
protected override void CancelImpl ()
2256+
{
2257+
if (invokeAsyncResult == null) {
2258+
DebuggerLoggingService.LogError ("invokeAsyncResult is null", new ArgumentNullException ("invokeAsyncResult"));
2259+
return;
23082260
}
2261+
invokeAsyncResult.Abort ();
23092262
}
23102263
}
23112264
}

Mono.Debugging.Soft/SoftEvaluationContext.cs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -184,17 +184,19 @@ Value RuntimeInvoke (MethodMirror method, object target, Value[] values, bool en
184184
return method.Evaluate (target is TypeMirror ? null : (Value) target, values);
185185
} catch (NotSupportedException) {
186186
AssertTargetInvokeAllowed ();
187-
188-
var mc = new MethodCall (this, method, target, values, enableOutArgs);
187+
var invocableMirror = target as IInvocableMethodOwnerMirror;
188+
if (invocableMirror == null)
189+
throw new ArgumentException ("Soft debugger method calls cannot be invoked on objects of type " + target.GetType ().Name);
190+
var mc = new SoftMethodCall (this, method, invocableMirror, values, enableOutArgs);
189191
//Since runtime is returning NOT_SUSPENDED error if two methods invokes are executed
190192
//at same time we have to lock invoking to prevent this...
191193
lock (method.VirtualMachine) {
192-
Adapter.AsyncExecute (mc, Options.EvaluationTimeout);
193-
}
194-
if (enableOutArgs) {
195-
outArgs = mc.OutArgs;
194+
var result = (SoftOperationResult)Adapter.InvokeSync (mc, Options.EvaluationTimeout).ThrowIfException (this);
195+
if (enableOutArgs) {
196+
outArgs = result.OutArgs;
197+
}
198+
return result.Result;
196199
}
197-
return mc.ReturnValue;
198200
}
199201
}
200202

Mono.Debugging/Mono.Debugging.Evaluation/AsyncEvaluationTracker.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ namespace Mono.Debugging.Evaluation
4141
/// will then be made asynchronous and the Run method will immediately return an ObjectValue
4242
/// with the Evaluating state.
4343
/// </summary>
44-
public class AsyncEvaluationTracker: RemoteFrameObject, IObjectValueUpdater, IDisposable
44+
public class AsyncEvaluationTracker: IObjectValueUpdater, IDisposable
4545
{
4646
Dictionary<string, UpdateCallback> asyncCallbacks = new Dictionary<string, UpdateCallback> ();
4747
Dictionary<string, ObjectValue> asyncResults = new Dictionary<string, ObjectValue> ();
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
using System;
2+
using System.Threading;
3+
using System.Threading.Tasks;
4+
using Mono.Debugging.Client;
5+
6+
namespace Mono.Debugging.Evaluation
7+
{
8+
public class OperationResult<TValue>
9+
{
10+
public TValue Result { get; private set; }
11+
public bool ResultIsException { get; private set; }
12+
13+
public OperationResult (TValue result, bool resultIsException)
14+
{
15+
Result = result;
16+
ResultIsException = resultIsException;
17+
}
18+
}
19+
20+
public static class OperationResultEx
21+
{
22+
public static OperationResult<TValue> ThrowIfException<TValue> (this OperationResult<TValue> result, EvaluationContext ctx)
23+
{
24+
if (!result.ResultIsException)
25+
return result;
26+
var exceptionTypeName = ctx.Adapter.GetValueTypeName (ctx, result.Result);
27+
throw new EvaluatorExceptionThrownException (result.Result, exceptionTypeName);
28+
}
29+
}
30+
31+
public interface IAsyncOperationBase
32+
{
33+
Task RawTask { get; }
34+
string Description { get; }
35+
void AfterCancelled (int elapsedAfterCancelMs);
36+
}
37+
38+
public abstract class AsyncOperationBase<TValue> : IAsyncOperationBase
39+
{
40+
public Task<OperationResult<TValue>> Task { get; protected set; }
41+
42+
public Task RawTask
43+
{
44+
get
45+
{
46+
return Task;
47+
}
48+
}
49+
50+
public abstract string Description { get; }
51+
52+
public void AfterCancelled (int elapsedAfterCancelMs)
53+
{
54+
try {
55+
AfterCancelledImpl (elapsedAfterCancelMs);
56+
}
57+
catch (Exception e) {
58+
DebuggerLoggingService.LogError ("AfterCancelledImpl() thrown an exception", e);
59+
}
60+
}
61+
62+
protected abstract void AfterCancelledImpl (int elapsedAfterCancelMs);
63+
64+
public Task<OperationResult<TValue>> InvokeAsync (CancellationToken token)
65+
{
66+
if (Task != null) throw new Exception("Task must be null");
67+
68+
token.Register (() => {
69+
try {
70+
CancelImpl ();
71+
}
72+
catch (OperationCanceledException) {
73+
// if CancelImpl throw OCE we shouldn't mute it
74+
throw;
75+
}
76+
catch (Exception e) {
77+
DebuggerLoggingService.LogMessage ("Exception in CancelImpl(): {0}", e.Message);
78+
}
79+
});
80+
Task = InvokeAsyncImpl (token);
81+
return Task;
82+
}
83+
protected abstract Task<OperationResult<TValue>> InvokeAsyncImpl (CancellationToken token);
84+
85+
protected abstract void CancelImpl ();
86+
87+
}
88+
}

0 commit comments

Comments
 (0)