1
- // RuntimeInvokeManager.cs
2
- //
3
- // Author:
4
- // Lluis Sanchez Gual <[email protected] >
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 System . Linq ;
31
- using System . Threading . Tasks ;
32
- using Mono . Debugging . Client ;
33
-
34
- namespace Mono . Debugging . Evaluation
35
- {
36
- public class AsyncOperationManager : IDisposable
37
- {
38
- readonly HashSet < IAsyncOperationBase > currentOperations = new HashSet < IAsyncOperationBase > ( ) ;
39
- bool disposed = false ;
40
- const int ShortCancelTimeout = 100 ;
41
-
42
- static bool IsOperationCancelledException ( Exception e , int depth = 4 )
43
- {
44
- if ( e is OperationCanceledException )
45
- return true ;
46
- var aggregateException = e as AggregateException ;
47
-
48
- if ( depth > 0 && aggregateException != null ) {
49
- foreach ( var innerException in aggregateException . InnerExceptions ) {
50
- if ( IsOperationCancelledException ( innerException , depth - 1 ) )
51
- return true ;
52
- }
53
- }
54
- return false ;
55
- }
56
-
57
- public OperationResult < TValue > Invoke < TValue > ( AsyncOperationBase < TValue > mc , int timeout )
58
- {
59
- if ( timeout <= 0 )
60
- throw new ArgumentOutOfRangeException ( "timeout" , timeout , "timeout must be greater than 0" ) ;
61
-
62
- Task < OperationResult < TValue > > task ;
63
- var description = mc . Description ;
64
- lock ( currentOperations ) {
65
- if ( disposed )
66
- throw new ObjectDisposedException ( "Already disposed" ) ;
67
- DebuggerLoggingService . LogMessage ( string . Format ( "Starting invoke for {0}" , description ) ) ;
68
- task = mc . InvokeAsync ( ) ;
69
- currentOperations . Add ( mc ) ;
70
- }
71
-
72
- bool cancelledAfterTimeout = false ;
73
- try {
74
- if ( task . Wait ( timeout ) ) {
75
- DebuggerLoggingService . LogMessage ( string . Format ( "Invoke {0} succeeded in {1} ms" , description , timeout ) ) ;
76
- return task . Result ;
77
- }
78
- DebuggerLoggingService . LogMessage ( string . Format ( "Invoke {0} timed out after {1} ms. Cancelling." , description , timeout ) ) ;
79
- mc . Abort ( ) ;
80
- try {
81
- WaitAfterCancel ( mc ) ;
82
- }
83
- catch ( Exception e ) {
84
- if ( IsOperationCancelledException ( e ) ) {
85
- DebuggerLoggingService . LogMessage ( string . Format ( "Invoke {0} was cancelled after timeout" , description ) ) ;
86
- cancelledAfterTimeout = true ;
87
- }
88
- throw ;
89
- }
90
- DebuggerLoggingService . LogMessage ( string . Format ( "{0} cancelling timed out" , description ) ) ;
91
- throw new TimeOutException ( ) ;
92
- }
93
- catch ( Exception e ) {
94
- if ( IsOperationCancelledException ( e ) ) {
95
- if ( cancelledAfterTimeout )
96
- throw new TimeOutException ( ) ;
97
- DebuggerLoggingService . LogMessage ( string . Format ( "Invoke {0} was cancelled outside before timeout" , description ) ) ;
98
- throw new EvaluatorAbortedException ( ) ;
99
- }
100
- throw ;
101
- }
102
- finally {
103
- lock ( currentOperations ) {
104
- currentOperations . Remove ( mc ) ;
105
- }
106
- }
107
- }
108
-
109
-
110
- public event EventHandler < BusyStateEventArgs > BusyStateChanged = delegate { } ;
111
-
112
- void ChangeBusyState ( bool busy , string description )
113
- {
114
- try {
115
- BusyStateChanged ( this , new BusyStateEventArgs { IsBusy = busy , Description = description } ) ;
116
- }
117
- catch ( Exception e ) {
118
- DebuggerLoggingService . LogError ( "Exception during ChangeBusyState" , e ) ;
119
- }
120
- }
121
-
122
- void WaitAfterCancel ( IAsyncOperationBase op )
123
- {
124
- var desc = op . Description ;
125
- DebuggerLoggingService . LogMessage ( string . Format ( "Waiting for cancel of invoke {0}" , desc ) ) ;
126
- if ( ! op . RawTask . Wait ( ShortCancelTimeout ) ) {
127
- try {
128
- ChangeBusyState ( true , desc ) ;
129
- while ( true ) {
130
- op . Abort ( ) ;
131
- if ( op . RawTask . Wait ( ShortCancelTimeout ) )
132
- break ;
133
- }
134
- }
135
- finally {
136
- ChangeBusyState ( false , desc ) ;
137
- }
138
- }
139
- }
140
-
141
- public void AbortAll ( )
142
- {
143
- DebuggerLoggingService . LogMessage ( "Aborting all the current invocations" ) ;
144
- List < IAsyncOperationBase > copy ;
145
- lock ( currentOperations ) {
146
- if ( disposed ) throw new ObjectDisposedException ( "Already disposed" ) ;
147
- copy = currentOperations . ToList ( ) ;
148
- currentOperations . Clear ( ) ;
149
- }
150
-
151
- CancelOperations ( copy , true ) ;
152
- }
153
-
154
- void CancelOperations ( List < IAsyncOperationBase > operations , bool wait )
155
- {
156
- foreach ( var operation in operations ) {
157
- var taskDescription = operation . Description ;
158
- try {
159
- operation . Abort ( ) ;
160
- if ( wait ) {
161
- WaitAfterCancel ( operation ) ;
162
- }
163
- }
164
- catch ( Exception e ) {
165
- if ( IsOperationCancelledException ( e ) ) {
166
- DebuggerLoggingService . LogMessage ( string . Format ( "Invocation of {0} cancelled in CancelOperations()" , taskDescription ) ) ;
167
- }
168
- else {
169
- DebuggerLoggingService . LogError ( string . Format ( "Invocation of {0} thrown an exception in CancelOperations()" , taskDescription ) , e ) ;
170
- }
171
- }
172
- }
173
- }
174
-
175
-
176
- public void Dispose ( )
177
- {
178
- List < IAsyncOperationBase > copy ;
179
- lock ( currentOperations ) {
180
- if ( disposed ) throw new ObjectDisposedException ( "Already disposed" ) ;
181
- disposed = true ;
182
- copy = currentOperations . ToList ( ) ;
183
- currentOperations . Clear ( ) ;
184
- }
185
- // don't wait on dispose
186
- CancelOperations ( copy , wait : false ) ;
187
- }
188
- }
1
+ // RuntimeInvokeManager.cs
2
+ //
3
+ // Author:
4
+ // Lluis Sanchez Gual <[email protected] >
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 System . Linq ;
31
+ using System . Threading . Tasks ;
32
+ using Mono . Debugging . Client ;
33
+
34
+ namespace Mono . Debugging . Evaluation
35
+ {
36
+ public class AsyncOperationManager : IDisposable
37
+ {
38
+ readonly HashSet < IAsyncOperationBase > currentOperations = new HashSet < IAsyncOperationBase > ( ) ;
39
+ bool disposed = false ;
40
+ const int ShortCancelTimeout = 100 ;
41
+
42
+ static bool IsOperationCancelledException ( Exception e , int depth = 4 )
43
+ {
44
+ if ( e is OperationCanceledException )
45
+ return true ;
46
+ var aggregateException = e as AggregateException ;
47
+
48
+ if ( depth > 0 && aggregateException != null ) {
49
+ foreach ( var innerException in aggregateException . InnerExceptions ) {
50
+ if ( IsOperationCancelledException ( innerException , depth - 1 ) )
51
+ return true ;
52
+ }
53
+ }
54
+ return false ;
55
+ }
56
+
57
+ public OperationResult < TValue > Invoke < TValue > ( AsyncOperationBase < TValue > mc , int timeout )
58
+ {
59
+ if ( timeout <= 0 )
60
+ throw new ArgumentOutOfRangeException ( "timeout" , timeout , "timeout must be greater than 0" ) ;
61
+
62
+ Task < OperationResult < TValue > > task ;
63
+ var description = mc . Description ;
64
+ lock ( currentOperations ) {
65
+ if ( disposed )
66
+ throw new ObjectDisposedException ( "Already disposed" ) ;
67
+ DebuggerLoggingService . LogMessage ( string . Format ( "Starting invoke for {0}" , description ) ) ;
68
+ task = mc . InvokeAsync ( ) ;
69
+ currentOperations . Add ( mc ) ;
70
+ }
71
+
72
+ bool cancelledAfterTimeout = false ;
73
+ try {
74
+ if ( task . Wait ( timeout ) ) {
75
+ DebuggerLoggingService . LogMessage ( string . Format ( "Invoke {0} succeeded in {1} ms" , description , timeout ) ) ;
76
+ return task . Result ;
77
+ }
78
+ DebuggerLoggingService . LogMessage ( string . Format ( "Invoke {0} timed out after {1} ms. Cancelling." , description , timeout ) ) ;
79
+ mc . Abort ( ) ;
80
+ try {
81
+ WaitAfterCancel ( mc ) ;
82
+ }
83
+ catch ( Exception e ) {
84
+ if ( IsOperationCancelledException ( e ) ) {
85
+ DebuggerLoggingService . LogMessage ( string . Format ( "Invoke {0} was cancelled after timeout" , description ) ) ;
86
+ cancelledAfterTimeout = true ;
87
+ }
88
+ throw ;
89
+ }
90
+ DebuggerLoggingService . LogMessage ( string . Format ( "{0} cancelling timed out" , description ) ) ;
91
+ throw new TimeOutException ( ) ;
92
+ }
93
+ catch ( Exception e ) {
94
+ if ( IsOperationCancelledException ( e ) ) {
95
+ if ( cancelledAfterTimeout )
96
+ throw new TimeOutException ( ) ;
97
+ DebuggerLoggingService . LogMessage ( string . Format ( "Invoke {0} was cancelled outside before timeout" , description ) ) ;
98
+ throw new EvaluatorAbortedException ( ) ;
99
+ }
100
+ throw ;
101
+ }
102
+ finally {
103
+ lock ( currentOperations ) {
104
+ currentOperations . Remove ( mc ) ;
105
+ }
106
+ }
107
+ }
108
+
109
+
110
+ public event EventHandler < BusyStateEventArgs > BusyStateChanged = delegate { } ;
111
+
112
+ void ChangeBusyState ( bool busy , string description )
113
+ {
114
+ try {
115
+ BusyStateChanged ( this , new BusyStateEventArgs { IsBusy = busy , Description = description } ) ;
116
+ }
117
+ catch ( Exception e ) {
118
+ DebuggerLoggingService . LogError ( "Exception during ChangeBusyState" , e ) ;
119
+ }
120
+ }
121
+
122
+ void WaitAfterCancel ( IAsyncOperationBase op )
123
+ {
124
+ var desc = op . Description ;
125
+ DebuggerLoggingService . LogMessage ( string . Format ( "Waiting for cancel of invoke {0}" , desc ) ) ;
126
+ if ( ! op . RawTask . Wait ( ShortCancelTimeout ) ) {
127
+ try {
128
+ ChangeBusyState ( true , desc ) ;
129
+ while ( true ) {
130
+ lock ( currentOperations ) {
131
+ if ( disposed )
132
+ break ;
133
+ }
134
+ op . Abort ( ) ;
135
+ if ( op . RawTask . Wait ( ShortCancelTimeout ) )
136
+ break ;
137
+ }
138
+ }
139
+ finally {
140
+ ChangeBusyState ( false , desc ) ;
141
+ }
142
+ }
143
+ }
144
+
145
+ public void AbortAll ( )
146
+ {
147
+ DebuggerLoggingService . LogMessage ( "Aborting all the current invocations" ) ;
148
+ List < IAsyncOperationBase > copy ;
149
+ lock ( currentOperations ) {
150
+ if ( disposed ) throw new ObjectDisposedException ( "Already disposed" ) ;
151
+ copy = currentOperations . ToList ( ) ;
152
+ currentOperations . Clear ( ) ;
153
+ }
154
+
155
+ CancelOperations ( copy , true ) ;
156
+ }
157
+
158
+ void CancelOperations ( List < IAsyncOperationBase > operations , bool wait )
159
+ {
160
+ foreach ( var operation in operations ) {
161
+ var taskDescription = operation . Description ;
162
+ try {
163
+ operation . Abort ( ) ;
164
+ if ( wait ) {
165
+ WaitAfterCancel ( operation ) ;
166
+ }
167
+ }
168
+ catch ( Exception e ) {
169
+ if ( IsOperationCancelledException ( e ) ) {
170
+ DebuggerLoggingService . LogMessage ( string . Format ( "Invocation of {0} cancelled in CancelOperations()" , taskDescription ) ) ;
171
+ }
172
+ else {
173
+ DebuggerLoggingService . LogError ( string . Format ( "Invocation of {0} thrown an exception in CancelOperations()" , taskDescription ) , e ) ;
174
+ }
175
+ }
176
+ }
177
+ }
178
+
179
+
180
+ public void Dispose ( )
181
+ {
182
+ List < IAsyncOperationBase > copy ;
183
+ lock ( currentOperations ) {
184
+ if ( disposed ) throw new ObjectDisposedException ( "Already disposed" ) ;
185
+ disposed = true ;
186
+ copy = currentOperations . ToList ( ) ;
187
+ currentOperations . Clear ( ) ;
188
+ }
189
+ // don't wait on dispose
190
+ CancelOperations ( copy , wait : false ) ;
191
+ }
192
+ }
189
193
}
0 commit comments