Merge pull request #2807 from akoeplinger/gchandle
[mono.git] / mcs / class / System / System.Net / SimpleAsyncResult.cs
1 //
2 // SimpleAsyncResult.cs
3 //
4 // Authors:
5 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
6 //      Martin Baulig (martin.baulig@xamarin.com)
7 //
8 // (C) 2003 Ximian, Inc (http://www.ximian.com)
9 // Copyright (c) 2014 Xamarin Inc. (http://www.xamarin.com)
10 //
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 using System.IO;
33 using System.Threading;
34
35 namespace System.Net
36 {
37         delegate void SimpleAsyncCallback (SimpleAsyncResult result);
38
39         class SimpleAsyncResult : IAsyncResult
40         {
41                 ManualResetEvent handle;
42                 bool synch;
43                 bool isCompleted;
44                 readonly SimpleAsyncCallback cb;
45                 object state;
46                 bool callbackDone;
47                 Exception exc;
48                 object locker = new object ();
49
50                 SimpleAsyncResult (SimpleAsyncCallback cb)
51                 {
52                         this.cb = cb;
53                 }
54
55                 protected SimpleAsyncResult (AsyncCallback cb, object state)
56                 {
57                         this.state = state;
58                         this.cb = result => {
59                                 if (cb != null)
60                                         cb (this);
61                         };
62                 }
63
64                 public static void Run (Func<SimpleAsyncResult, bool> func, SimpleAsyncCallback callback)
65                 {
66                         var result = new SimpleAsyncResult (callback);
67                         try {
68                                 if (!func (result))
69                                         result.SetCompleted (true);
70                         } catch (Exception ex) {
71                                 result.SetCompleted (true, ex);
72                         }
73                 }
74
75                 public static void RunWithLock (object locker, Func<SimpleAsyncResult, bool> func, SimpleAsyncCallback callback)
76                 {
77                         Run (inner => {
78                                 bool running = func (inner);
79                                 if (running)
80                                         Monitor.Exit (locker);
81                                 return running;
82                         }, inner => {
83                                 if (inner.GotException) {
84                                         if (inner.CompletedSynchronously)
85                                                 Monitor.Exit (locker);
86                                         callback (inner);
87                                         return;
88                                 }
89
90                                 try {
91                                         if (!inner.CompletedSynchronously)
92                                                 Monitor.Enter (locker);
93
94                                         callback (inner);
95                                 } finally {
96                                         Monitor.Exit (locker);
97                                 }
98                         });
99                 }
100
101                 protected void Reset_internal ()
102                 {
103                         callbackDone = false;
104                         exc = null;
105                         lock (locker) {
106                                 isCompleted = false;
107                                 if (handle != null)
108                                         handle.Reset ();
109                         }
110                 }
111
112                 internal void SetCompleted (bool synch, Exception e)
113                 {
114                         SetCompleted_internal (synch, e);
115                         DoCallback_private ();
116                 }
117
118                 internal void SetCompleted (bool synch)
119                 {
120                         SetCompleted_internal (synch);
121                         DoCallback_private ();
122                 }
123
124                 void SetCompleted_internal (bool synch, Exception e)
125                 {
126                         this.synch = synch;
127                         exc = e;
128                         lock (locker) {
129                                 isCompleted = true;
130                                 if (handle != null)
131                                         handle.Set ();
132                         }
133                 }
134
135                 protected void SetCompleted_internal (bool synch)
136                 {
137                         SetCompleted_internal (synch, null);
138                 }
139
140                 void DoCallback_private ()
141                 {
142                         if (callbackDone)
143                                 return;
144                         callbackDone = true;
145                         if (cb == null)
146                                 return;
147                         cb (this);
148                 }
149
150                 protected void DoCallback_internal ()
151                 {
152                         if (!callbackDone && cb != null) {
153                                 callbackDone = true;
154                                 cb (this);
155                         }
156                 }
157
158                 internal void WaitUntilComplete ()
159                 {
160                         if (IsCompleted)
161                                 return;
162
163                         AsyncWaitHandle.WaitOne ();
164                 }
165
166                 internal bool WaitUntilComplete (int timeout, bool exitContext)
167                 {
168                         if (IsCompleted)
169                                 return true;
170
171                         return AsyncWaitHandle.WaitOne (timeout, exitContext);
172                 }
173
174                 public object AsyncState {
175                         get { return state; }
176                 }
177
178                 public WaitHandle AsyncWaitHandle {
179                         get {
180                                 lock (locker) {
181                                         if (handle == null)
182                                                 handle = new ManualResetEvent (isCompleted);
183                                 }
184
185                                 return handle;
186                         }
187                 }
188
189                 public bool CompletedSynchronously {
190                         get { return synch; }
191                 }
192
193                 public bool IsCompleted {
194                         get {
195                                 lock (locker) {
196                                         return isCompleted;
197                                 }
198                         }
199                 }
200
201                 internal bool GotException {
202                         get { return (exc != null); }
203                 }
204
205                 internal Exception Exception {
206                         get { return exc; }
207                 }
208         }
209 }
210