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