Merge pull request #201 from QuickJack/master
[mono.git] / mcs / class / corlib / System.Threading.Tasks / Task.cs
1 //
2 // Task.cs
3 //
4 // Authors:
5 //    Marek Safar  <marek.safar@gmail.com>
6 //    Jérémie Laval <jeremie dot laval at xamarin dot com>
7 //
8 // Copyright (c) 2008 Jérémie "Garuma" Laval
9 // Copyright 2011 Xamarin Inc (http://www.xamarin.com).
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining a copy
12 // of this software and associated documentation files (the "Software"), to deal
13 // in the Software without restriction, including without limitation the rights
14 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 // copies of the Software, and to permit persons to whom the Software is
16 // furnished to do so, subject to the following conditions:
17 //
18 // The above copyright notice and this permission notice shall be included in
19 // all copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 // THE SOFTWARE.
28 //
29 //
30
31 #if NET_4_0 || MOBILE
32
33 using System;
34 using System.Threading;
35 using System.Collections.Concurrent;
36 using System.Collections.Generic;
37 using System.Runtime.CompilerServices;
38
39 namespace System.Threading.Tasks
40 {
41         [System.Diagnostics.DebuggerDisplay ("Id = {Id}, Status = {Status}")]
42         [System.Diagnostics.DebuggerTypeProxy (typeof (TaskDebuggerView))]
43         public class Task : IDisposable, IAsyncResult
44         {
45                 const TaskCreationOptions TaskCreationOptionsContinuation = (TaskCreationOptions) (1 << 10);
46
47                 // With this attribute each thread has its own value so that it's correct for our Schedule code
48                 // and for Parent property.
49                 [System.ThreadStatic]
50                 static Task         current;
51                 [System.ThreadStatic]
52                 static Action<Task> childWorkAdder;
53                 
54                 Task parent;
55                 
56                 static int          id = -1;
57                 static readonly TaskFactory defaultFactory = new TaskFactory ();
58
59                 CountdownEvent childTasks;
60                 
61                 int                 taskId;
62                 TaskCreationOptions taskCreationOptions;
63                 
64                 internal TaskScheduler       scheduler;
65
66                 TaskExceptionSlot exSlot;
67
68                 TaskStatus          status;
69
70                 TaskActionInvoker invoker;
71                 object         state;
72                 internal AtomicBooleanValue executing;
73
74                 TaskCompletionQueue<IContinuation> continuations;
75
76                 CancellationToken token;
77                 CancellationTokenRegistration? cancellationRegistration;
78
79                 internal const TaskCreationOptions WorkerTaskNotSupportedOptions = TaskCreationOptions.LongRunning | TaskCreationOptions.PreferFairness;
80
81                 const TaskCreationOptions MaxTaskCreationOptions =
82 #if NET_4_5
83                         TaskCreationOptions.DenyChildAttach | TaskCreationOptions.HideScheduler |
84 #endif
85                         TaskCreationOptions.PreferFairness | TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent;
86
87                 public Task (Action action)
88                         : this (action, TaskCreationOptions.None)
89                 {
90                         
91                 }
92                 
93                 public Task (Action action, TaskCreationOptions creationOptions)
94                         : this (action, CancellationToken.None, creationOptions)
95                 {
96                         
97                 }
98                 
99                 public Task (Action action, CancellationToken cancellationToken)
100                         : this (action, cancellationToken, TaskCreationOptions.None)
101                 {
102                         
103                 }
104                 
105                 public Task (Action action, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
106                         : this (TaskActionInvoker.Create (action), null, cancellationToken, creationOptions, current)
107                 {
108                         if (action == null)
109                                 throw new ArgumentNullException ("action");
110                         if (creationOptions > MaxTaskCreationOptions || creationOptions < TaskCreationOptions.None)
111                                 throw new ArgumentOutOfRangeException ("creationOptions");
112                 }
113                 
114                 public Task (Action<object> action, object state)
115                         : this (action, state, TaskCreationOptions.None)
116                 {       
117                 }
118                 
119                 public Task (Action<object> action, object state, TaskCreationOptions creationOptions)
120                         : this (action, state, CancellationToken.None, creationOptions)
121                 {
122                 }
123                 
124                 public Task (Action<object> action, object state, CancellationToken cancellationToken)
125                         : this (action, state, cancellationToken, TaskCreationOptions.None)
126                 {       
127                 }
128
129                 public Task (Action<object> action, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
130                         : this (TaskActionInvoker.Create (action), state, cancellationToken, creationOptions, current)
131                 {
132                         if (action == null)
133                                 throw new ArgumentNullException ("action");
134                         if (creationOptions > MaxTaskCreationOptions || creationOptions < TaskCreationOptions.None)
135                                 throw new ArgumentOutOfRangeException ("creationOptions");
136                 }
137
138                 internal Task (TaskActionInvoker invoker, object state, CancellationToken cancellationToken,
139                                TaskCreationOptions creationOptions, Task parent)
140                 {
141                         this.invoker = invoker;
142                         this.taskCreationOptions = creationOptions;
143                         this.state               = state;
144                         this.taskId              = Interlocked.Increment (ref id);
145                         this.status              = cancellationToken.IsCancellationRequested ? TaskStatus.Canceled : TaskStatus.Created;
146                         this.token               = cancellationToken;
147                         this.parent              = parent;
148
149                         // Process taskCreationOptions
150                         if (CheckTaskOptions (taskCreationOptions, TaskCreationOptions.AttachedToParent) && parent != null)
151                                 parent.AddChild ();
152
153                         if (token.CanBeCanceled)
154                                 cancellationRegistration = token.Register (l => ((Task) l).CancelReal (), this);
155                 }
156
157                 bool CheckTaskOptions (TaskCreationOptions opt, TaskCreationOptions member)
158                 {
159                         return (opt & member) == member;
160                 }
161
162                 #region Start
163                 public void Start ()
164                 {
165                         Start (TaskScheduler.Current);
166                 }
167                 
168                 public void Start (TaskScheduler scheduler)
169                 {
170                         if (scheduler == null)
171                                 throw new ArgumentNullException ("scheduler");
172
173                         if (status >= TaskStatus.WaitingToRun)
174                                 throw new InvalidOperationException ("The Task is not in a valid state to be started.");
175
176                         if (IsContinuation)
177                                 throw new InvalidOperationException ("Start may not be called on a continuation task");
178
179                         SetupScheduler (scheduler);
180                         Schedule ();
181                 }
182
183                 internal void SetupScheduler (TaskScheduler scheduler)
184                 {
185                         this.scheduler = scheduler;
186                         Status = TaskStatus.WaitingForActivation;
187                 }
188                 
189                 public void RunSynchronously ()
190                 {
191                         RunSynchronously (TaskScheduler.Current);
192                 }
193                 
194                 public void RunSynchronously (TaskScheduler scheduler)
195                 {
196                         if (scheduler == null)
197                                 throw new ArgumentNullException ("scheduler");
198
199                         if (Status > TaskStatus.WaitingForActivation)
200                                 throw new InvalidOperationException ("The task is not in a valid state to be started");
201
202                         SetupScheduler (scheduler);
203                         var saveStatus = status;
204                         Status = TaskStatus.WaitingToRun;
205
206                         try {
207                                 if (scheduler.RunInline (this))
208                                         return;
209                         } catch (Exception inner) {
210                                 throw new TaskSchedulerException (inner);
211                         }
212
213                         Status = saveStatus;
214                         Start (scheduler);
215                         Wait ();
216                 }
217                 #endregion
218                 
219                 #region ContinueWith
220                 public Task ContinueWith (Action<Task> continuationAction)
221                 {
222                         return ContinueWith (continuationAction, TaskContinuationOptions.None);
223                 }
224                 
225                 public Task ContinueWith (Action<Task> continuationAction, TaskContinuationOptions continuationOptions)
226                 {
227                         return ContinueWith (continuationAction, CancellationToken.None, continuationOptions, TaskScheduler.Current);
228                 }
229                 
230                 public Task ContinueWith (Action<Task> continuationAction, CancellationToken cancellationToken)
231                 {
232                         return ContinueWith (continuationAction, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
233                 }
234                 
235                 public Task ContinueWith (Action<Task> continuationAction, TaskScheduler scheduler)
236                 {
237                         return ContinueWith (continuationAction, CancellationToken.None, TaskContinuationOptions.None, scheduler);
238                 }
239                 
240                 public Task ContinueWith (Action<Task> continuationAction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
241                 {
242                         if (continuationAction == null)
243                                 throw new ArgumentNullException ("continuationAction");
244                         if (scheduler == null)
245                                 throw new ArgumentNullException ("scheduler");
246
247                         return ContinueWith (TaskActionInvoker.Create (continuationAction), cancellationToken, continuationOptions, scheduler);
248                 }
249
250                 internal Task ContinueWith (TaskActionInvoker invoker, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
251                 {
252                         var continuation = new Task (invoker, null, cancellationToken, GetCreationOptions (continuationOptions), this);
253                         ContinueWithCore (continuation, continuationOptions, scheduler);
254
255                         return continuation;
256                 }
257                 
258                 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction)
259                 {
260                         return ContinueWith<TResult> (continuationFunction, TaskContinuationOptions.None);
261                 }
262                 
263                 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, TaskContinuationOptions continuationOptions)
264                 {
265                         return ContinueWith<TResult> (continuationFunction, CancellationToken.None, continuationOptions, TaskScheduler.Current);
266                 }
267                 
268                 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, CancellationToken cancellationToken)
269                 {
270                         return ContinueWith<TResult> (continuationFunction, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
271                 }
272                 
273                 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, TaskScheduler scheduler)
274                 {
275                         return ContinueWith<TResult> (continuationFunction, CancellationToken.None, TaskContinuationOptions.None, scheduler);
276                 }
277                 
278                 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, CancellationToken cancellationToken,
279                                                             TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
280                 {
281                         if (continuationFunction == null)
282                                 throw new ArgumentNullException ("continuationFunction");
283                         if (scheduler == null)
284                                 throw new ArgumentNullException ("scheduler");
285
286                         return ContinueWith<TResult> (TaskActionInvoker.Create (continuationFunction), cancellationToken, continuationOptions, scheduler);
287                 }
288
289                 internal Task<TResult> ContinueWith<TResult> (TaskActionInvoker invoker, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
290                 {
291                         var continuation = new Task<TResult> (invoker, null, cancellationToken, GetCreationOptions (continuationOptions), this);
292                         ContinueWithCore (continuation, continuationOptions, scheduler);
293
294                         return continuation;
295                 }
296         
297                 internal void ContinueWithCore (Task continuation, TaskContinuationOptions options, TaskScheduler scheduler)
298                 {
299                         const TaskContinuationOptions wrongRan = TaskContinuationOptions.NotOnRanToCompletion | TaskContinuationOptions.OnlyOnRanToCompletion;
300                         const TaskContinuationOptions wrongCanceled = TaskContinuationOptions.NotOnCanceled | TaskContinuationOptions.OnlyOnCanceled;
301                         const TaskContinuationOptions wrongFaulted = TaskContinuationOptions.NotOnFaulted | TaskContinuationOptions.OnlyOnFaulted;
302
303                         if (((options & wrongRan) == wrongRan) || ((options & wrongCanceled) == wrongCanceled) || ((options & wrongFaulted) == wrongFaulted))
304                                 throw new ArgumentException ("continuationOptions", "Some options are mutually exclusive");
305
306                         // Already set the scheduler so that user can call Wait and that sort of stuff
307                         continuation.scheduler = scheduler;
308                         continuation.Status = TaskStatus.WaitingForActivation;
309                         continuation.taskCreationOptions |= TaskCreationOptionsContinuation;
310
311                         ContinueWith (new TaskContinuation (continuation, options));
312                 }
313                 
314                 internal void ContinueWith (IContinuation continuation)
315                 {
316                         if (IsCompleted) {
317                                 continuation.Execute ();
318                                 return;
319                         }
320                         
321                         continuations.Add (continuation);
322                         
323                         // Retry in case completion was achieved but event adding was too late
324                         if (IsCompleted && continuations.Remove (continuation))
325                                 continuation.Execute ();
326                 }
327
328                 void RemoveContinuation (IContinuation continuation)
329                 {
330                         continuations.Remove (continuation);
331                 }
332
333                 static internal TaskCreationOptions GetCreationOptions (TaskContinuationOptions kind)
334                 {
335                         TaskCreationOptions options = TaskCreationOptions.None;
336                         if ((kind & TaskContinuationOptions.AttachedToParent) > 0)
337                                 options |= TaskCreationOptions.AttachedToParent;
338                         if ((kind & TaskContinuationOptions.PreferFairness) > 0)
339                                 options |= TaskCreationOptions.PreferFairness;
340                         if ((kind & TaskContinuationOptions.LongRunning) > 0)
341                                 options |= TaskCreationOptions.LongRunning;
342                         
343                         return options;
344                 }
345                 #endregion
346                 
347                 #region Internal and protected thingies
348                 internal void Schedule ()
349                 {
350                         Status = TaskStatus.WaitingToRun;
351                         
352                         // If worker is null it means it is a local one, revert to the old behavior
353                         // If TaskScheduler.Current is not being used, the scheduler was explicitly provided, so we must use that
354                         if (scheduler != TaskScheduler.Current || childWorkAdder == null || CheckTaskOptions (taskCreationOptions, TaskCreationOptions.PreferFairness)) {
355                                 scheduler.QueueTask (this);
356                         } else {
357                                 /* Like the semantic of the ABP paper describe it, we add ourselves to the bottom 
358                                  * of our Parent Task's ThreadWorker deque. It's ok to do that since we are in
359                                  * the correct Thread during the creation
360                                  */
361                                 childWorkAdder (this);
362                         }
363                 }
364                 
365                 void ThreadStart ()
366                 {
367                         /* Allow scheduler to break fairness of deque ordering without
368                          * breaking its semantic (the task can be executed twice but the
369                          * second time it will return immediately
370                          */
371                         if (!executing.TryRelaxedSet ())
372                                 return;
373
374                         // Disable CancellationToken direct cancellation
375                         if (cancellationRegistration != null) {
376                                 cancellationRegistration.Value.Dispose ();
377                                 cancellationRegistration = null;
378                         }
379                         current = this;
380                         TaskScheduler.Current = scheduler;
381                         
382                         if (!token.IsCancellationRequested) {
383                                 
384                                 status = TaskStatus.Running;
385                                 
386                                 try {
387                                         InnerInvoke ();
388                                 } catch (OperationCanceledException oce) {
389                                         if (token != CancellationToken.None && oce.CancellationToken == token)
390                                                 CancelReal ();
391                                         else
392                                                 HandleGenericException (oce);
393                                 } catch (Exception e) {
394                                         HandleGenericException (e);
395                                 }
396                         } else {
397                                 CancelReal ();
398                         }
399                         
400                         Finish ();
401                 }
402
403                 internal bool TrySetCanceled ()
404                 {
405                         if (IsCompleted)
406                                 return false;
407                         
408                         if (!executing.TryRelaxedSet ()) {
409                                 var sw = new SpinWait ();
410                                 while (!IsCompleted)
411                                         sw.SpinOnce ();
412
413                                 return false;
414                         }
415                         
416                         CancelReal ();
417                         return true;
418                 }
419
420                 internal bool TrySetException (AggregateException aggregate)
421                 {
422                         if (IsCompleted)
423                                 return false;
424                         
425                         if (!executing.TryRelaxedSet ()) {
426                                 var sw = new SpinWait ();
427                                 while (!IsCompleted)
428                                         sw.SpinOnce ();
429
430                                 return false;
431                         }
432                         
433                         HandleGenericException (aggregate);
434                         return true;
435                 }
436 /*
437                 internal void Execute (Action<Task> childAdder)
438                 {
439                         childWorkAdder = childAdder;
440                         Execute ();
441                 }
442 */              
443                 internal void Execute ()
444                 {
445                         ThreadStart ();
446                 }
447                 
448                 internal void AddChild ()
449                 {
450                         if (childTasks == null)
451                                 Interlocked.CompareExchange (ref childTasks, new CountdownEvent (1), null);
452                         childTasks.AddCount ();
453                 }
454
455                 internal void ChildCompleted (AggregateException childEx)
456                 {
457                         if (childEx != null) {
458                                 if (ExceptionSlot.ChildExceptions == null)
459                                         Interlocked.CompareExchange (ref ExceptionSlot.ChildExceptions, new ConcurrentQueue<AggregateException> (), null);
460                                 ExceptionSlot.ChildExceptions.Enqueue (childEx);
461                         }
462
463                         if (childTasks.Signal () && status == TaskStatus.WaitingForChildrenToComplete) {
464                                 Status = TaskStatus.RanToCompletion;
465                                 ProcessChildExceptions ();
466                                 ProcessCompleteDelegates ();
467                         }
468                 }
469
470                 void InnerInvoke ()
471                 {
472                         if (IsContinuation) {
473                                 invoker.Invoke (parent, state, this);
474                         } else {
475                                 invoker.Invoke (this, state, this);
476                         }
477                 }
478                 
479                 internal void Finish ()
480                 {
481                         // If there was children created and they all finished, we set the countdown
482                         if (childTasks != null)
483                                 childTasks.Signal ();
484                         
485                         // Don't override Canceled or Faulted
486                         if (status == TaskStatus.Running) {
487                                 if (childTasks == null || childTasks.IsSet)
488                                         Status = TaskStatus.RanToCompletion;
489                                 else
490                                         Status = TaskStatus.WaitingForChildrenToComplete;
491                         }
492                 
493                         // Completions are already processed when task is canceled or faulted
494                         if (status == TaskStatus.RanToCompletion)
495                                 ProcessCompleteDelegates ();
496
497                         // Reset the current thingies
498                         current = null;
499                         TaskScheduler.Current = null;
500
501                         if (cancellationRegistration.HasValue)
502                                 cancellationRegistration.Value.Dispose ();
503                         
504                         // Tell parent that we are finished
505                         if (CheckTaskOptions (taskCreationOptions, TaskCreationOptions.AttachedToParent) && parent != null) {
506                                 parent.ChildCompleted (this.Exception);
507                         }
508                 }
509
510                 void ProcessCompleteDelegates ()
511                 {
512                         if (continuations.HasElements) {
513                                 IContinuation continuation;
514                                 while (continuations.TryGetNextCompletion (out continuation))
515                                         continuation.Execute ();
516                         }
517                 }
518
519                 void ProcessChildExceptions ()
520                 {
521                         if (exSlot == null || exSlot.ChildExceptions == null)
522                                 return;
523
524                         if (ExceptionSlot.Exception == null)
525                                 exSlot.Exception = new AggregateException ();
526
527                         AggregateException childEx;
528                         while (exSlot.ChildExceptions.TryDequeue (out childEx))
529                                 exSlot.Exception.AddChildException (childEx);
530                 }
531                 #endregion
532                 
533                 #region Cancel and Wait related method
534                 
535                 internal void CancelReal ()
536                 {
537                         Status = TaskStatus.Canceled;
538                         ProcessCompleteDelegates ();
539                 }
540
541                 void HandleGenericException (Exception e)
542                 {
543                         HandleGenericException (new AggregateException (e));
544                 }
545
546                 void HandleGenericException (AggregateException e)
547                 {
548                         ExceptionSlot.Exception = e;
549                         Thread.MemoryBarrier ();
550                         Status = TaskStatus.Faulted;
551                         ProcessCompleteDelegates ();
552                 }
553                 
554                 public void Wait ()
555                 {
556                         Wait (Timeout.Infinite, CancellationToken.None);
557                 }
558
559                 public void Wait (CancellationToken cancellationToken)
560                 {
561                         Wait (Timeout.Infinite, cancellationToken);
562                 }
563                 
564                 public bool Wait (TimeSpan timeout)
565                 {
566                         return Wait (CheckTimeout (timeout), CancellationToken.None);
567                 }
568                 
569                 public bool Wait (int millisecondsTimeout)
570                 {
571                         return Wait (millisecondsTimeout, CancellationToken.None);
572                 }
573
574                 public bool Wait (int millisecondsTimeout, CancellationToken cancellationToken)
575                 {
576                         if (millisecondsTimeout < -1)
577                                 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
578
579                         bool result = true;
580
581                         if (!IsCompleted) {
582                                 // If the task is ready to be run and we were supposed to wait on it indefinitely, just run it
583                                 if (Status == TaskStatus.WaitingToRun && millisecondsTimeout == -1 && scheduler != null)
584                                         Execute ();
585
586                                 if (!IsCompleted) {
587                                         var evt = new ManualResetEventSlim ();
588                                         var slot = new ManualEventSlot (evt);
589                                         try {
590                                                 ContinueWith (slot);
591                                                 result = evt.Wait (millisecondsTimeout, cancellationToken);
592                                         } finally {
593                                                 if (!result)
594                                                         RemoveContinuation (slot);
595                                                 evt.Dispose ();
596                                         }
597                                 }
598                         }
599
600                         if (IsCanceled)
601                                 throw new AggregateException (new TaskCanceledException (this));
602
603                         var exception = Exception;
604                         if (exception != null)
605                                 throw exception;
606
607                         return result;
608                 }
609                 
610                 public static void WaitAll (params Task[] tasks)
611                 {
612                         WaitAll (tasks, Timeout.Infinite, CancellationToken.None);
613                 }
614
615                 public static void WaitAll (Task[] tasks, CancellationToken cancellationToken)
616                 {
617                         WaitAll (tasks, Timeout.Infinite, cancellationToken);
618                 }
619                 
620                 public static bool WaitAll (Task[] tasks, TimeSpan timeout)
621                 {
622                         return WaitAll (tasks, CheckTimeout (timeout), CancellationToken.None);
623                 }
624                 
625                 public static bool WaitAll (Task[] tasks, int millisecondsTimeout)
626                 {
627                         return WaitAll (tasks, millisecondsTimeout, CancellationToken.None);
628                 }
629                 
630                 public static bool WaitAll (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
631                 {
632                         if (tasks == null)
633                                 throw new ArgumentNullException ("tasks");
634
635                         bool result = true;
636                         foreach (var t in tasks) {
637                                 if (t == null)
638                                         throw new ArgumentNullException ("tasks", "the tasks argument contains a null element");
639
640                                 result &= t.Status == TaskStatus.RanToCompletion;
641                         }
642
643                         if (!result) {
644                                 var evt = new CountdownEvent (tasks.Length);
645                                 var slot = new CountdownEventSlot (evt);
646                                 try {
647                                         foreach (var t in tasks)
648                                                 t.ContinueWith (slot);
649
650                                         result = evt.Wait (millisecondsTimeout, cancellationToken);
651                                 } finally {
652                                         List<Exception> exceptions = null;
653
654                                         foreach (var t in tasks) {
655                                                 if (result) {
656                                                         if (t.Status == TaskStatus.RanToCompletion)
657                                                                 continue;
658                                                         if (exceptions == null)
659                                                                 exceptions = new List<Exception> ();
660                                                         if (t.Exception != null)
661                                                                 exceptions.AddRange (t.Exception.InnerExceptions);
662                                                         else
663                                                                 exceptions.Add (new TaskCanceledException (t));
664                                                 } else {
665                                                         t.RemoveContinuation (slot);
666                                                 }
667                                         }
668
669                                         evt.Dispose ();
670
671                                         if (exceptions != null)
672                                                 throw new AggregateException (exceptions);
673                                 }
674                         }
675
676                         return result;
677                 }
678                 
679                 public static int WaitAny (params Task[] tasks)
680                 {
681                         return WaitAny (tasks, Timeout.Infinite, CancellationToken.None);
682                 }
683
684                 public static int WaitAny (Task[] tasks, TimeSpan timeout)
685                 {
686                         return WaitAny (tasks, CheckTimeout (timeout));
687                 }
688                 
689                 public static int WaitAny (Task[] tasks, int millisecondsTimeout)
690                 {
691                         return WaitAny (tasks, millisecondsTimeout, CancellationToken.None);
692                 }
693
694                 public static int WaitAny (Task[] tasks, CancellationToken cancellationToken)
695                 {
696                         return WaitAny (tasks, Timeout.Infinite, cancellationToken);
697                 }
698
699                 public static int WaitAny (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
700                 {
701                         if (tasks == null)
702                                 throw new ArgumentNullException ("tasks");
703                         if (millisecondsTimeout < -1)
704                                 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
705                         CheckForNullTasks (tasks);
706
707                         if (tasks.Length > 0) {
708                                 var evt = new ManualResetEventSlim ();
709                                 var slot = new ManualEventSlot (evt);
710                                 bool result = false;
711                                 try {
712                                         for (int i = 0; i < tasks.Length; i++) {
713                                                 var t = tasks[i];
714                                                 if (t.IsCompleted)
715                                                         return i;
716                                                 t.ContinueWith (slot);
717                                         }
718
719                                         if (!(result = evt.Wait (millisecondsTimeout, cancellationToken)))
720                                                 return -1;
721                                 } finally {
722                                         if (!result)
723                                                 foreach (var t in tasks)
724                                                         t.RemoveContinuation (slot);
725                                         evt.Dispose ();
726                                 }
727                         }
728
729                         int firstFinished = -1;
730                         for (int i = 0; i < tasks.Length; i++) {
731                                 var t = tasks[i];
732                                 if (t.IsCompleted) {
733                                         firstFinished = i;
734                                         break;
735                                 }
736                         }
737
738                         return firstFinished;
739                 }
740
741                 static int CheckTimeout (TimeSpan timeout)
742                 {
743                         try {
744                                 return checked ((int)timeout.TotalMilliseconds);
745                         } catch (System.OverflowException) {
746                                 throw new ArgumentOutOfRangeException ("timeout");
747                         }
748                 }
749
750                 static void CheckForNullTasks (Task[] tasks)
751                 {
752                         foreach (var t in tasks)
753                                 if (t == null)
754                                         throw new ArgumentNullException ("tasks", "the tasks argument contains a null element");
755                 }
756                 #endregion
757                 
758                 #region Dispose
759                 public void Dispose ()
760                 {
761                         Dispose (true);
762                 }
763                 
764                 protected virtual void Dispose (bool disposing)
765                 {
766                         if (!IsCompleted)
767                                 throw new InvalidOperationException ("A task may only be disposed if it is in a completion state");
768
769                         // Set action to null so that the GC can collect the delegate and thus
770                         // any big object references that the user might have captured in a anonymous method
771                         if (disposing) {
772                                 invoker = null;
773                                 state = null;
774                                 if (cancellationRegistration != null)
775                                         cancellationRegistration.Value.Dispose ();
776                         }
777                 }
778                 #endregion
779                 
780 #if NET_4_5
781
782                 public ConfiguredTaskAwaitable ConfigureAwait (bool continueOnCapturedContext)
783                 {
784                         return new ConfiguredTaskAwaitable (this, continueOnCapturedContext);
785                 }
786
787                 public Task ContinueWith (Action<Task, object> continuationAction, object state)
788                 {
789                         return ContinueWith (continuationAction, state, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current);
790                 }
791
792                 public Task ContinueWith (Action<Task, object> continuationAction, object state, CancellationToken cancellationToken)
793                 {
794                         return ContinueWith (continuationAction, state, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
795                 }
796
797                 public Task ContinueWith (Action<Task, object> continuationAction, object state, TaskContinuationOptions continuationOptions)
798                 {
799                         return ContinueWith (continuationAction, state, CancellationToken.None, continuationOptions, TaskScheduler.Current);
800                 }
801
802                 public Task ContinueWith (Action<Task, object> continuationAction, object state, TaskScheduler scheduler)
803                 {
804                         return ContinueWith (continuationAction, state, CancellationToken.None, TaskContinuationOptions.None, scheduler);
805                 }
806
807                 public Task ContinueWith (Action<Task, object> continuationAction, object state, CancellationToken cancellationToken,
808                                                                   TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
809                 {
810                         if (continuationAction == null)
811                                 throw new ArgumentNullException ("continuationAction");
812                         if (scheduler == null)
813                                 throw new ArgumentNullException ("scheduler");
814
815                         Task continuation = new Task (TaskActionInvoker.Create (continuationAction),
816                                                                                   state, cancellationToken,
817                                                                                   GetCreationOptions (continuationOptions),
818                                                                                   this);
819                         ContinueWithCore (continuation, continuationOptions, scheduler);
820
821                         return continuation;
822                 }
823
824                 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state)
825                 {
826                         return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current);
827                 }
828
829                 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, TaskContinuationOptions continuationOptions)
830                 {
831                         return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, continuationOptions, TaskScheduler.Current);
832                 }
833
834                 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, CancellationToken cancellationToken)
835                 {
836                         return ContinueWith<TResult> (continuationFunction, state, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
837                 }
838
839                 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, TaskScheduler scheduler)
840                 {
841                         return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, TaskContinuationOptions.None, scheduler);
842                 }
843
844                 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, CancellationToken cancellationToken,
845                                                                                                         TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
846                 {
847                         if (continuationFunction == null)
848                                 throw new ArgumentNullException ("continuationFunction");
849                         if (scheduler == null)
850                                 throw new ArgumentNullException ("scheduler");
851
852                         var t = new Task<TResult> (TaskActionInvoker.Create (continuationFunction),
853                                                                                                  state,
854                                                                                                  cancellationToken,
855                                                                                                  GetCreationOptions (continuationOptions),
856                                                                                                  this);
857
858                         ContinueWithCore (t, continuationOptions, scheduler);
859
860                         return t;
861                 }
862
863                 public static Task<TResult> FromResult<TResult> (TResult result)
864                 {
865                         var tcs = new TaskCompletionSource<TResult> ();
866                         tcs.SetResult (result);
867                         return tcs.Task;
868                 }
869
870                 public TaskAwaiter GetAwaiter ()
871                 {
872                         return new TaskAwaiter (this);
873                 }
874
875                 public static Task Run (Action action)
876                 {
877                         return Run (action, CancellationToken.None);
878                 }
879
880                 public static Task Run (Action action, CancellationToken cancellationToken)
881                 {
882                         if (cancellationToken.IsCancellationRequested)
883                                 return TaskConstants.Canceled;
884
885                         var t = new Task (action, cancellationToken, TaskCreationOptions.DenyChildAttach);
886                         t.Start ();
887                         return t;
888                 }
889
890                 public static Task Run (Func<Task> function)
891                 {
892                         return Run (function, CancellationToken.None);
893                 }
894
895                 public static Task Run (Func<Task> function, CancellationToken cancellationToken)
896                 {
897                         if (cancellationToken.IsCancellationRequested)
898                                 return TaskConstants.Canceled;
899
900                         var t = new Task<Task> (function, cancellationToken);
901                         t.Start ();
902                         return t;
903                 }
904
905                 public static Task<TResult> Run<TResult> (Func<TResult> function)
906                 {
907                         return Run (function, CancellationToken.None);
908                 }
909
910                 public static Task<TResult> Run<TResult> (Func<TResult> function, CancellationToken cancellationToken)
911                 {
912                         if (cancellationToken.IsCancellationRequested)
913                                 return TaskConstants<TResult>.Canceled;
914
915                         var t = new Task<TResult> (function, cancellationToken, TaskCreationOptions.DenyChildAttach);
916                         t.Start ();
917                         return t;
918                 }
919
920                 public static Task<TResult> Run<TResult> (Func<Task<TResult>> function)
921                 {
922                         return Run (function, CancellationToken.None);
923                 }
924
925                 public static Task<TResult> Run<TResult> (Func<Task<TResult>> function, CancellationToken cancellationToken)
926                 {
927                         if (cancellationToken.IsCancellationRequested)
928                                 return TaskConstants<TResult>.Canceled;
929
930                         var t = Task<Task<TResult>>.Factory.StartNew (function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
931                         return GetTaskResult (t);
932                 }
933
934                 async static Task<TResult> GetTaskResult<TResult> (Task<Task<TResult>> task)
935                 {
936                         var r = await task.ConfigureAwait (false);
937                         return r.Result;
938                 }
939                 
940                 public static YieldAwaitable Yield ()
941                 {
942                         return new YieldAwaitable ();
943                 }
944 #endif
945
946                 #region Properties
947                 public static TaskFactory Factory {
948                         get {
949                                 return defaultFactory;
950                         }
951                 }
952                 
953                 public static int? CurrentId {
954                         get {
955                                 Task t = current;
956                                 return t == null ? (int?)null : t.Id;
957                         }
958                 }
959                 
960                 public AggregateException Exception {
961                         get {
962                                 if (exSlot == null)
963                                         return null;
964                                 exSlot.Observed = true;
965                                 return exSlot.Exception;
966                         }
967                         internal set {
968                                 ExceptionSlot.Exception = value;
969                         }
970                 }
971                 
972                 public bool IsCanceled {
973                         get {
974                                 return status == TaskStatus.Canceled;
975                         }
976                 }
977
978                 public bool IsCompleted {
979                         get {
980                                 return status >= TaskStatus.RanToCompletion;
981                         }
982                 }
983                 
984                 public bool IsFaulted {
985                         get {
986                                 return status == TaskStatus.Faulted;
987                         }
988                 }
989
990                 public TaskCreationOptions CreationOptions {
991                         get {
992                                 return taskCreationOptions & MaxTaskCreationOptions;
993                         }
994                 }
995                 
996                 public TaskStatus Status {
997                         get {
998                                 return status;
999                         }
1000                         internal set {
1001                                 status = value;
1002                                 Thread.MemoryBarrier ();
1003                         }
1004                 }
1005
1006                 TaskExceptionSlot ExceptionSlot {
1007                         get {
1008                                 if (exSlot != null)
1009                                         return exSlot;
1010                                 Interlocked.CompareExchange (ref exSlot, new TaskExceptionSlot (this), null);
1011                                 return exSlot;
1012                         }
1013                 }
1014
1015                 public object AsyncState {
1016                         get {
1017                                 return state;
1018                         }
1019                 }
1020                 
1021                 bool IAsyncResult.CompletedSynchronously {
1022                         get {
1023                                 return true;
1024                         }
1025                 }
1026
1027                 WaitHandle IAsyncResult.AsyncWaitHandle {
1028                         get {
1029                                 return null;
1030                         }
1031                 }
1032                 
1033                 public int Id {
1034                         get {
1035                                 return taskId;
1036                         }
1037                 }
1038
1039                 bool IsContinuation {
1040                         get {
1041                                 return (taskCreationOptions & TaskCreationOptionsContinuation) != 0;
1042                         }
1043                 }
1044
1045                 internal Task Parent {
1046                         get {
1047                                 return parent;
1048                         }
1049                 }
1050                 
1051                 internal string DisplayActionMethod {
1052                         get {
1053                                 Delegate d = invoker.Action;
1054                                 return d == null ? "<none>" : d.Method.ToString ();
1055                         }
1056                 }
1057                 
1058                 #endregion
1059         }
1060 }
1061 #endif