Merge pull request #1072 from esdrubal/bug19862
[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         delegate bool SimpleAsyncFunc (SimpleAsyncResult result);
40
41         class SimpleAsyncResult : IAsyncResult
42         {
43                 ManualResetEvent handle;
44                 bool synch;
45                 bool isCompleted;
46                 SimpleAsyncCallback cb;
47                 object state;
48                 bool callbackDone;
49                 Exception exc;
50                 object locker = new object ();
51
52                 SimpleAsyncResult (SimpleAsyncCallback cb)
53                 {
54                         this.cb = cb;
55                 }
56
57                 protected SimpleAsyncResult (AsyncCallback cb, object state)
58                 {
59                         this.state = state;
60                         this.cb = result => {
61                                 if (cb != null)
62                                         cb (this);
63                         };
64                 }
65
66                 public static void Run (SimpleAsyncFunc func, SimpleAsyncCallback callback)
67                 {
68                         var result = new SimpleAsyncResult (callback);
69                         try {
70                                 if (!func (result))
71                                         result.SetCompleted (true);
72                         } catch (Exception ex) {
73                                 result.SetCompleted (true, ex);
74                         }
75                 }
76
77                 public static void RunWithLock (object locker, SimpleAsyncFunc func, SimpleAsyncCallback callback)
78                 {
79                         Run (inner => {
80                                 bool running = func (inner);
81                                 if (running)
82                                         Monitor.Exit (locker);
83                                 return running;
84                         }, inner => {
85                                 if (inner.GotException) {
86                                         if (inner.CompletedSynchronously)
87                                                 Monitor.Exit (locker);
88                                         callback (inner);
89                                         return;
90                                 }
91
92                                 try {
93                                         if (!inner.CompletedSynchronously)
94                                                 Monitor.Enter (locker);
95
96                                         callback (inner);
97                                 } finally {
98                                         Monitor.Exit (locker);
99                                 }
100                         });
101                 }
102
103                 protected void Reset_internal ()
104                 {
105                         callbackDone = false;
106                         exc = null;
107                         lock (locker) {
108                                 isCompleted = false;
109                                 if (handle != null)
110                                         handle.Reset ();
111                         }
112                 }
113
114                 internal void SetCompleted (bool synch, Exception e)
115                 {
116                         SetCompleted_internal (synch, e);
117                         DoCallback_private ();
118                 }
119
120                 internal void SetCompleted (bool synch)
121                 {
122                         SetCompleted_internal (synch);
123                         DoCallback_private ();
124                 }
125
126                 protected void SetCompleted_internal (bool synch, Exception e)
127                 {
128                         this.synch = synch;
129                         exc = e;
130                         lock (locker) {
131                                 isCompleted = true;
132                                 if (handle != null)
133                                         handle.Set ();
134                         }
135                 }
136
137                 protected void SetCompleted_internal (bool synch)
138                 {
139                         this.synch = synch;
140                         exc = null;
141                         lock (locker) {
142                                 isCompleted = true;
143                                 if (handle != null)
144                                         handle.Set ();
145                         }
146                 }
147
148                 void DoCallback_private ()
149                 {
150                         if (callbackDone)
151                                 return;
152                         callbackDone = true;
153                         if (cb == null)
154                                 return;
155                         cb (this);
156                 }
157
158                 protected void DoCallback_internal ()
159                 {
160                         if (!callbackDone && cb != null) {
161                                 callbackDone = true;
162 //                              if (true || synch)
163                                         cb (this);
164 //                              else
165 //                                      ThreadPool.QueueUserWorkItem (CB, null);
166                         }
167                 }
168
169                 void CB (object unused)
170                 {
171                         cb (this);
172                 }
173
174                 internal void WaitUntilComplete ()
175                 {
176                         if (IsCompleted)
177                                 return;
178
179                         AsyncWaitHandle.WaitOne ();
180                 }
181
182                 internal bool WaitUntilComplete (int timeout, bool exitContext)
183                 {
184                         if (IsCompleted)
185                                 return true;
186
187                         return AsyncWaitHandle.WaitOne (timeout, exitContext);
188                 }
189
190                 public object AsyncState {
191                         get { return state; }
192                 }
193
194                 public WaitHandle AsyncWaitHandle {
195                         get {
196                                 lock (locker) {
197                                         if (handle == null)
198                                                 handle = new ManualResetEvent (isCompleted);
199                                 }
200
201                                 return handle;
202                         }
203                 }
204
205                 public bool CompletedSynchronously {
206                         get { return synch; }
207                 }
208
209                 public bool IsCompleted {
210                         get {
211                                 lock (locker) {
212                                         return isCompleted;
213                                 }
214                         }
215                 }
216
217                 internal bool GotException {
218                         get { return (exc != null); }
219                 }
220
221                 internal Exception Exception {
222                         get { return exc; }
223                 }
224         }
225 }
226