-
Notifications
You must be signed in to change notification settings - Fork 1
/
AsyncResult.cs
289 lines (253 loc) · 9.39 KB
/
AsyncResult.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------
namespace System.IdentityModel
{
using System;
using System.Diagnostics;
using System.Threading;
using System.Runtime;
/// <summary>
/// Base class for common AsyncResult programming scenarios.
/// </summary>
public abstract class AsyncResult : IAsyncResult, IDisposable
{
/// <summary>
/// End should be called when the End function for the asynchronous operation is complete. It
/// ensures the asynchronous operation is complete, and does some common validation.
/// </summary>
/// <param name="result">The <see cref="IAsyncResult"/> representing the status of an asynchronous operation.</param>
public static void End(IAsyncResult result)
{
if (result == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("result");
AsyncResult asyncResult = result as AsyncResult;
if (asyncResult == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.ID4001), "result"));
if (asyncResult.endCalled)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ID4002)));
asyncResult.endCalled = true;
if (!asyncResult.completed)
asyncResult.AsyncWaitHandle.WaitOne();
if (asyncResult.resetEvent != null)
((IDisposable)asyncResult.resetEvent).Dispose();
if (asyncResult.exception != null)
throw asyncResult.exception;
}
AsyncCallback callback;
bool completed;
bool completedSync;
bool disposed;
bool endCalled;
Exception exception;
ManualResetEvent resetEvent;
object state;
object thisLock;
/// <summary>
/// Constructor for async results that do not need a callback or state.
/// </summary>
protected AsyncResult()
: this(null, null)
{
}
/// <summary>
/// Constructor for async results that do not need a callback.
/// </summary>
/// <param name="state">A user-defined object that qualifies or contains information about an asynchronous operation.</param>
protected AsyncResult(object state)
: this(null, state)
{
}
/// <summary>
/// Constructor for async results that need a callback and a state.
/// </summary>
/// <param name="callback">The method to be called when the async operation completes.</param>
/// <param name="state">A user-defined object that qualifies or contains information about an asynchronous operation.</param>
protected AsyncResult(AsyncCallback callback, object state)
{
this.thisLock = new object();
this.callback = callback;
this.state = state;
}
/// <summary>
/// Finalizer for AsyncResult.
/// </summary>
~AsyncResult()
{
Dispose(false);
}
/// <summary>
/// Call this version of complete when your asynchronous operation is complete. This will update the state
/// of the operation and notify the callback.
/// </summary>
/// <param name="completedSynchronously">True if the asynchronous operation completed synchronously.</param>
protected void Complete(bool completedSynchronously)
{
Complete(completedSynchronously, null);
}
/// <summary>
/// Call this version of complete if you raise an exception during processing. In addition to notifying
/// the callback, it will capture the exception and store it to be thrown during AsyncResult.End.
/// </summary>
/// <param name="completedSynchronously">True if the asynchronous operation completed synchronously.</param>
/// <param name="exception">The exception during the processing of the asynchronous operation.</param>
protected void Complete(bool completedSynchronously, Exception exception)
{
if (completed == true)
{
// it is a bug to call complete twice
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new AsynchronousOperationException(SR.GetString(SR.ID4005)));
}
completedSync = completedSynchronously;
this.exception = exception;
if (completedSynchronously)
{
//
// No event should be set for synchronous completion
//
completed = true;
Fx.Assert(resetEvent == null, SR.GetString(SR.ID8025));
}
else
{
//
// Complete asynchronously
//
lock (thisLock)
{
completed = true;
if (resetEvent != null)
resetEvent.Set();
}
}
//
// finally call the call back. Note, we are expecting user's callback to handle the exception
// so, if the callback throw exception, all we can do is burn and crash.
//
try
{
if (callback != null)
callback(this);
}
catch (ThreadAbortException)
{
//
// The thread running the callback is being aborted. We ignore this case.
//
}
catch (AsynchronousOperationException)
{
throw;
}
#pragma warning suppress 56500
catch (Exception unhandledException)
{
//
// The callback raising an exception is equivalent to Main raising an exception w/out a catch.
// We should just throw it back. We should log the exception somewhere.
//
// Because the stack trace gets lost on a rethrow, we're wrapping it in a generic exception
// so the stack trace is preserved.
//
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new AsynchronousOperationException(SR.GetString(SR.ID4003), unhandledException));
}
}
/// <summary>
/// Disposes of unmanaged resources held by the AsyncResult.
/// </summary>
/// <param name="isExplicitDispose">True if this is an explicit call to Dispose.</param>
protected virtual void Dispose(bool isExplicitDispose)
{
if (!disposed)
{
if (isExplicitDispose)
{
lock (thisLock)
{
if (!disposed)
{
//
// Mark disposed
//
disposed = true;
//
// Called explicitly to close the object
//
if (resetEvent != null)
resetEvent.Close();
}
}
}
else
{
//
// Called for finalization
//
}
}
}
#region IAsyncResult implementation
/// <summary>
/// Gets the user-defined state information that was passed to the Begin method.
/// </summary>
public object AsyncState
{
get
{
return state;
}
}
/// <summary>
/// Gets the wait handle of the async event.
/// </summary>
public virtual WaitHandle AsyncWaitHandle
{
get
{
if (resetEvent == null)
{
bool savedCompleted = completed;
lock (thisLock)
{
if (resetEvent == null)
resetEvent = new ManualResetEvent(completed);
}
if (!savedCompleted && completed)
resetEvent.Set();
}
return resetEvent;
}
}
/// <summary>
/// Gets a value that indicates whether the asynchronous operation completed synchronously.
/// </summary>
public bool CompletedSynchronously
{
get
{
return completedSync;
}
}
/// <summary>
/// Gets a value that indicates whether the asynchronous operation has completed.
/// </summary>
public bool IsCompleted
{
get
{
return completed;
}
}
#endregion
#region IDisposable Members
/// <summary>
/// Disposes this object
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
}
}