1
// RuntimeInvokeManager.cs
4
// Lluis Sanchez Gual <lluis@novell.com>
6
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
8
// Permission is hereby granted, free of charge, to any person obtaining a copy
9
// of this software and associated documentation files (the "Software"), to deal
10
// in the Software without restriction, including without limitation the rights
11
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
// copies of the Software, and to permit persons to whom the Software is
13
// furnished to do so, subject to the following conditions:
15
// The above copyright notice and this permission notice shall be included in
16
// all copies or substantial portions of the Software.
18
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29
using System.Collections.Generic;
30
using ST = System.Threading;
31
using Mono.Debugging.Client;
33
namespace Mono.Debugging.Evaluation
35
public class AsyncOperationManager: IDisposable
37
List<AsyncOperation> operationsToCancel = new List<AsyncOperation> ();
38
internal bool Disposing;
40
public void Invoke (AsyncOperation methodCall, int timeout)
42
methodCall.Aborted = false;
43
methodCall.Manager = this;
45
lock (operationsToCancel) {
46
operationsToCancel.Add (methodCall);
51
if (!methodCall.WaitForCompleted (timeout)) {
52
bool wasAborted = methodCall.Aborted;
53
methodCall.InternalAbort ();
54
lock (operationsToCancel) {
55
operationsToCancel.Remove (methodCall);
56
ST.Monitor.PulseAll (operationsToCancel);
59
throw new EvaluatorException ("Aborted.");
61
throw new TimeOutException ();
65
methodCall.WaitForCompleted (System.Threading.Timeout.Infinite);
68
lock (operationsToCancel) {
69
operationsToCancel.Remove (methodCall);
70
ST.Monitor.PulseAll (operationsToCancel);
71
if (methodCall.Aborted) {
72
throw new EvaluatorException ("Aborted.");
76
if (!string.IsNullOrEmpty (methodCall.ExceptionMessage)) {
77
throw new Exception (methodCall.ExceptionMessage);
81
public void Dispose ()
84
lock (operationsToCancel) {
85
foreach (AsyncOperation op in operationsToCancel) {
86
op.InternalShutdown ();
88
operationsToCancel.Clear ();
92
public void AbortAll ()
94
lock (operationsToCancel) {
95
foreach (AsyncOperation op in operationsToCancel)
100
public void EnterBusyState (AsyncOperation oper)
102
BusyStateEventArgs args = new BusyStateEventArgs ();
104
args.Description = oper.Description;
105
if (BusyStateChanged != null)
106
BusyStateChanged (this, args);
109
public void LeaveBusyState (AsyncOperation oper)
111
BusyStateEventArgs args = new BusyStateEventArgs ();
113
args.Description = oper.Description;
114
if (BusyStateChanged != null)
115
BusyStateChanged (this, args);
118
public event EventHandler<BusyStateEventArgs> BusyStateChanged;
121
public abstract class AsyncOperation
123
internal bool Aborted;
124
internal bool Aborting;
125
internal AsyncOperationManager Manager;
127
internal void InternalAbort ()
129
ST.Monitor.Enter (this);
131
ST.Monitor.Exit (this);
136
// Somebody else is aborting this. Just wait for it to finish.
137
ST.Monitor.Exit (this);
138
WaitForCompleted (System.Threading.Timeout.Infinite);
145
int abortRetryWait = 100;
149
ST.Monitor.Enter (this);
154
ST.Monitor.Exit (this);
157
// If abort fails, try again after a short wait
160
if (abortState == 6) {
161
// Several abort calls have failed. Inform the user that the debugger is busy
162
abortRetryWait = 500;
164
Manager.EnterBusyState (this);
165
} catch (Exception ex) {
166
Console.WriteLine (ex);
169
ST.Monitor.Exit (this);
170
} while (!Aborted && !WaitForCompleted (abortRetryWait) && !Manager.Disposing);
172
if (Manager.Disposing) {
179
Manager.LeaveBusyState (this);
184
internal void InternalShutdown ()
199
/// Message of the exception, if the execution failed.
201
public string ExceptionMessage { get; set; }
204
/// Returns a short description of the operation, to be shown in the Debugger Busy Dialog
205
/// when it blocks the execution of the debugger.
207
public abstract string Description { get; }
210
/// Called to invoke the operation. The execution must be asynchronous (it must return immediatelly).
212
public abstract void Invoke ( );
215
/// Called to abort the execution of the operation. It has to throw an exception
216
/// if the operation can't be aborted.
218
public abstract void Abort ( );
221
/// Waits until the operation has been completed or aborted.
223
public abstract bool WaitForCompleted (int timeout);
226
/// Called when the debugging session has been disposed.
227
/// I must cause any call to WaitForCompleted to exit, even if the operation
228
/// has not been completed or can't be aborted.
230
public abstract void Shutdown ();
1
// RuntimeInvokeManager.cs
4
// Lluis Sanchez Gual <lluis@novell.com>
6
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
8
// Permission is hereby granted, free of charge, to any person obtaining a copy
9
// of this software and associated documentation files (the "Software"), to deal
10
// in the Software without restriction, including without limitation the rights
11
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
// copies of the Software, and to permit persons to whom the Software is
13
// furnished to do so, subject to the following conditions:
15
// The above copyright notice and this permission notice shall be included in
16
// all copies or substantial portions of the Software.
18
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29
using System.Collections.Generic;
30
using ST = System.Threading;
31
using Mono.Debugging.Client;
33
namespace Mono.Debugging.Evaluation
35
public class AsyncOperationManager: IDisposable
37
List<AsyncOperation> operationsToCancel = new List<AsyncOperation> ();
38
internal bool Disposing;
40
public void Invoke (AsyncOperation methodCall, int timeout)
42
methodCall.Aborted = false;
43
methodCall.Manager = this;
45
lock (operationsToCancel) {
46
operationsToCancel.Add (methodCall);
51
if (!methodCall.WaitForCompleted (timeout)) {
52
bool wasAborted = methodCall.Aborted;
53
methodCall.InternalAbort ();
54
lock (operationsToCancel) {
55
operationsToCancel.Remove (methodCall);
56
ST.Monitor.PulseAll (operationsToCancel);
59
throw new EvaluatorException ("Aborted.");
61
throw new TimeOutException ();
65
methodCall.WaitForCompleted (System.Threading.Timeout.Infinite);
68
lock (operationsToCancel) {
69
operationsToCancel.Remove (methodCall);
70
ST.Monitor.PulseAll (operationsToCancel);
71
if (methodCall.Aborted) {
72
throw new EvaluatorException ("Aborted.");
76
if (!string.IsNullOrEmpty (methodCall.ExceptionMessage)) {
77
throw new Exception (methodCall.ExceptionMessage);
81
public void Dispose ()
84
lock (operationsToCancel) {
85
foreach (AsyncOperation op in operationsToCancel) {
86
op.InternalShutdown ();
88
operationsToCancel.Clear ();
92
public void AbortAll ()
94
lock (operationsToCancel) {
95
foreach (AsyncOperation op in operationsToCancel)
100
public void EnterBusyState (AsyncOperation oper)
102
BusyStateEventArgs args = new BusyStateEventArgs ();
104
args.Description = oper.Description;
105
if (BusyStateChanged != null)
106
BusyStateChanged (this, args);
109
public void LeaveBusyState (AsyncOperation oper)
111
BusyStateEventArgs args = new BusyStateEventArgs ();
113
args.Description = oper.Description;
114
if (BusyStateChanged != null)
115
BusyStateChanged (this, args);
118
public event EventHandler<BusyStateEventArgs> BusyStateChanged;
121
public abstract class AsyncOperation
123
internal bool Aborted;
124
internal AsyncOperationManager Manager;
126
public bool Aborting { get; internal set; }
128
internal void InternalAbort ()
130
ST.Monitor.Enter (this);
132
ST.Monitor.Exit (this);
137
// Somebody else is aborting this. Just wait for it to finish.
138
ST.Monitor.Exit (this);
139
WaitForCompleted (ST.Timeout.Infinite);
146
int abortRetryWait = 100;
147
bool abortRequested = false;
151
ST.Monitor.Enter (this);
154
if (!Aborted && !abortRequested) {
155
// The Abort() call doesn't block. WaitForCompleted is used below to wait for the abort to succeed
157
abortRequested = true;
159
// Short wait for the Abort to finish. If this wait is not enough, it will wait again in the next loop
160
if (WaitForCompleted (100)) {
161
ST.Monitor.Exit (this);
165
// If abort fails, try again after a short wait
168
if (abortState == 6) {
169
// Several abort calls have failed. Inform the user that the debugger is busy
170
abortRetryWait = 500;
172
Manager.EnterBusyState (this);
173
} catch (Exception ex) {
174
Console.WriteLine (ex);
177
ST.Monitor.Exit (this);
178
} while (!Aborted && !WaitForCompleted (abortRetryWait) && !Manager.Disposing);
180
if (Manager.Disposing) {
187
Manager.LeaveBusyState (this);
192
internal void InternalShutdown ()
207
/// Message of the exception, if the execution failed.
209
public string ExceptionMessage { get; set; }
212
/// Returns a short description of the operation, to be shown in the Debugger Busy Dialog
213
/// when it blocks the execution of the debugger.
215
public abstract string Description { get; }
218
/// Called to invoke the operation. The execution must be asynchronous (it must return immediatelly).
220
public abstract void Invoke ( );
223
/// Called to abort the execution of the operation. It has to throw an exception
224
/// if the operation can't be aborted. This operation must not block. The engine
225
/// will wait for the operation to be aborted by calling WaitForCompleted.
227
public abstract void Abort ();
230
/// Waits until the operation has been completed or aborted.
232
public abstract bool WaitForCompleted (int timeout);
235
/// Called when the debugging session has been disposed.
236
/// I must cause any call to WaitForCompleted to exit, even if the operation
237
/// has not been completed or can't be aborted.
239
public abstract void Shutdown ();