1
+ using System ;
2
+ using System . Collections . Generic ;
3
+ using System . Threading ;
4
+ using System . Threading . Tasks ;
5
+
6
+ namespace Mono . Debugger . Soft
7
+ {
8
+ /// <summary>
9
+ /// A bunch of extension methods to <see cref="IInvocableMethodOwnerMirror"/> to perform invocations on objects
10
+ /// </summary>
11
+ public static class InvocationsAPI
12
+ {
13
+ public static Value InvokeMethod ( this IInvocableMethodOwnerMirror mirror , ThreadMirror thread , MethodMirror method , IList < Value > arguments , InvokeOptions options = InvokeOptions . None ) {
14
+ return InvokeMethod ( mirror , mirror . VirtualMachine , thread , method , mirror . GetThisObject ( ) , arguments , options ) ;
15
+ }
16
+
17
+ [ Obsolete ( "Use the overload without the 'vm' argument" ) ]
18
+ public static IAsyncResult BeginInvokeMethod ( this IInvocableMethodOwnerMirror mirror , VirtualMachine vm , ThreadMirror thread , MethodMirror method , IList < Value > arguments , InvokeOptions options , AsyncCallback callback , object state ) {
19
+ return BeginInvokeMethod ( vm , thread , method , mirror . GetThisObject ( ) , arguments , options , callback , state ) ;
20
+ }
21
+
22
+ public static IAsyncResult BeginInvokeMethod ( this IInvocableMethodOwnerMirror mirror , ThreadMirror thread , MethodMirror method , IList < Value > arguments , InvokeOptions options , AsyncCallback callback , object state ) {
23
+ return BeginInvokeMethod ( mirror . VirtualMachine , thread , method , mirror . GetThisObject ( ) , arguments , options , callback , state ) ;
24
+ }
25
+
26
+ public static Value EndInvokeMethod ( this IInvocableMethodOwnerMirror mirror , IAsyncResult asyncResult ) {
27
+ return EndInvokeMethodInternal ( mirror , asyncResult ) ;
28
+ }
29
+
30
+ public static InvokeResult EndInvokeMethodWithResult ( this IInvocableMethodOwnerMirror mirror , IAsyncResult asyncResult ) {
31
+ return EndInvokeMethodInternalWithResult ( mirror , asyncResult ) ;
32
+ }
33
+
34
+ public static Task < Value > InvokeMethodAsync ( this IInvocableMethodOwnerMirror mirror , ThreadMirror thread , MethodMirror method , IList < Value > arguments , InvokeOptions options = InvokeOptions . None ) {
35
+ var tcs = new TaskCompletionSource < Value > ( ) ;
36
+ BeginInvokeMethod ( mirror , thread , method , arguments , options , iar =>
37
+ {
38
+ try {
39
+ tcs . SetResult ( EndInvokeMethod ( mirror , iar ) ) ;
40
+ } catch ( OperationCanceledException ) {
41
+ tcs . TrySetCanceled ( ) ;
42
+ } catch ( Exception ex ) {
43
+ tcs . TrySetException ( ex ) ;
44
+ }
45
+ } , null ) ;
46
+ return tcs . Task ;
47
+ }
48
+
49
+ public static Task < InvokeResult > InvokeMethodAsyncWithResult ( this IInvocableMethodOwnerMirror mirror , ThreadMirror thread , MethodMirror method , IList < Value > arguments , InvokeOptions options = InvokeOptions . None ) {
50
+ var tcs = new TaskCompletionSource < InvokeResult > ( ) ;
51
+ BeginInvokeMethod ( mirror , thread , method , arguments , options , iar =>
52
+ {
53
+ try {
54
+ tcs . SetResult ( EndInvokeMethodInternalWithResult ( mirror , iar ) ) ;
55
+ } catch ( OperationCanceledException ) {
56
+ tcs . TrySetCanceled ( ) ;
57
+ } catch ( Exception ex ) {
58
+ tcs . TrySetException ( ex ) ;
59
+ }
60
+ } , null ) ;
61
+ return tcs . Task ;
62
+ }
63
+
64
+ /// <summary>
65
+ /// Invoke the members of METHODS one-by-one, calling CALLBACK after each invoke was finished. The IAsyncResult will be marked as completed after all invokes have
66
+ /// finished. The callback will be called with a different IAsyncResult that represents one method invocation.
67
+ /// From protocol version 2.22.
68
+ /// </summary>
69
+ public static IAsyncResult BeginInvokeMultiple ( this IInvocableMethodOwnerMirror mirror , ThreadMirror thread , MethodMirror [ ] methods , IList < IList < Value > > arguments , InvokeOptions options , AsyncCallback callback , object state ) {
70
+ return BeginInvokeMultiple ( mirror . VirtualMachine , thread , methods , mirror . GetThisObject ( ) , arguments , options , callback , state ) ;
71
+ }
72
+
73
+ public static void EndInvokeMultiple ( IAsyncResult asyncResult ) {
74
+ EndInvokeMultipleInternal ( asyncResult ) ;
75
+ }
76
+
77
+ /*
78
+ * Common implementation for invokes
79
+ */
80
+
81
+ class InvokeAsyncResult : IInvokeAsyncResult {
82
+
83
+ public object AsyncState {
84
+ get ; set ;
85
+ }
86
+
87
+ public WaitHandle AsyncWaitHandle {
88
+ get ; set ;
89
+ }
90
+
91
+ public bool CompletedSynchronously {
92
+ get {
93
+ return false ;
94
+ }
95
+ }
96
+
97
+ public bool IsCompleted {
98
+ get ; set ;
99
+ }
100
+
101
+ public AsyncCallback Callback {
102
+ get ; set ;
103
+ }
104
+
105
+ public ErrorCode ErrorCode {
106
+ get ; set ;
107
+ }
108
+
109
+ public VirtualMachine VM {
110
+ get ; set ;
111
+ }
112
+
113
+ public ThreadMirror Thread {
114
+ get ; set ;
115
+ }
116
+
117
+ public ValueImpl Value {
118
+ get ; set ;
119
+ }
120
+
121
+ public ValueImpl OutThis {
122
+ get ; set ;
123
+ }
124
+
125
+ public ValueImpl [ ] OutArgs {
126
+ get ; set ;
127
+ }
128
+
129
+ public ValueImpl Exception {
130
+ get ; set ;
131
+ }
132
+
133
+ public int ID {
134
+ get ; set ;
135
+ }
136
+
137
+ public bool IsMultiple {
138
+ get ; set ;
139
+ }
140
+
141
+ public int NumPending ;
142
+
143
+ public void Abort ( )
144
+ {
145
+ if ( ID == 0 ) // Ooops
146
+ return ;
147
+
148
+ AbortInvoke ( VM , Thread , ID ) ;
149
+ }
150
+ }
151
+
152
+ static IInvokeAsyncResult BeginInvokeMethod ( VirtualMachine vm , ThreadMirror thread , MethodMirror method , Value this_obj , IList < Value > arguments , InvokeOptions options , AsyncCallback callback , object state ) {
153
+ if ( thread == null )
154
+ throw new ArgumentNullException ( "thread" ) ;
155
+ if ( method == null )
156
+ throw new ArgumentNullException ( "method" ) ;
157
+ if ( arguments == null )
158
+ arguments = new Value [ 0 ] ;
159
+
160
+ InvokeFlags f = InvokeFlags . NONE ;
161
+
162
+ if ( ( options & InvokeOptions . DisableBreakpoints ) != 0 )
163
+ f |= InvokeFlags . DISABLE_BREAKPOINTS ;
164
+ if ( ( options & InvokeOptions . SingleThreaded ) != 0 )
165
+ f |= InvokeFlags . SINGLE_THREADED ;
166
+ if ( ( options & InvokeOptions . ReturnOutThis ) != 0 )
167
+ f |= InvokeFlags . OUT_THIS ;
168
+ if ( ( options & InvokeOptions . ReturnOutArgs ) != 0 )
169
+ f |= InvokeFlags . OUT_ARGS ;
170
+ if ( ( options & InvokeOptions . Virtual ) != 0 )
171
+ f |= InvokeFlags . VIRTUAL ;
172
+
173
+ InvokeAsyncResult r = new InvokeAsyncResult { AsyncState = state , AsyncWaitHandle = new ManualResetEvent ( false ) , VM = vm , Thread = thread , Callback = callback } ;
174
+ thread . InvalidateFrames ( ) ;
175
+ r . ID = vm . conn . VM_BeginInvokeMethod ( thread . Id , method . Id , this_obj != null ? vm . EncodeValue ( this_obj ) : vm . EncodeValue ( vm . CreateValue ( null ) ) , vm . EncodeValues ( arguments ) , f , InvokeCB , r ) ;
176
+
177
+ return r ;
178
+ }
179
+
180
+ // This is called when the result of an invoke is received
181
+ static void InvokeCB ( ValueImpl v , ValueImpl exc , ValueImpl out_this , ValueImpl [ ] out_args , ErrorCode error , object state ) {
182
+ InvokeAsyncResult r = ( InvokeAsyncResult ) state ;
183
+
184
+ if ( error != 0 ) {
185
+ r . ErrorCode = error ;
186
+ } else {
187
+ r . Value = v ;
188
+ r . Exception = exc ;
189
+ }
190
+
191
+ r . OutThis = out_this ;
192
+ r . OutArgs = out_args ;
193
+
194
+ r . IsCompleted = true ;
195
+ ( ( ManualResetEvent ) r . AsyncWaitHandle ) . Set ( ) ;
196
+
197
+ if ( r . Callback != null )
198
+ r . Callback . BeginInvoke ( r , null , null ) ;
199
+ }
200
+
201
+ static InvokeResult EndInvokeMethodInternalWithResult ( IInvocableMethodOwnerMirror mirror , IAsyncResult asyncResult ) {
202
+ var result = EndInvokeMethodInternalWithResultImpl ( asyncResult ) ;
203
+ mirror . ProcessResult ( result ) ;
204
+ return result ;
205
+ }
206
+
207
+ static InvokeResult EndInvokeMethodInternalWithResultImpl ( IAsyncResult asyncResult ) {
208
+ if ( asyncResult == null )
209
+ throw new ArgumentNullException ( "asyncResult" ) ;
210
+
211
+ InvokeAsyncResult r = ( InvokeAsyncResult ) asyncResult ;
212
+
213
+ if ( ! r . IsCompleted )
214
+ r . AsyncWaitHandle . WaitOne ( ) ;
215
+
216
+ if ( r . ErrorCode != 0 ) {
217
+ try {
218
+ r . VM . ErrorHandler ( null , new ErrorHandlerEventArgs ( ) { ErrorCode = r . ErrorCode } ) ;
219
+ } catch ( CommandException ex ) {
220
+ if ( ex . ErrorCode == ErrorCode . INVALID_ARGUMENT )
221
+ throw new ArgumentException ( "Incorrect number or types of arguments" , "arguments" ) ;
222
+
223
+ throw ;
224
+ }
225
+ throw new NotImplementedException ( ) ;
226
+ } else {
227
+ if ( r . Exception != null )
228
+ throw new InvocationException ( ( ObjectMirror ) r . VM . DecodeValue ( r . Exception ) ) ;
229
+
230
+ Value out_this = null ;
231
+ if ( r . OutThis != null )
232
+ out_this = r . VM . DecodeValue ( r . OutThis ) ;
233
+ Value [ ] out_args = null ;
234
+ if ( r . OutArgs != null )
235
+ out_args = r . VM . DecodeValues ( r . OutArgs ) ;
236
+
237
+ return new InvokeResult ( ) { Result = r . VM . DecodeValue ( r . Value ) , OutThis = out_this , OutArgs = out_args } ;
238
+ }
239
+ }
240
+
241
+ static Value EndInvokeMethodInternal ( IInvocableMethodOwnerMirror mirror , IAsyncResult asyncResult ) {
242
+ InvokeResult res = EndInvokeMethodInternalWithResult ( mirror , asyncResult ) ;
243
+ return res . Result ;
244
+ }
245
+
246
+ static void EndInvokeMultipleInternal ( IAsyncResult asyncResult ) {
247
+ if ( asyncResult == null )
248
+ throw new ArgumentNullException ( "asyncResult" ) ;
249
+
250
+ InvokeAsyncResult r = ( InvokeAsyncResult ) asyncResult ;
251
+
252
+ if ( ! r . IsCompleted )
253
+ r . AsyncWaitHandle . WaitOne ( ) ;
254
+ }
255
+
256
+ static Value InvokeMethod ( IInvocableMethodOwnerMirror mirror , VirtualMachine vm , ThreadMirror thread , MethodMirror method , Value this_obj , IList < Value > arguments , InvokeOptions options ) {
257
+ return EndInvokeMethodInternal ( mirror , BeginInvokeMethod ( vm , thread , method , this_obj , arguments , options , null , null ) ) ;
258
+ }
259
+
260
+ static void AbortInvoke ( VirtualMachine vm , ThreadMirror thread , int id )
261
+ {
262
+ vm . conn . VM_AbortInvoke ( thread . Id , id ) ;
263
+ }
264
+
265
+ //
266
+ // Implementation of InvokeMultiple
267
+ //
268
+
269
+ static IInvokeAsyncResult BeginInvokeMultiple ( VirtualMachine vm , ThreadMirror thread , MethodMirror [ ] methods , Value this_obj , IList < IList < Value > > arguments , InvokeOptions options , AsyncCallback callback , object state ) {
270
+ if ( thread == null )
271
+ throw new ArgumentNullException ( "thread" ) ;
272
+ if ( methods == null )
273
+ throw new ArgumentNullException ( "methods" ) ;
274
+ foreach ( var m in methods )
275
+ if ( m == null )
276
+ throw new ArgumentNullException ( "method" ) ;
277
+ if ( arguments == null ) {
278
+ arguments = new List < IList < Value > > ( ) ;
279
+ for ( int i = 0 ; i < methods . Length ; ++ i )
280
+ arguments . Add ( new Value [ 0 ] ) ;
281
+ } else {
282
+ // FIXME: Not needed for property evaluation
283
+ throw new NotImplementedException ( ) ;
284
+ }
285
+ if ( callback == null )
286
+ throw new ArgumentException ( "A callback argument is required for this method." , "callback" ) ;
287
+
288
+ InvokeFlags f = InvokeFlags . NONE ;
289
+
290
+ if ( ( options & InvokeOptions . DisableBreakpoints ) != 0 )
291
+ f |= InvokeFlags . DISABLE_BREAKPOINTS ;
292
+ if ( ( options & InvokeOptions . SingleThreaded ) != 0 )
293
+ f |= InvokeFlags . SINGLE_THREADED ;
294
+
295
+ InvokeAsyncResult r = new InvokeAsyncResult { AsyncState = state , AsyncWaitHandle = new ManualResetEvent ( false ) , VM = vm , Thread = thread , Callback = callback , NumPending = methods . Length , IsMultiple = true } ;
296
+
297
+ var mids = new long [ methods . Length ] ;
298
+ for ( int i = 0 ; i < methods . Length ; ++ i )
299
+ mids [ i ] = methods [ i ] . Id ;
300
+ var args = new List < ValueImpl [ ] > ( ) ;
301
+ for ( int i = 0 ; i < methods . Length ; ++ i )
302
+ args . Add ( vm . EncodeValues ( arguments [ i ] ) ) ;
303
+ thread . InvalidateFrames ( ) ;
304
+ r . ID = vm . conn . VM_BeginInvokeMethods ( thread . Id , mids , this_obj != null ? vm . EncodeValue ( this_obj ) : vm . EncodeValue ( vm . CreateValue ( null ) ) , args , f , InvokeMultipleCB , r ) ;
305
+
306
+ return r ;
307
+ }
308
+
309
+ // This is called when the result of an invoke is received
310
+ static void InvokeMultipleCB ( ValueImpl v , ValueImpl exc , ValueImpl out_this , ValueImpl [ ] out_args , ErrorCode error , object state ) {
311
+ var r = ( InvokeAsyncResult ) state ;
312
+
313
+ Interlocked . Decrement ( ref r . NumPending ) ;
314
+
315
+ if ( error != 0 )
316
+ r . ErrorCode = error ;
317
+
318
+ if ( r . NumPending == 0 ) {
319
+ r . IsCompleted = true ;
320
+ ( ( ManualResetEvent ) r . AsyncWaitHandle ) . Set ( ) ;
321
+ }
322
+
323
+ // Have to pass another asyncresult to the callback since multiple threads can execute it concurrently with results of multiple invocations
324
+ var r2 = new InvokeAsyncResult { AsyncState = r . AsyncState , AsyncWaitHandle = null , VM = r . VM , Thread = r . Thread , Callback = r . Callback , IsCompleted = true } ;
325
+
326
+ if ( error != 0 ) {
327
+ r2 . ErrorCode = error ;
328
+ } else {
329
+ r2 . Value = v ;
330
+ r2 . Exception = exc ;
331
+ }
332
+
333
+ r . Callback . BeginInvoke ( r2 , null , null ) ;
334
+ }
335
+
336
+ }
337
+ }
0 commit comments