Skip to content

Commit 3e78933

Browse files
committed
Async operations rewritten to Tasks
1 parent d4492b0 commit 3e78933

File tree

8 files changed

+312
-287
lines changed

8 files changed

+312
-287
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.Backend;
3939
using Mono.Debugging.Evaluation;
@@ -2177,30 +2177,36 @@ static string MirrorStringToString (EvaluationContext ctx, StringMirror mirror)
21772177
}
21782178
}
21792179

2180-
class MethodCall: AsyncOperation
2180+
internal class SoftOperationResult : OperationResult<Value>
21812181
{
2182-
readonly InvokeOptions options = InvokeOptions.DisableBreakpoints | InvokeOptions.SingleThreaded;
2182+
public SoftOperationResult (Value result, bool resultIsException, Value[] outArgs) : base (result, resultIsException)
2183+
{
2184+
OutArgs = outArgs;
2185+
}
2186+
2187+
public Value[] OutArgs { get; private set; }
2188+
}
21832189

2184-
readonly ManualResetEvent shutdownEvent = new ManualResetEvent (false);
2190+
internal class SoftMethodCall: AsyncOperationBase<Value>
2191+
{
2192+
readonly InvokeOptions options = InvokeOptions.DisableBreakpoints | InvokeOptions.SingleThreaded;
21852193
readonly SoftEvaluationContext ctx;
21862194
readonly MethodMirror function;
21872195
readonly Value[] args;
2188-
readonly object obj;
2189-
IAsyncResult handle;
2190-
Exception exception;
2191-
IInvokeResult result;
2192-
2193-
public MethodCall (SoftEvaluationContext ctx, MethodMirror function, object obj, Value[] args, bool enableOutArgs)
2196+
readonly IInvocableMethodOwnerMirror obj;
2197+
IInvokeAsyncResult invokeAsyncResult;
2198+
2199+
public SoftMethodCall (SoftEvaluationContext ctx, MethodMirror function, IInvocableMethodOwnerMirror obj, Value[] args, bool enableOutArgs)
21942200
{
21952201
this.ctx = ctx;
21962202
this.function = function;
21972203
this.obj = obj;
21982204
this.args = args;
21992205
if (enableOutArgs) {
2200-
this.options |= InvokeOptions.ReturnOutArgs;
2206+
options |= InvokeOptions.ReturnOutArgs;
22012207
}
22022208
if (function.VirtualMachine.Version.AtLeast (2, 40)) {
2203-
this.options |= InvokeOptions.Virtual;
2209+
options |= InvokeOptions.Virtual;
22042210
}
22052211
}
22062212

@@ -2210,113 +2216,60 @@ public override string Description {
22102216
}
22112217
}
22122218

2213-
public override void Invoke ()
2219+
protected override void AfterCancelledImpl (int elapsedAfterCancelMs)
22142220
{
2215-
try {
2216-
var invocableMirror = obj as IInvocableMethodOwnerMirror;
2217-
if (invocableMirror != null) {
2218-
var optionsToInvoke = options;
2219-
if (obj is StructMirror) {
2220-
optionsToInvoke |= InvokeOptions.ReturnOutThis;
2221-
}
2222-
handle = invocableMirror.BeginInvokeMethod (ctx.Thread, function, args, optionsToInvoke, null, null);
2223-
}
2224-
else
2225-
throw new ArgumentException ("Soft debugger method calls cannot be invoked on objects of type " + obj.GetType ().Name);
2226-
} catch (InvocationException ex) {
2227-
ctx.Session.StackVersion++;
2228-
exception = ex;
2229-
} catch (Exception ex) {
2230-
ctx.Session.StackVersion++;
2231-
DebuggerLoggingService.LogError ("Error in soft debugger method call thread on " + GetInfo (), ex);
2232-
exception = ex;
2233-
}
22342221
}
22352222

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

2293-
public override bool WaitForCompleted (int timeout)
2261+
void UpdateSessionState ()
22942262
{
2295-
if (handle == null)
2296-
return true;
2297-
int res = WaitHandle.WaitAny (new WaitHandle[] { handle.AsyncWaitHandle, shutdownEvent }, timeout);
2298-
if (res == 0) {
2299-
EndInvoke ();
2300-
return true;
2301-
}
2302-
// Return true if shut down.
2303-
return res == 1;
2263+
ctx.Session.StackVersion++;
23042264
}
23052265

2306-
public Value ReturnValue {
2307-
get {
2308-
if (exception != null)
2309-
throw new EvaluatorException (exception.Message);
2310-
return result.Result;
2311-
}
2312-
}
2313-
2314-
public Value[] OutArgs {
2315-
get {
2316-
if (exception != null)
2317-
throw new EvaluatorException (exception.Message);
2318-
return result.OutArgs;
2266+
protected override void CancelImpl ()
2267+
{
2268+
if (invokeAsyncResult == null) {
2269+
DebuggerLoggingService.LogError ("invokeAsyncResult is null", new ArgumentNullException ("invokeAsyncResult"));
2270+
return;
23192271
}
2272+
invokeAsyncResult.Abort ();
23202273
}
23212274
}
23222275
}

Mono.Debugging.Soft/SoftEvaluationContext.cs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -190,16 +190,19 @@ Value RuntimeInvoke (MethodMirror method, object target, Value[] values, bool en
190190
DC.DebuggerLoggingService.LogMessage ("Thread state before evaluation is {0}", threadState);
191191
throw new EvaluatorException ("Evaluation is not allowed when the thread is in 'Wait' state");
192192
}
193-
var mc = new MethodCall (this, method, target, values, enableOutArgs);
193+
var invocableMirror = target as IInvocableMethodOwnerMirror;
194+
if (invocableMirror == null)
195+
throw new ArgumentException ("Soft debugger method calls cannot be invoked on objects of type " + target.GetType ().Name);
196+
var mc = new SoftMethodCall (this, method, invocableMirror, values, enableOutArgs);
194197
//Since runtime is returning NOT_SUSPENDED error if two methods invokes are executed
195198
//at same time we have to lock invoking to prevent this...
196199
lock (method.VirtualMachine) {
197-
Adapter.AsyncExecute (mc, Options.EvaluationTimeout);
198-
}
199-
if (enableOutArgs) {
200-
outArgs = mc.OutArgs;
200+
var result = (SoftOperationResult)Adapter.InvokeSync (mc, Options.EvaluationTimeout).ThrowIfException (this);
201+
if (enableOutArgs) {
202+
outArgs = result.OutArgs;
203+
}
204+
return result.Result;
201205
}
202-
return mc.ReturnValue;
203206
}
204207
}
205208

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)