update .sln too.
[mono.git] / mcs / class / corlib / System.Threading.Tasks / TaskContinuation.cs
1 //
2 // TaskContinuation.cs
3 //
4 // Authors:
5 //    Jérémie Laval <jeremie dot laval at xamarin dot com>
6 //    Marek Safar  <marek.safar@gmail.com>
7 //
8 // Copyright 2011 Xamarin Inc (http://www.xamarin.com).
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining a copy
11 // of this software and associated documentation files (the "Software"), to deal
12 // in the Software without restriction, including without limitation the rights
13 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 // copies of the Software, and to permit persons to whom the Software is
15 // furnished to do so, subject to the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be included in
18 // all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 // THE SOFTWARE.
27 //
28 //
29
30 #if NET_4_0
31
32 using System.Collections.Generic;
33
34 namespace System.Threading.Tasks
35 {
36         interface IContinuation
37         {
38                 void Execute ();
39         }
40
41         class TaskContinuation : IContinuation
42         {
43                 readonly Task task;
44                 readonly TaskContinuationOptions continuationOptions;
45
46                 public TaskContinuation (Task task, TaskContinuationOptions continuationOptions)
47                 {
48                         this.task = task;
49                         this.continuationOptions = continuationOptions;
50                 }
51
52                 bool ContinuationStatusCheck (TaskContinuationOptions kind)
53                 {
54                         if (kind == TaskContinuationOptions.None)
55                                 return true;
56
57                         int kindCode = (int) kind;
58                         var status = task.ContinuationAncestor.Status;
59
60                         if (kindCode >= ((int) TaskContinuationOptions.NotOnRanToCompletion)) {
61                                 // Remove other options
62                                 kind &= ~(TaskContinuationOptions.PreferFairness
63                                                   | TaskContinuationOptions.LongRunning
64                                                   | TaskContinuationOptions.AttachedToParent
65                                                   | TaskContinuationOptions.ExecuteSynchronously);
66
67                                 if (status == TaskStatus.Canceled) {
68                                         if (kind == TaskContinuationOptions.NotOnCanceled)
69                                                 return false;
70                                         if (kind == TaskContinuationOptions.OnlyOnFaulted)
71                                                 return false;
72                                         if (kind == TaskContinuationOptions.OnlyOnRanToCompletion)
73                                                 return false;
74                                 } else if (status == TaskStatus.Faulted) {
75                                         if (kind == TaskContinuationOptions.NotOnFaulted)
76                                                 return false;
77                                         if (kind == TaskContinuationOptions.OnlyOnCanceled)
78                                                 return false;
79                                         if (kind == TaskContinuationOptions.OnlyOnRanToCompletion)
80                                                 return false;
81                                 } else if (status == TaskStatus.RanToCompletion) {
82                                         if (kind == TaskContinuationOptions.NotOnRanToCompletion)
83                                                 return false;
84                                         if (kind == TaskContinuationOptions.OnlyOnFaulted)
85                                                 return false;
86                                         if (kind == TaskContinuationOptions.OnlyOnCanceled)
87                                                 return false;
88                                 }
89                         }
90
91                         return true;
92                 }
93
94                 public void Execute ()
95                 {
96                         if (!ContinuationStatusCheck (continuationOptions)) {
97                                 task.CancelReal ();
98                                 task.Dispose ();
99                                 return;
100                         }
101
102                         // The task may have been canceled externally
103                         if (task.IsCompleted)
104                                 return;
105
106                         if ((continuationOptions & TaskContinuationOptions.ExecuteSynchronously) != 0)
107                                 task.RunSynchronouslyCore (task.scheduler);
108                         else
109                                 task.Schedule ();
110                 }
111         }
112
113         class ActionContinuation : IContinuation
114         {
115                 readonly Action action;
116
117                 public ActionContinuation (Action action)
118                 {
119                         this.action = action;
120                 }
121
122                 public void Execute ()
123                 {
124                         action ();
125                 }
126         }
127
128         class SynchronizationContextContinuation : IContinuation
129         {
130                 readonly Action action;
131                 readonly SynchronizationContext ctx;
132
133                 public SynchronizationContextContinuation (Action action, SynchronizationContext ctx)
134                 {
135                         this.action = action;
136                         this.ctx = ctx;
137                 }
138
139                 public void Execute ()
140                 {
141                         ctx.Post (l => ((Action) l) (), action);
142                 }
143         }
144
145         sealed class WhenAllContinuation : IContinuation
146         {
147                 readonly Task owner;
148                 readonly IList<Task> tasks;
149                 int counter;
150
151                 public WhenAllContinuation (Task owner, IList<Task> tasks)
152                 {
153                         this.owner = owner;
154                         this.counter = tasks.Count;
155                         this.tasks = tasks;
156                 }
157
158                 public void Execute ()
159                 {
160                         if (Interlocked.Decrement (ref counter) != 0)
161                                 return;
162
163                         owner.Status = TaskStatus.Running;
164
165                         bool canceled = false;
166                         List<Exception> exceptions = null;
167                         foreach (var task in tasks) {
168                                 if (task.IsFaulted) {
169                                         if (exceptions == null)
170                                                 exceptions = new List<Exception> ();
171
172                                         exceptions.AddRange (task.Exception.InnerExceptions);
173                                         continue;
174                                 }
175
176                                 if (task.IsCanceled) {
177                                         canceled = true;
178                                 }
179                         }
180
181                         if (exceptions != null) {
182                                 owner.TrySetException (new AggregateException (exceptions));
183                                 return;
184                         }
185
186                         if (canceled) {
187                                 owner.CancelReal ();
188                                 return;
189                         }
190
191                         owner.Finish ();
192                 }
193         }
194
195         sealed class WhenAllContinuation<TResult> : IContinuation
196         {
197                 readonly Task<TResult[]> owner;
198                 readonly IList<Task<TResult>> tasks;
199                 int counter;
200
201                 public WhenAllContinuation (Task<TResult[]> owner, IList<Task<TResult>> tasks)
202                 {
203                         this.owner = owner;
204                         this.counter = tasks.Count;
205                         this.tasks = tasks;
206                 }
207
208                 public void Execute ()
209                 {
210                         if (Interlocked.Decrement (ref counter) != 0)
211                                 return;
212
213                         bool canceled = false;
214                         List<Exception> exceptions = null;
215                         TResult[] results = null;
216                         for (int i = 0; i < tasks.Count; ++i) {
217                                 var task = tasks [i];
218                                 if (task.IsFaulted) {
219                                         if (exceptions == null)
220                                                 exceptions = new List<Exception> ();
221
222                                         exceptions.AddRange (task.Exception.InnerExceptions);
223                                         continue;
224                                 }
225
226                                 if (task.IsCanceled) {
227                                         canceled = true;
228                                         continue;
229                                 }
230
231                                 if (results == null) {
232                                         if (canceled || exceptions != null)
233                                                 continue;
234
235                                         results = new TResult[tasks.Count];
236                                 }
237
238                                 results[i] = task.Result;
239                         }
240
241                         if (exceptions != null) {
242                                 owner.TrySetException (new AggregateException (exceptions));
243                                 return;
244                         }
245
246                         if (canceled) {
247                                 owner.CancelReal ();
248                                 return;
249                         }
250
251                         owner.TrySetResult (results);
252                 }
253         }
254
255         sealed class WhenAnyContinuation<T> : IContinuation where T : Task
256         {
257                 readonly Task<T> owner;
258                 readonly IList<T> tasks;
259                 AtomicBooleanValue executed;
260
261                 public WhenAnyContinuation (Task<T> owner, IList<T> tasks)
262                 {
263                         this.owner = owner;
264                         this.tasks = tasks;
265                         executed = new AtomicBooleanValue ();
266                 }
267
268                 public void Execute ()
269                 {
270                         if (!executed.TryRelaxedSet ())
271                                 return;
272
273                         bool owner_notified = false;
274                         for (int i = 0; i < tasks.Count; ++i) {
275                                 var task = tasks[i];
276                                 if (!task.IsCompleted) {
277                                         task.RemoveContinuation (this);
278                                         continue;
279                                 }
280
281                                 if (owner_notified)
282                                         continue;
283
284                                 owner.TrySetResult (task);
285                                 owner_notified = true;
286                         }
287                 }
288         }
289
290         sealed class ManualResetContinuation : IContinuation, IDisposable
291         {
292                 readonly ManualResetEventSlim evt;
293
294                 public ManualResetContinuation ()
295                 {
296                         this.evt = new ManualResetEventSlim ();
297                 }
298
299                 public ManualResetEventSlim Event {
300                         get {
301                                 return evt;
302                         }
303                 }
304
305                 public void Dispose ()
306                 {
307                         evt.Dispose ();
308                 }
309
310                 public void Execute ()
311                 {
312                         evt.Set ();
313                 }
314         }
315
316         sealed class CountdownContinuation : IContinuation, IDisposable
317         {
318                 readonly CountdownEvent evt;
319
320                 public CountdownContinuation (int initialCount)
321                 {
322                         this.evt = new CountdownEvent (initialCount);
323                 }
324
325                 public CountdownEvent Event {
326                         get {
327                                 return evt;
328                         }
329                 }
330
331                 public void Dispose ()
332                 {
333                         evt.Dispose ();
334                 }
335
336                 public void Execute ()
337                 {
338                         evt.Signal ();
339                 }
340         }
341
342         sealed class DisposeContinuation : IContinuation
343         {
344                 readonly IDisposable instance;
345
346                 public DisposeContinuation (IDisposable instance)
347                 {
348                         this.instance = instance;
349                 }
350
351                 public void Execute ()
352                 {
353                         instance.Dispose ();
354                 }
355         }
356 }
357
358 #endif