~ubuntu-branches/ubuntu/oneiric/monodevelop/oneiric

« back to all changes in this revision

Viewing changes to src/core/Mono.Debugging/Mono.Debugging.Evaluation/AsyncOperationManager.cs

  • Committer: Bazaar Package Importer
  • Author(s): Jo Shields
  • Date: 2011-06-27 17:03:13 UTC
  • mto: (1.8.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 54.
  • Revision ID: james.westby@ubuntu.com-20110627170313-6cvz3s19x6e9hqe9
ImportĀ upstreamĀ versionĀ 2.5.92+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// RuntimeInvokeManager.cs
2
 
//
3
 
// Author:
4
 
//   Lluis Sanchez Gual <lluis@novell.com>
5
 
//
6
 
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
7
 
//
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:
14
 
//
15
 
// The above copyright notice and this permission notice shall be included in
16
 
// all copies or substantial portions of the Software.
17
 
//
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
24
 
// THE SOFTWARE.
25
 
//
26
 
//
27
 
 
28
 
using System;
29
 
using System.Collections.Generic;
30
 
using ST = System.Threading;
31
 
using Mono.Debugging.Client;
32
 
 
33
 
namespace Mono.Debugging.Evaluation
34
 
{
35
 
        public class AsyncOperationManager: IDisposable
36
 
        {
37
 
                List<AsyncOperation> operationsToCancel = new List<AsyncOperation> ();
38
 
                internal bool Disposing;
39
 
 
40
 
                public void Invoke (AsyncOperation methodCall, int timeout)
41
 
                {
42
 
                        methodCall.Aborted = false;
43
 
                        methodCall.Manager = this;
44
 
 
45
 
                        lock (operationsToCancel) {
46
 
                                operationsToCancel.Add (methodCall);
47
 
                                methodCall.Invoke ();
48
 
                        }
49
 
 
50
 
                        if (timeout != -1) {
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);
57
 
                                        }
58
 
                                        if (wasAborted)
59
 
                                                throw new EvaluatorException ("Aborted.");
60
 
                                        else
61
 
                                                throw new TimeOutException ();
62
 
                                }
63
 
                        }
64
 
                        else {
65
 
                                methodCall.WaitForCompleted (System.Threading.Timeout.Infinite);
66
 
                        }
67
 
 
68
 
                        lock (operationsToCancel) {
69
 
                                operationsToCancel.Remove (methodCall);
70
 
                                ST.Monitor.PulseAll (operationsToCancel);
71
 
                                if (methodCall.Aborted) {
72
 
                                        throw new EvaluatorException ("Aborted.");
73
 
                                }
74
 
                        }
75
 
 
76
 
                        if (!string.IsNullOrEmpty (methodCall.ExceptionMessage)) {
77
 
                                throw new Exception (methodCall.ExceptionMessage);
78
 
                        }
79
 
                }
80
 
                
81
 
                public void Dispose ()
82
 
                {
83
 
                        Disposing = true;
84
 
                        lock (operationsToCancel) {
85
 
                                foreach (AsyncOperation op in operationsToCancel) {
86
 
                                        op.InternalShutdown ();
87
 
                                }
88
 
                                operationsToCancel.Clear ();
89
 
                        }
90
 
                }
91
 
 
92
 
                public void AbortAll ()
93
 
                {
94
 
                        lock (operationsToCancel) {
95
 
                                foreach (AsyncOperation op in operationsToCancel)
96
 
                                        op.InternalAbort ();
97
 
                        }
98
 
                }
99
 
                
100
 
                public void EnterBusyState (AsyncOperation oper)
101
 
                {
102
 
                        BusyStateEventArgs args = new BusyStateEventArgs ();
103
 
                        args.IsBusy = true;
104
 
                        args.Description = oper.Description;
105
 
                        if (BusyStateChanged != null)
106
 
                                BusyStateChanged (this, args);
107
 
                }
108
 
                
109
 
                public void LeaveBusyState (AsyncOperation oper)
110
 
                {
111
 
                        BusyStateEventArgs args = new BusyStateEventArgs ();
112
 
                        args.IsBusy = false;
113
 
                        args.Description = oper.Description;
114
 
                        if (BusyStateChanged != null)
115
 
                                BusyStateChanged (this, args);
116
 
                }
117
 
                
118
 
                public event EventHandler<BusyStateEventArgs> BusyStateChanged;
119
 
        }
120
 
 
121
 
        public abstract class AsyncOperation
122
 
        {
123
 
                internal bool Aborted;
124
 
                internal bool Aborting;
125
 
                internal AsyncOperationManager Manager;
126
 
                
127
 
                internal void InternalAbort ()
128
 
                {
129
 
                        ST.Monitor.Enter (this);
130
 
                        if (Aborted) {
131
 
                                ST.Monitor.Exit (this);
132
 
                                return;
133
 
                        }
134
 
                        
135
 
                        if (Aborting) {
136
 
                                // Somebody else is aborting this. Just wait for it to finish.
137
 
                                ST.Monitor.Exit (this);
138
 
                                WaitForCompleted (System.Threading.Timeout.Infinite);
139
 
                                return;
140
 
                        }
141
 
                        
142
 
                        Aborting = true;
143
 
                        
144
 
                        int abortState = 0;
145
 
                        int abortRetryWait = 100;
146
 
                        
147
 
                        do {
148
 
                                if (abortState > 0)
149
 
                                        ST.Monitor.Enter (this);
150
 
                                
151
 
                                try {
152
 
                                        if (!Aborted)
153
 
                                                Abort ();
154
 
                                        ST.Monitor.Exit (this);
155
 
                                        break;
156
 
                                } catch {
157
 
                                        // If abort fails, try again after a short wait
158
 
                                }
159
 
                                abortState++;
160
 
                                if (abortState == 6) {
161
 
                                        // Several abort calls have failed. Inform the user that the debugger is busy
162
 
                                        abortRetryWait = 500;
163
 
                                        try {
164
 
                                                Manager.EnterBusyState (this);
165
 
                                        } catch (Exception ex) {
166
 
                                                Console.WriteLine (ex);
167
 
                                        }
168
 
                                }
169
 
                                ST.Monitor.Exit (this);
170
 
                        } while (!Aborted && !WaitForCompleted (abortRetryWait) && !Manager.Disposing);
171
 
                        
172
 
                        if (Manager.Disposing) {
173
 
                                InternalShutdown ();
174
 
                        }
175
 
                        else {
176
 
                                lock (this) {
177
 
                                        Aborted = true;
178
 
                                        if (abortState >= 6)
179
 
                                                Manager.LeaveBusyState (this);
180
 
                                }
181
 
                        }
182
 
                }
183
 
                
184
 
                internal void InternalShutdown ()
185
 
                {
186
 
                        lock (this) {
187
 
                                if (Aborted)
188
 
                                        return;
189
 
                                try {
190
 
                                        Aborted = true;
191
 
                                        Shutdown ();
192
 
                                } catch {
193
 
                                        // Ignore
194
 
                                }
195
 
                        }
196
 
                }
197
 
                
198
 
                /// <summary>
199
 
                /// Message of the exception, if the execution failed. 
200
 
                /// </summary>
201
 
                public string ExceptionMessage { get; set; }
202
 
 
203
 
                /// <summary>
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. 
206
 
                /// </summary>
207
 
                public abstract string Description { get; }
208
 
                
209
 
                /// <summary>
210
 
                /// Called to invoke the operation. The execution must be asynchronous (it must return immediatelly).
211
 
                /// </summary>
212
 
                public abstract void Invoke ( );
213
 
 
214
 
                /// <summary>
215
 
                /// Called to abort the execution of the operation. It has to throw an exception
216
 
                /// if the operation can't be aborted.
217
 
                /// </summary>
218
 
                public abstract void Abort ( );
219
 
 
220
 
                /// <summary>
221
 
                /// Waits until the operation has been completed or aborted.
222
 
                /// </summary>
223
 
                public abstract bool WaitForCompleted (int timeout);
224
 
                
225
 
                /// <summary>
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.
229
 
                /// </summary>
230
 
                public abstract void Shutdown ();
231
 
        }
232
 
}
 
1
// RuntimeInvokeManager.cs
 
2
//
 
3
// Author:
 
4
//   Lluis Sanchez Gual <lluis@novell.com>
 
5
//
 
6
// Copyright (c) 2008 Novell, Inc (http://www.novell.com)
 
7
//
 
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:
 
14
//
 
15
// The above copyright notice and this permission notice shall be included in
 
16
// all copies or substantial portions of the Software.
 
17
//
 
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
 
24
// THE SOFTWARE.
 
25
//
 
26
//
 
27
 
 
28
using System;
 
29
using System.Collections.Generic;
 
30
using ST = System.Threading;
 
31
using Mono.Debugging.Client;
 
32
 
 
33
namespace Mono.Debugging.Evaluation
 
34
{
 
35
        public class AsyncOperationManager: IDisposable
 
36
        {
 
37
                List<AsyncOperation> operationsToCancel = new List<AsyncOperation> ();
 
38
                internal bool Disposing;
 
39
 
 
40
                public void Invoke (AsyncOperation methodCall, int timeout)
 
41
                {
 
42
                        methodCall.Aborted = false;
 
43
                        methodCall.Manager = this;
 
44
 
 
45
                        lock (operationsToCancel) {
 
46
                                operationsToCancel.Add (methodCall);
 
47
                                methodCall.Invoke ();
 
48
                        }
 
49
 
 
50
                        if (timeout != -1) {
 
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);
 
57
                                        }
 
58
                                        if (wasAborted)
 
59
                                                throw new EvaluatorException ("Aborted.");
 
60
                                        else
 
61
                                                throw new TimeOutException ();
 
62
                                }
 
63
                        }
 
64
                        else {
 
65
                                methodCall.WaitForCompleted (System.Threading.Timeout.Infinite);
 
66
                        }
 
67
 
 
68
                        lock (operationsToCancel) {
 
69
                                operationsToCancel.Remove (methodCall);
 
70
                                ST.Monitor.PulseAll (operationsToCancel);
 
71
                                if (methodCall.Aborted) {
 
72
                                        throw new EvaluatorException ("Aborted.");
 
73
                                }
 
74
                        }
 
75
 
 
76
                        if (!string.IsNullOrEmpty (methodCall.ExceptionMessage)) {
 
77
                                throw new Exception (methodCall.ExceptionMessage);
 
78
                        }
 
79
                }
 
80
                
 
81
                public void Dispose ()
 
82
                {
 
83
                        Disposing = true;
 
84
                        lock (operationsToCancel) {
 
85
                                foreach (AsyncOperation op in operationsToCancel) {
 
86
                                        op.InternalShutdown ();
 
87
                                }
 
88
                                operationsToCancel.Clear ();
 
89
                        }
 
90
                }
 
91
 
 
92
                public void AbortAll ()
 
93
                {
 
94
                        lock (operationsToCancel) {
 
95
                                foreach (AsyncOperation op in operationsToCancel)
 
96
                                        op.InternalAbort ();
 
97
                        }
 
98
                }
 
99
                
 
100
                public void EnterBusyState (AsyncOperation oper)
 
101
                {
 
102
                        BusyStateEventArgs args = new BusyStateEventArgs ();
 
103
                        args.IsBusy = true;
 
104
                        args.Description = oper.Description;
 
105
                        if (BusyStateChanged != null)
 
106
                                BusyStateChanged (this, args);
 
107
                }
 
108
                
 
109
                public void LeaveBusyState (AsyncOperation oper)
 
110
                {
 
111
                        BusyStateEventArgs args = new BusyStateEventArgs ();
 
112
                        args.IsBusy = false;
 
113
                        args.Description = oper.Description;
 
114
                        if (BusyStateChanged != null)
 
115
                                BusyStateChanged (this, args);
 
116
                }
 
117
                
 
118
                public event EventHandler<BusyStateEventArgs> BusyStateChanged;
 
119
        }
 
120
 
 
121
        public abstract class AsyncOperation
 
122
        {
 
123
                internal bool Aborted;
 
124
                internal AsyncOperationManager Manager;
 
125
                
 
126
                public bool Aborting { get; internal set; }
 
127
                
 
128
                internal void InternalAbort ()
 
129
                {
 
130
                        ST.Monitor.Enter (this);
 
131
                        if (Aborted) {
 
132
                                ST.Monitor.Exit (this);
 
133
                                return;
 
134
                        }
 
135
                        
 
136
                        if (Aborting) {
 
137
                                // Somebody else is aborting this. Just wait for it to finish.
 
138
                                ST.Monitor.Exit (this);
 
139
                                WaitForCompleted (ST.Timeout.Infinite);
 
140
                                return;
 
141
                        }
 
142
                        
 
143
                        Aborting = true;
 
144
                        
 
145
                        int abortState = 0;
 
146
                        int abortRetryWait = 100;
 
147
                        bool abortRequested = false;
 
148
                        
 
149
                        do {
 
150
                                if (abortState > 0)
 
151
                                        ST.Monitor.Enter (this);
 
152
                                
 
153
                                try {
 
154
                                        if (!Aborted && !abortRequested) {
 
155
                                                // The Abort() call doesn't block. WaitForCompleted is used below to wait for the abort to succeed
 
156
                                                Abort ();
 
157
                                                abortRequested = true;
 
158
                                        }
 
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);
 
162
                                                break;
 
163
                                        }
 
164
                                } catch {
 
165
                                        // If abort fails, try again after a short wait
 
166
                                }
 
167
                                abortState++;
 
168
                                if (abortState == 6) {
 
169
                                        // Several abort calls have failed. Inform the user that the debugger is busy
 
170
                                        abortRetryWait = 500;
 
171
                                        try {
 
172
                                                Manager.EnterBusyState (this);
 
173
                                        } catch (Exception ex) {
 
174
                                                Console.WriteLine (ex);
 
175
                                        }
 
176
                                }
 
177
                                ST.Monitor.Exit (this);
 
178
                        } while (!Aborted && !WaitForCompleted (abortRetryWait) && !Manager.Disposing);
 
179
                        
 
180
                        if (Manager.Disposing) {
 
181
                                InternalShutdown ();
 
182
                        }
 
183
                        else {
 
184
                                lock (this) {
 
185
                                        Aborted = true;
 
186
                                        if (abortState >= 6)
 
187
                                                Manager.LeaveBusyState (this);
 
188
                                }
 
189
                        }
 
190
                }
 
191
                
 
192
                internal void InternalShutdown ()
 
193
                {
 
194
                        lock (this) {
 
195
                                if (Aborted)
 
196
                                        return;
 
197
                                try {
 
198
                                        Aborted = true;
 
199
                                        Shutdown ();
 
200
                                } catch {
 
201
                                        // Ignore
 
202
                                }
 
203
                        }
 
204
                }
 
205
                
 
206
                /// <summary>
 
207
                /// Message of the exception, if the execution failed. 
 
208
                /// </summary>
 
209
                public string ExceptionMessage { get; set; }
 
210
 
 
211
                /// <summary>
 
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. 
 
214
                /// </summary>
 
215
                public abstract string Description { get; }
 
216
                
 
217
                /// <summary>
 
218
                /// Called to invoke the operation. The execution must be asynchronous (it must return immediatelly).
 
219
                /// </summary>
 
220
                public abstract void Invoke ( );
 
221
 
 
222
                /// <summary>
 
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.
 
226
                /// </summary>
 
227
                public abstract void Abort ();
 
228
 
 
229
                /// <summary>
 
230
                /// Waits until the operation has been completed or aborted.
 
231
                /// </summary>
 
232
                public abstract bool WaitForCompleted (int timeout);
 
233
                
 
234
                /// <summary>
 
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.
 
238
                /// </summary>
 
239
                public abstract void Shutdown ();
 
240
        }
 
241
}