Skip to content

Commit f3e1fee

Browse files
committed
Async operations rewritten to Tasks
1 parent 54a8ed0 commit f3e1fee

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;
@@ -2145,30 +2145,36 @@ static string MirrorStringToString (EvaluationContext ctx, StringMirror mirror)
21452145
}
21462146
}
21472147

2148-
class MethodCall: AsyncOperation
2148+
internal class SoftOperationResult : OperationResult<Value>
21492149
{
2150-
readonly InvokeOptions options = InvokeOptions.DisableBreakpoints | InvokeOptions.SingleThreaded;
2150+
public SoftOperationResult (Value result, bool resultIsException, Value[] outArgs) : base (result, resultIsException)
2151+
{
2152+
OutArgs = outArgs;
2153+
}
2154+
2155+
public Value[] OutArgs { get; private set; }
2156+
}
21512157

2152-
readonly ManualResetEvent shutdownEvent = new ManualResetEvent (false);
2158+
internal class SoftMethodCall: AsyncOperationBase<Value>
2159+
{
2160+
readonly InvokeOptions options = InvokeOptions.DisableBreakpoints | InvokeOptions.SingleThreaded;
21532161
readonly SoftEvaluationContext ctx;
21542162
readonly MethodMirror function;
21552163
readonly Value[] args;
2156-
readonly object obj;
2157-
IAsyncResult handle;
2158-
Exception exception;
2159-
IInvokeResult result;
2160-
2161-
public MethodCall (SoftEvaluationContext ctx, MethodMirror function, object obj, Value[] args, bool enableOutArgs)
2164+
readonly IInvocableMethodOwnerMirror obj;
2165+
IInvokeAsyncResult invokeAsyncResult;
2166+
2167+
public SoftMethodCall (SoftEvaluationContext ctx, MethodMirror function, IInvocableMethodOwnerMirror obj, Value[] args, bool enableOutArgs)
21622168
{
21632169
this.ctx = ctx;
21642170
this.function = function;
21652171
this.obj = obj;
21662172
this.args = args;
21672173
if (enableOutArgs) {
2168-
this.options |= InvokeOptions.ReturnOutArgs;
2174+
options |= InvokeOptions.ReturnOutArgs;
21692175
}
21702176
if (function.VirtualMachine.Version.AtLeast (2, 40)) {
2171-
this.options |= InvokeOptions.Virtual;
2177+
options |= InvokeOptions.Virtual;
21722178
}
21732179
}
21742180

@@ -2178,113 +2184,60 @@ public override string Description {
21782184
}
21792185
}
21802186

2181-
public override void Invoke ()
2187+
protected override void AfterCancelledImpl (int elapsedAfterCancelMs)
21822188
{
2183-
try {
2184-
var invocableMirror = obj as IInvocableMethodOwnerMirror;
2185-
if (invocableMirror != null) {
2186-
var optionsToInvoke = options;
2187-
if (obj is StructMirror) {
2188-
optionsToInvoke |= InvokeOptions.ReturnOutThis;
2189-
}
2190-
handle = invocableMirror.BeginInvokeMethod (ctx.Thread, function, args, optionsToInvoke, null, null);
2191-
}
2192-
else
2193-
throw new ArgumentException ("Soft debugger method calls cannot be invoked on objects of type " + obj.GetType ().Name);
2194-
} catch (InvocationException ex) {
2195-
ctx.Session.StackVersion++;
2196-
exception = ex;
2197-
} catch (Exception ex) {
2198-
ctx.Session.StackVersion++;
2199-
DebuggerLoggingService.LogError ("Error in soft debugger method call thread on " + GetInfo (), ex);
2200-
exception = ex;
2201-
}
22022189
}
22032190

2204-
public override void Abort ()
2205-
{
2206-
if (handle is IInvokeAsyncResult) {
2207-
var info = GetInfo ();
2208-
DebuggerLoggingService.LogMessage ("Aborting invocation of " + info);
2209-
((IInvokeAsyncResult) handle).Abort ();
2210-
// Don't wait for the abort to finish. The engine will do it.
2211-
} else {
2212-
throw new NotSupportedException ();
2213-
}
2214-
}
2215-
2216-
public override void Shutdown ()
2217-
{
2218-
shutdownEvent.Set ();
2219-
}
2220-
2221-
void EndInvoke ()
2191+
protected override Task<OperationResult<Value>> InvokeAsyncImpl (CancellationToken token)
22222192
{
22232193
try {
2224-
result = ((IInvocableMethodOwnerMirror) obj).EndInvokeMethodWithResult (handle);
2225-
} catch (InvocationException ex) {
2226-
if (!Aborting && ex.Exception != null) {
2227-
string ename = ctx.Adapter.GetValueTypeName (ctx, ex.Exception);
2228-
var vref = ctx.Adapter.GetMember (ctx, null, ex.Exception, "Message");
2229-
2230-
exception = vref != null ? new Exception (ename + ": " + (string) vref.ObjectValue) : new Exception (ename);
2231-
return;
2194+
var optionsToInvoke = options;
2195+
if (obj is StructMirror) {
2196+
optionsToInvoke |= InvokeOptions.ReturnOutThis;
22322197
}
2233-
exception = ex;
2234-
} catch (Exception ex) {
2235-
DebuggerLoggingService.LogError ("Error in soft debugger method call thread on " + GetInfo (), ex);
2236-
exception = ex;
2237-
} finally {
2238-
ctx.Session.StackVersion++;
2239-
}
2240-
}
2241-
2242-
string GetInfo ()
2243-
{
2244-
try {
2245-
TypeMirror type = null;
2246-
if (obj is ObjectMirror)
2247-
type = ((ObjectMirror)obj).Type;
2248-
else if (obj is TypeMirror)
2249-
type = (TypeMirror)obj;
2250-
else if (obj is StructMirror)
2251-
type = ((StructMirror)obj).Type;
2252-
return string.Format ("method {0} on object {1}",
2253-
function == null? "[null]" : function.FullName,
2254-
type == null? "[null]" : type.FullName);
2255-
} catch (Exception ex) {
2256-
DebuggerLoggingService.LogError ("Error getting info for SDB MethodCall", ex);
2257-
return "";
2198+
var tcs = new TaskCompletionSource<OperationResult<Value>> ();
2199+
invokeAsyncResult = (IInvokeAsyncResult)obj.BeginInvokeMethod (ctx.Thread, function, args, optionsToInvoke, ar => {
2200+
try {
2201+
var endInvokeResult = obj.EndInvokeMethodWithResult (ar);
2202+
token.ThrowIfCancellationRequested ();
2203+
tcs.SetResult (new SoftOperationResult (endInvokeResult.Result, false, endInvokeResult.OutArgs));
2204+
}
2205+
catch (InvocationException ex) {
2206+
// throw OCE if cancelled
2207+
token.ThrowIfCancellationRequested ();
2208+
if (ex.Exception != null) {
2209+
tcs.SetResult (new SoftOperationResult (ex.Exception, true, null));
2210+
}
2211+
else {
2212+
tcs.SetException (new EvaluatorException ("Target method has thrown an exception but the exception object is inaccessible"));
2213+
}
2214+
}
2215+
catch (Exception e) {
2216+
tcs.SetException (e);
2217+
}
2218+
finally {
2219+
UpdateSessionState ();
2220+
}
2221+
}, null);
2222+
return tcs.Task;
2223+
} catch (Exception) {
2224+
UpdateSessionState ();
2225+
throw;
22582226
}
22592227
}
22602228

2261-
public override bool WaitForCompleted (int timeout)
2229+
void UpdateSessionState ()
22622230
{
2263-
if (handle == null)
2264-
return true;
2265-
int res = WaitHandle.WaitAny (new WaitHandle[] { handle.AsyncWaitHandle, shutdownEvent }, timeout);
2266-
if (res == 0) {
2267-
EndInvoke ();
2268-
return true;
2269-
}
2270-
// Return true if shut down.
2271-
return res == 1;
2231+
ctx.Session.StackVersion++;
22722232
}
22732233

2274-
public Value ReturnValue {
2275-
get {
2276-
if (exception != null)
2277-
throw new EvaluatorException (exception.Message);
2278-
return result.Result;
2279-
}
2280-
}
2281-
2282-
public Value[] OutArgs {
2283-
get {
2284-
if (exception != null)
2285-
throw new EvaluatorException (exception.Message);
2286-
return result.OutArgs;
2234+
protected override void CancelImpl ()
2235+
{
2236+
if (invokeAsyncResult == null) {
2237+
DebuggerLoggingService.LogError ("invokeAsyncResult is null", new ArgumentNullException ("invokeAsyncResult"));
2238+
return;
22872239
}
2240+
invokeAsyncResult.Abort ();
22882241
}
22892242
}
22902243
}

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)