xbuild: use the AdditionalReferencePath items to locate assemblies
[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-2013 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
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                 // With this attribute each thread has its own value so that it's correct for our Schedule code
46                 // and for Parent property.
47                 [System.ThreadStatic]
48                 static Task current;
49                 [System.ThreadStatic]
50                 static Action<Task> childWorkAdder;
51                 
52                 // parent is the outer task in which this task is created
53                 readonly Task parent;
54                 // contAncestor is the Task on which this continuation was setup
55                 readonly Task contAncestor;
56                 
57                 static int          id = -1;
58                 static readonly TaskFactory defaultFactory = new TaskFactory ();
59
60                 CountdownEvent childTasks;
61                 
62                 int                 taskId;
63                 TaskCreationOptions creationOptions;
64                 
65                 internal TaskScheduler       scheduler;
66
67                 TaskExceptionSlot exSlot;
68                 ManualResetEvent wait_handle;
69
70                 TaskStatus          status;
71
72                 TaskActionInvoker invoker;
73                 object         state;
74                 internal AtomicBooleanValue executing;
75
76                 TaskCompletionQueue<IContinuation> continuations;
77
78                 CancellationToken token;
79                 CancellationTokenRegistration? cancellationRegistration;
80
81                 internal const TaskCreationOptions WorkerTaskNotSupportedOptions = TaskCreationOptions.LongRunning | TaskCreationOptions.PreferFairness;
82
83                 const TaskCreationOptions MaxTaskCreationOptions =
84 #if NET_4_5
85                         TaskCreationOptions.DenyChildAttach | TaskCreationOptions.HideScheduler |
86 #endif
87                         TaskCreationOptions.PreferFairness | TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent;
88
89                 public Task (Action action)
90                         : this (action, TaskCreationOptions.None)
91                 {
92                         
93                 }
94                 
95                 public Task (Action action, TaskCreationOptions creationOptions)
96                         : this (action, CancellationToken.None, creationOptions)
97                 {
98                         
99                 }
100                 
101                 public Task (Action action, CancellationToken cancellationToken)
102                         : this (action, cancellationToken, TaskCreationOptions.None)
103                 {
104                         
105                 }
106                 
107                 public Task (Action action, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
108                         : this (TaskActionInvoker.Create (action), null, cancellationToken, creationOptions, current)
109                 {
110                         if (action == null)
111                                 throw new ArgumentNullException ("action");
112                         if (creationOptions > MaxTaskCreationOptions || creationOptions < TaskCreationOptions.None)
113                                 throw new ArgumentOutOfRangeException ("creationOptions");
114                 }
115                 
116                 public Task (Action<object> action, object state)
117                         : this (action, state, TaskCreationOptions.None)
118                 {       
119                 }
120                 
121                 public Task (Action<object> action, object state, TaskCreationOptions creationOptions)
122                         : this (action, state, CancellationToken.None, creationOptions)
123                 {
124                 }
125                 
126                 public Task (Action<object> action, object state, CancellationToken cancellationToken)
127                         : this (action, state, cancellationToken, TaskCreationOptions.None)
128                 {       
129                 }
130
131                 public Task (Action<object> action, object state, CancellationToken cancellationToken, TaskCreationOptions creationOptions)
132                         : this (TaskActionInvoker.Create (action), state, cancellationToken, creationOptions, current)
133                 {
134                         if (action == null)
135                                 throw new ArgumentNullException ("action");
136                         if (creationOptions > MaxTaskCreationOptions || creationOptions < TaskCreationOptions.None)
137                                 throw new ArgumentOutOfRangeException ("creationOptions");
138                 }
139
140                 internal Task (TaskActionInvoker invoker, object state, CancellationToken cancellationToken,
141                                TaskCreationOptions creationOptions, Task parent = null, Task contAncestor = null, bool ignoreCancellation = false)
142                 {
143                         this.invoker         = invoker;
144                         this.creationOptions = creationOptions;
145                         this.state           = state;
146                         this.taskId          = Interlocked.Increment (ref id);
147                         this.token           = cancellationToken;
148                         this.parent          = parent = parent == null ? current : parent;
149                         this.contAncestor    = contAncestor;
150                         this.status          = cancellationToken.IsCancellationRequested && !ignoreCancellation ? TaskStatus.Canceled : TaskStatus.Created;
151
152                         // Process creationOptions
153 #if NET_4_5
154                         if (parent != null && HasFlag (creationOptions, TaskCreationOptions.AttachedToParent)
155                             && !HasFlag (parent.CreationOptions, TaskCreationOptions.DenyChildAttach))
156 #else
157                         if (parent != null && HasFlag (creationOptions, TaskCreationOptions.AttachedToParent))
158 #endif
159                                 parent.AddChild ();
160
161                         if (token.CanBeCanceled && !ignoreCancellation)
162                                 cancellationRegistration = token.Register (l => ((Task) l).CancelReal (), this);
163                 }
164
165                 static bool HasFlag (TaskCreationOptions opt, TaskCreationOptions member)
166                 {
167                         return (opt & member) == member;
168                 }
169
170                 #region Start
171                 public void Start ()
172                 {
173                         Start (TaskScheduler.Current);
174                 }
175                 
176                 public void Start (TaskScheduler scheduler)
177                 {
178                         if (scheduler == null)
179                                 throw new ArgumentNullException ("scheduler");
180
181                         if (status >= TaskStatus.WaitingToRun)
182                                 throw new InvalidOperationException ("The Task is not in a valid state to be started.");
183
184                         if (IsContinuation)
185                                 throw new InvalidOperationException ("Start may not be called on a continuation task");
186
187                         SetupScheduler (scheduler);
188                         Schedule ();
189                 }
190
191                 internal void SetupScheduler (TaskScheduler scheduler)
192                 {
193                         this.scheduler = scheduler;
194                         Status = TaskStatus.WaitingForActivation;
195                 }
196                 
197                 public void RunSynchronously ()
198                 {
199                         RunSynchronously (TaskScheduler.Current);
200                 }
201                 
202                 public void RunSynchronously (TaskScheduler scheduler)
203                 {
204                         if (scheduler == null)
205                                 throw new ArgumentNullException ("scheduler");
206
207                         if (Status > TaskStatus.WaitingForActivation)
208                                 throw new InvalidOperationException ("The task is not in a valid state to be started");
209
210                         if (IsContinuation)
211                                 throw new InvalidOperationException ("RunSynchronously may not be called on a continuation task");
212
213                         RunSynchronouslyCore (scheduler);
214                 }
215
216                 internal void RunSynchronouslyCore (TaskScheduler scheduler)
217                 {
218                         SetupScheduler (scheduler);
219                         var saveStatus = status;
220                         Status = TaskStatus.WaitingToRun;
221
222                         try {
223                                 if (scheduler.RunInline (this, false))
224                                         return;
225                         } catch (Exception inner) {
226                                 throw new TaskSchedulerException (inner);
227                         }
228
229                         Status = saveStatus;
230                         Start (scheduler);
231                         Wait ();
232                 }
233                 #endregion
234                 
235                 #region ContinueWith
236                 public Task ContinueWith (Action<Task> continuationAction)
237                 {
238                         return ContinueWith (continuationAction, TaskContinuationOptions.None);
239                 }
240                 
241                 public Task ContinueWith (Action<Task> continuationAction, TaskContinuationOptions continuationOptions)
242                 {
243                         return ContinueWith (continuationAction, CancellationToken.None, continuationOptions, TaskScheduler.Current);
244                 }
245                 
246                 public Task ContinueWith (Action<Task> continuationAction, CancellationToken cancellationToken)
247                 {
248                         return ContinueWith (continuationAction, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
249                 }
250                 
251                 public Task ContinueWith (Action<Task> continuationAction, TaskScheduler scheduler)
252                 {
253                         return ContinueWith (continuationAction, CancellationToken.None, TaskContinuationOptions.None, scheduler);
254                 }
255                 
256                 public Task ContinueWith (Action<Task> continuationAction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
257                 {
258                         if (continuationAction == null)
259                                 throw new ArgumentNullException ("continuationAction");
260                         if (scheduler == null)
261                                 throw new ArgumentNullException ("scheduler");
262
263                         return ContinueWith (TaskActionInvoker.Create (continuationAction), cancellationToken, continuationOptions, scheduler);
264                 }
265
266                 internal Task ContinueWith (TaskActionInvoker invoker, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
267                 {
268                         var lazyCancellation = false;
269 #if NET_4_5
270                         lazyCancellation = (continuationOptions & TaskContinuationOptions.LazyCancellation) > 0;
271 #endif
272                         var continuation = new Task (invoker, null, cancellationToken, GetCreationOptions (continuationOptions), null, this, lazyCancellation);
273                         ContinueWithCore (continuation, continuationOptions, scheduler);
274
275                         return continuation;
276                 }
277                 
278                 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction)
279                 {
280                         return ContinueWith<TResult> (continuationFunction, TaskContinuationOptions.None);
281                 }
282                 
283                 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, TaskContinuationOptions continuationOptions)
284                 {
285                         return ContinueWith<TResult> (continuationFunction, CancellationToken.None, continuationOptions, TaskScheduler.Current);
286                 }
287                 
288                 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, CancellationToken cancellationToken)
289                 {
290                         return ContinueWith<TResult> (continuationFunction, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
291                 }
292                 
293                 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, TaskScheduler scheduler)
294                 {
295                         return ContinueWith<TResult> (continuationFunction, CancellationToken.None, TaskContinuationOptions.None, scheduler);
296                 }
297                 
298                 public Task<TResult> ContinueWith<TResult> (Func<Task, TResult> continuationFunction, CancellationToken cancellationToken,
299                                                             TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
300                 {
301                         if (continuationFunction == null)
302                                 throw new ArgumentNullException ("continuationFunction");
303                         if (scheduler == null)
304                                 throw new ArgumentNullException ("scheduler");
305
306                         return ContinueWith<TResult> (TaskActionInvoker.Create (continuationFunction), cancellationToken, continuationOptions, scheduler);
307                 }
308
309                 internal Task<TResult> ContinueWith<TResult> (TaskActionInvoker invoker, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
310                 {
311                         var lazyCancellation = false;
312 #if NET_4_5
313                         lazyCancellation = (continuationOptions & TaskContinuationOptions.LazyCancellation) > 0;
314 #endif
315                         var continuation = new Task<TResult> (invoker, null, cancellationToken, GetCreationOptions (continuationOptions), parent, this, lazyCancellation);
316                         ContinueWithCore (continuation, continuationOptions, scheduler);
317
318                         return continuation;
319                 }
320         
321                 internal void ContinueWithCore (Task continuation, TaskContinuationOptions options, TaskScheduler scheduler)
322                 {
323                         const TaskContinuationOptions wrongRan = TaskContinuationOptions.NotOnRanToCompletion | TaskContinuationOptions.OnlyOnRanToCompletion;
324                         const TaskContinuationOptions wrongCanceled = TaskContinuationOptions.NotOnCanceled | TaskContinuationOptions.OnlyOnCanceled;
325                         const TaskContinuationOptions wrongFaulted = TaskContinuationOptions.NotOnFaulted | TaskContinuationOptions.OnlyOnFaulted;
326
327                         if (((options & wrongRan) == wrongRan) || ((options & wrongCanceled) == wrongCanceled) || ((options & wrongFaulted) == wrongFaulted))
328                                 throw new ArgumentException ("continuationOptions", "Some options are mutually exclusive");
329
330                         // Already set the scheduler so that user can call Wait and that sort of stuff
331                         continuation.scheduler = scheduler;
332                         continuation.Status = TaskStatus.WaitingForActivation;
333
334                         ContinueWith (new TaskContinuation (continuation, options));
335                 }
336                 
337                 internal void ContinueWith (IContinuation continuation)
338                 {
339                         if (IsCompleted) {
340                                 continuation.Execute ();
341                                 return;
342                         }
343                         
344                         continuations.Add (continuation);
345                         
346                         // Retry in case completion was achieved but event adding was too late
347                         if (IsCompleted && continuations.Remove (continuation))
348                                 continuation.Execute ();
349                 }
350
351                 internal void RemoveContinuation (IContinuation continuation)
352                 {
353                         continuations.Remove (continuation);
354                 }
355
356                 static internal TaskCreationOptions GetCreationOptions (TaskContinuationOptions kind)
357                 {
358                         TaskCreationOptions options = TaskCreationOptions.None;
359                         if ((kind & TaskContinuationOptions.AttachedToParent) > 0)
360                                 options |= TaskCreationOptions.AttachedToParent;
361                         if ((kind & TaskContinuationOptions.PreferFairness) > 0)
362                                 options |= TaskCreationOptions.PreferFairness;
363                         if ((kind & TaskContinuationOptions.LongRunning) > 0)
364                                 options |= TaskCreationOptions.LongRunning;
365                         
366                         return options;
367                 }
368                 #endregion
369                 
370                 #region Internal and protected thingies
371                 internal void Schedule ()
372                 {
373                         Status = TaskStatus.WaitingToRun;
374                         
375                         // If worker is null it means it is a local one, revert to the old behavior
376                         // If TaskScheduler.Current is not being used, the scheduler was explicitly provided, so we must use that
377                         if (scheduler != TaskScheduler.Current || childWorkAdder == null || HasFlag (creationOptions, TaskCreationOptions.PreferFairness)) {
378                                 scheduler.QueueTask (this);
379                         } else {
380                                 /* Like the semantic of the ABP paper describe it, we add ourselves to the bottom 
381                                  * of our Parent Task's ThreadWorker deque. It's ok to do that since we are in
382                                  * the correct Thread during the creation
383                                  */
384                                 childWorkAdder (this);
385                         }
386                 }
387                 
388                 void ThreadStart ()
389                 {
390                         /* Allow scheduler to break fairness of deque ordering without
391                          * breaking its semantic (the task can be executed twice but the
392                          * second time it will return immediately
393                          */
394                         if (!executing.TryRelaxedSet ())
395                                 return;
396
397                         // Disable CancellationToken direct cancellation
398                         if (cancellationRegistration != null) {
399                                 cancellationRegistration.Value.Dispose ();
400                                 cancellationRegistration = null;
401                         }
402
403                         // If Task are ran inline on the same thread we might trash these values
404                         var saveCurrent = current;
405                         var saveScheduler = TaskScheduler.Current;
406
407                         current = this;
408 #if NET_4_5
409                         TaskScheduler.Current = HasFlag (creationOptions, TaskCreationOptions.HideScheduler) ? TaskScheduler.Default : scheduler;
410 #else
411                         TaskScheduler.Current = scheduler;
412 #endif
413                         
414                         if (!token.IsCancellationRequested) {
415                                 
416                                 status = TaskStatus.Running;
417                                 
418                                 try {
419                                         InnerInvoke ();
420                                 } catch (OperationCanceledException oce) {
421                                         if (token != CancellationToken.None && oce.CancellationToken == token)
422                                                 CancelReal ();
423                                         else
424                                                 HandleGenericException (oce);
425                                 } catch (Exception e) {
426                                         HandleGenericException (e);
427                                 }
428                         } else {
429                                 CancelReal ();
430                         }
431
432                         if (saveCurrent != null)
433                                 current = saveCurrent;
434                         if (saveScheduler != null)
435                                 TaskScheduler.Current = saveScheduler;
436                         Finish ();
437                 }
438
439                 internal bool TrySetCanceled ()
440                 {
441                         if (IsCompleted)
442                                 return false;
443                         
444                         if (!executing.TryRelaxedSet ()) {
445                                 var sw = new SpinWait ();
446                                 while (!IsCompleted)
447                                         sw.SpinOnce ();
448
449                                 return false;
450                         }
451                         
452                         CancelReal ();
453                         return true;
454                 }
455
456                 internal bool TrySetException (AggregateException aggregate)
457                 {
458                         if (IsCompleted)
459                                 return false;
460                         
461                         if (!executing.TryRelaxedSet ()) {
462                                 var sw = new SpinWait ();
463                                 while (!IsCompleted)
464                                         sw.SpinOnce ();
465
466                                 return false;
467                         }
468                         
469                         HandleGenericException (aggregate);
470                         return true;
471                 }
472
473                 internal bool TrySetExceptionObserved ()
474                 {
475                         if (exSlot != null) {
476                                 exSlot.Observed = true;
477                                 return true;
478                         }
479                         return false;
480                 }
481
482                 internal void Execute ()
483                 {
484                         ThreadStart ();
485                 }
486                 
487                 internal void AddChild ()
488                 {
489                         if (childTasks == null)
490                                 Interlocked.CompareExchange (ref childTasks, new CountdownEvent (1), null);
491                         childTasks.AddCount ();
492                 }
493
494                 internal void ChildCompleted (AggregateException childEx)
495                 {
496                         if (childEx != null) {
497                                 if (ExceptionSlot.ChildExceptions == null)
498                                         Interlocked.CompareExchange (ref ExceptionSlot.ChildExceptions, new ConcurrentQueue<AggregateException> (), null);
499                                 ExceptionSlot.ChildExceptions.Enqueue (childEx);
500                         }
501
502                         if (childTasks.Signal () && status == TaskStatus.WaitingForChildrenToComplete) {
503                                 ProcessChildExceptions ();
504                                 Status = exSlot == null ? TaskStatus.RanToCompletion : TaskStatus.Faulted;
505                                 ProcessCompleteDelegates ();
506                                 if (parent != null &&
507 #if NET_4_5
508                                     !HasFlag (parent.CreationOptions, TaskCreationOptions.DenyChildAttach) &&
509 #endif
510                                         HasFlag (creationOptions, TaskCreationOptions.AttachedToParent))
511                                         parent.ChildCompleted (this.Exception);
512                         }
513                 }
514
515                 void InnerInvoke ()
516                 {
517                         if (IsContinuation) {
518                                 invoker.Invoke (contAncestor, state, this);
519                         } else {
520                                 invoker.Invoke (this, state, this);
521                         }
522                 }
523                 
524                 internal void Finish ()
525                 {
526                         // If there was children created and they all finished, we set the countdown
527                         if (childTasks != null) {
528                                 if (childTasks.Signal ())
529                                         ProcessChildExceptions (true);
530                         }
531                         
532                         // Don't override Canceled or Faulted
533                         if (status == TaskStatus.Running) {
534                                 if (childTasks == null || childTasks.IsSet)
535                                         Status = TaskStatus.RanToCompletion;
536                                 else
537                                         Status = TaskStatus.WaitingForChildrenToComplete;
538                         }
539
540                         if (wait_handle != null)
541                                 wait_handle.Set ();
542
543                         // Tell parent that we are finished
544                         if (parent != null && HasFlag (creationOptions, TaskCreationOptions.AttachedToParent) &&
545 #if NET_4_5
546                             !HasFlag (parent.CreationOptions, TaskCreationOptions.DenyChildAttach) &&
547 #endif
548                                 status != TaskStatus.WaitingForChildrenToComplete) {
549                                 parent.ChildCompleted (this.Exception);
550                         }
551
552                         // Completions are already processed when task is canceled or faulted
553                         if (status == TaskStatus.RanToCompletion)
554                                 ProcessCompleteDelegates ();
555
556                         // Reset the current thingies
557                         if (current == this)
558                                 current = null;
559                         if (TaskScheduler.Current == scheduler)
560                                 TaskScheduler.Current = null;
561
562                         if (cancellationRegistration.HasValue)
563                                 cancellationRegistration.Value.Dispose ();
564                 }
565
566                 void ProcessCompleteDelegates ()
567                 {
568                         if (continuations.HasElements) {
569                                 IContinuation continuation;
570                                 while (continuations.TryGetNextCompletion (out continuation))
571                                         continuation.Execute ();
572                         }
573                 }
574
575                 void ProcessChildExceptions (bool isParent = false)
576                 {
577                         if (exSlot == null || exSlot.ChildExceptions == null)
578                                 return;
579
580                         if (ExceptionSlot.Exception == null)
581                                 exSlot.Exception = new AggregateException ();
582
583                         AggregateException childEx;
584                         while (exSlot.ChildExceptions.TryDequeue (out childEx))
585                                 exSlot.Exception.AddChildException (childEx);
586
587                         if (isParent) {
588                                 Status = TaskStatus.Faulted;
589                                 ProcessCompleteDelegates ();                    
590                         }
591                 }
592                 #endregion
593                 
594                 #region Cancel and Wait related method
595                 
596                 internal void CancelReal ()
597                 {
598                         Status = TaskStatus.Canceled;
599
600                         if (wait_handle != null)
601                                 wait_handle.Set ();
602
603                         ProcessCompleteDelegates ();
604                 }
605
606                 void HandleGenericException (Exception e)
607                 {
608                         HandleGenericException (new AggregateException (e));
609                 }
610
611                 void HandleGenericException (AggregateException e)
612                 {
613                         ExceptionSlot.Exception = e;
614                         Thread.MemoryBarrier ();
615                         Status = TaskStatus.Faulted;
616
617                         if (wait_handle != null)
618                                 wait_handle.Set ();
619
620                         ProcessCompleteDelegates ();
621                 }
622
623                 internal bool WaitOnChildren ()
624                 {
625                         if (Status == TaskStatus.WaitingForChildrenToComplete && childTasks != null) {
626                                 childTasks.Wait ();
627                                 return true;
628                         }
629                         return false;
630                 }
631                 
632                 public void Wait ()
633                 {
634                         Wait (Timeout.Infinite, CancellationToken.None);
635                 }
636
637                 public void Wait (CancellationToken cancellationToken)
638                 {
639                         Wait (Timeout.Infinite, cancellationToken);
640                 }
641                 
642                 public bool Wait (TimeSpan timeout)
643                 {
644                         return Wait (CheckTimeout (timeout), CancellationToken.None);
645                 }
646                 
647                 public bool Wait (int millisecondsTimeout)
648                 {
649                         return Wait (millisecondsTimeout, CancellationToken.None);
650                 }
651
652                 public bool Wait (int millisecondsTimeout, CancellationToken cancellationToken)
653                 {
654                         if (millisecondsTimeout < -1)
655                                 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
656
657                         bool result = true;
658
659                         if (!IsCompleted) {
660                                 // If the task is ready to be run and we were supposed to wait on it indefinitely without cancellation, just run it
661                                 if (Status == TaskStatus.WaitingToRun && millisecondsTimeout == Timeout.Infinite && scheduler != null && !cancellationToken.CanBeCanceled)
662                                         scheduler.RunInline (this, true);
663
664                                 if (!IsCompleted) {
665                                         var continuation = new ManualResetContinuation ();
666                                         try {
667                                                 ContinueWith (continuation);
668                                                 result = continuation.Event.Wait (millisecondsTimeout, cancellationToken);
669                                         } finally {
670                                                 if (!result)
671                                                         RemoveContinuation (continuation);
672                                                 continuation.Dispose ();
673                                         }
674                                 }
675                         }
676
677                         if (IsCanceled)
678                                 throw new AggregateException (new TaskCanceledException (this));
679
680                         var exception = Exception;
681                         if (exception != null)
682                                 throw exception;
683
684                         return result;
685                 }
686                 
687                 public static void WaitAll (params Task[] tasks)
688                 {
689                         WaitAll (tasks, Timeout.Infinite, CancellationToken.None);
690                 }
691
692                 public static void WaitAll (Task[] tasks, CancellationToken cancellationToken)
693                 {
694                         WaitAll (tasks, Timeout.Infinite, cancellationToken);
695                 }
696                 
697                 public static bool WaitAll (Task[] tasks, TimeSpan timeout)
698                 {
699                         return WaitAll (tasks, CheckTimeout (timeout), CancellationToken.None);
700                 }
701                 
702                 public static bool WaitAll (Task[] tasks, int millisecondsTimeout)
703                 {
704                         return WaitAll (tasks, millisecondsTimeout, CancellationToken.None);
705                 }
706                 
707                 public static bool WaitAll (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
708                 {
709                         if (tasks == null)
710                                 throw new ArgumentNullException ("tasks");
711
712                         bool result = true;
713                         foreach (var t in tasks) {
714                                 if (t == null)
715                                         throw new ArgumentException ("tasks", "the tasks argument contains a null element");
716
717                                 result &= t.Status == TaskStatus.RanToCompletion;
718                         }
719
720                         if (!result) {
721                                 var continuation = new CountdownContinuation (tasks.Length);
722                                 try {
723                                         foreach (var t in tasks)
724                                                 t.ContinueWith (continuation);
725
726                                         result = continuation.Event.Wait (millisecondsTimeout, cancellationToken);
727                                 } finally {
728                                         List<Exception> exceptions = null;
729
730                                         foreach (var t in tasks) {
731                                                 if (result) {
732                                                         if (t.Status == TaskStatus.RanToCompletion)
733                                                                 continue;
734                                                         if (exceptions == null)
735                                                                 exceptions = new List<Exception> ();
736                                                         if (t.Exception != null)
737                                                                 exceptions.AddRange (t.Exception.InnerExceptions);
738                                                         else
739                                                                 exceptions.Add (new TaskCanceledException (t));
740                                                 } else {
741                                                         t.RemoveContinuation (continuation);
742                                                 }
743                                         }
744
745                                         continuation.Dispose ();
746
747                                         if (exceptions != null)
748                                                 throw new AggregateException (exceptions);
749                                 }
750                         }
751
752                         return result;
753                 }
754                 
755                 public static int WaitAny (params Task[] tasks)
756                 {
757                         return WaitAny (tasks, Timeout.Infinite, CancellationToken.None);
758                 }
759
760                 public static int WaitAny (Task[] tasks, TimeSpan timeout)
761                 {
762                         return WaitAny (tasks, CheckTimeout (timeout));
763                 }
764                 
765                 public static int WaitAny (Task[] tasks, int millisecondsTimeout)
766                 {
767                         return WaitAny (tasks, millisecondsTimeout, CancellationToken.None);
768                 }
769
770                 public static int WaitAny (Task[] tasks, CancellationToken cancellationToken)
771                 {
772                         return WaitAny (tasks, Timeout.Infinite, cancellationToken);
773                 }
774
775                 public static int WaitAny (Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken)
776                 {
777                         if (tasks == null)
778                                 throw new ArgumentNullException ("tasks");
779                         if (millisecondsTimeout < -1)
780                                 throw new ArgumentOutOfRangeException ("millisecondsTimeout");
781                         CheckForNullTasks (tasks);
782
783                         if (tasks.Length > 0) {
784                                 var continuation = new ManualResetContinuation ();
785                                 bool result = false;
786                                 try {
787                                         for (int i = 0; i < tasks.Length; i++) {
788                                                 var t = tasks[i];
789                                                 if (t.IsCompleted)
790                                                         return i;
791                                                 t.ContinueWith (continuation);
792                                         }
793
794                                         if (!(result = continuation.Event.Wait (millisecondsTimeout, cancellationToken)))
795                                                 return -1;
796                                 } finally {
797                                         if (!result)
798                                                 foreach (var t in tasks)
799                                                         t.RemoveContinuation (continuation);
800                                         continuation.Dispose ();
801                                 }
802                         }
803
804                         int firstFinished = -1;
805                         for (int i = 0; i < tasks.Length; i++) {
806                                 var t = tasks[i];
807                                 if (t.IsCompleted) {
808                                         firstFinished = i;
809                                         break;
810                                 }
811                         }
812
813                         return firstFinished;
814                 }
815
816                 static int CheckTimeout (TimeSpan timeout)
817                 {
818                         try {
819                                 return checked ((int)timeout.TotalMilliseconds);
820                         } catch (System.OverflowException) {
821                                 throw new ArgumentOutOfRangeException ("timeout");
822                         }
823                 }
824
825                 static void CheckForNullTasks (Task[] tasks)
826                 {
827                         foreach (var t in tasks)
828                                 if (t == null)
829                                         throw new ArgumentException ("tasks", "the tasks argument contains a null element");
830                 }
831                 #endregion
832                 
833                 #region Dispose
834                 public void Dispose ()
835                 {
836                         Dispose (true);                 
837                 }
838                 
839                 protected virtual void Dispose (bool disposing)
840                 {
841                         if (!IsCompleted)
842                                 throw new InvalidOperationException ("A task may only be disposed if it is in a completion state");
843
844                         // Set action to null so that the GC can collect the delegate and thus
845                         // any big object references that the user might have captured in a anonymous method
846                         if (disposing) {
847                                 invoker = null;
848                                 state = null;
849                                 if (cancellationRegistration != null)
850                                         cancellationRegistration.Value.Dispose ();
851                                 if (wait_handle != null)
852                                         wait_handle.Dispose ();
853                         }
854                 }
855                 #endregion
856
857 #if NET_4_5
858                 public
859 #else
860                 internal
861 #endif
862                 Task ContinueWith (Action<Task, object> continuationAction, object state, CancellationToken cancellationToken,
863                                                                   TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
864                 {
865                         if (continuationAction == null)
866                                 throw new ArgumentNullException ("continuationAction");
867                         if (scheduler == null)
868                                 throw new ArgumentNullException ("scheduler");
869
870                         Task continuation = new Task (TaskActionInvoker.Create (continuationAction),
871                                                                                   state, cancellationToken,
872                                                                                   GetCreationOptions (continuationOptions),
873                                                       parent,
874                                                       this);
875                         ContinueWithCore (continuation, continuationOptions, scheduler);
876
877                         return continuation;
878                 }
879                 
880 #if NET_4_5
881
882                 public ConfiguredTaskAwaitable ConfigureAwait (bool continueOnCapturedContext)
883                 {
884                         return new ConfiguredTaskAwaitable (this, continueOnCapturedContext);
885                 }
886
887                 public Task ContinueWith (Action<Task, object> continuationAction, object state)
888                 {
889                         return ContinueWith (continuationAction, state, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current);
890                 }
891
892                 public Task ContinueWith (Action<Task, object> continuationAction, object state, CancellationToken cancellationToken)
893                 {
894                         return ContinueWith (continuationAction, state, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
895                 }
896
897                 public Task ContinueWith (Action<Task, object> continuationAction, object state, TaskContinuationOptions continuationOptions)
898                 {
899                         return ContinueWith (continuationAction, state, CancellationToken.None, continuationOptions, TaskScheduler.Current);
900                 }
901
902                 public Task ContinueWith (Action<Task, object> continuationAction, object state, TaskScheduler scheduler)
903                 {
904                         return ContinueWith (continuationAction, state, CancellationToken.None, TaskContinuationOptions.None, scheduler);
905                 }
906
907                 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state)
908                 {
909                         return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Current);
910                 }
911
912                 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, TaskContinuationOptions continuationOptions)
913                 {
914                         return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, continuationOptions, TaskScheduler.Current);
915                 }
916
917                 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, CancellationToken cancellationToken)
918                 {
919                         return ContinueWith<TResult> (continuationFunction, state, cancellationToken, TaskContinuationOptions.None, TaskScheduler.Current);
920                 }
921
922                 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, TaskScheduler scheduler)
923                 {
924                         return ContinueWith<TResult> (continuationFunction, state, CancellationToken.None, TaskContinuationOptions.None, scheduler);
925                 }
926
927                 public Task<TResult> ContinueWith<TResult> (Func<Task, object, TResult> continuationFunction, object state, CancellationToken cancellationToken,
928                                                                                                         TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
929                 {
930                         if (continuationFunction == null)
931                                 throw new ArgumentNullException ("continuationFunction");
932                         if (scheduler == null)
933                                 throw new ArgumentNullException ("scheduler");
934
935                         var t = new Task<TResult> (TaskActionInvoker.Create (continuationFunction),
936                                                    state,
937                                                    cancellationToken,
938                                                    GetCreationOptions (continuationOptions),
939                                                    parent,
940                                                    this);
941
942                         ContinueWithCore (t, continuationOptions, scheduler);
943
944                         return t;
945                 }
946
947                 public static Task Delay (int millisecondsDelay)
948                 {
949                         return Delay (millisecondsDelay, CancellationToken.None);
950                 }
951
952                 public static Task Delay (TimeSpan delay)
953                 {
954                         return Delay (CheckTimeout (delay), CancellationToken.None);
955                 }
956
957                 public static Task Delay (TimeSpan delay, CancellationToken cancellationToken)
958                 {
959                         return Delay (CheckTimeout (delay), cancellationToken);
960                 }
961
962                 public static Task Delay (int millisecondsDelay, CancellationToken cancellationToken)
963                 {
964                         if (millisecondsDelay < -1)
965                                 throw new ArgumentOutOfRangeException ("millisecondsDelay");
966
967                         var task = new Task (TaskActionInvoker.Delay, millisecondsDelay, cancellationToken, TaskCreationOptions.None, null, TaskConstants.Finished);
968                         task.SetupScheduler (TaskScheduler.Current);
969                         
970                         if (millisecondsDelay != Timeout.Infinite)
971                                 task.scheduler.QueueTask (task);
972
973                         return task;
974                 }
975
976                 public static Task<TResult> FromResult<TResult> (TResult result)
977                 {
978                         var tcs = new TaskCompletionSource<TResult> ();
979                         tcs.SetResult (result);
980                         return tcs.Task;
981                 }
982
983                 public TaskAwaiter GetAwaiter ()
984                 {
985                         return new TaskAwaiter (this);
986                 }
987
988                 public static Task Run (Action action)
989                 {
990                         return Run (action, CancellationToken.None);
991                 }
992
993                 public static Task Run (Action action, CancellationToken cancellationToken)
994                 {
995                         if (cancellationToken.IsCancellationRequested)
996                                 return TaskConstants.Canceled;
997
998                         return Task.Factory.StartNew (action, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
999                 }
1000
1001                 public static Task Run (Func<Task> function)
1002                 {
1003                         return Run (function, CancellationToken.None);
1004                 }
1005
1006                 public static Task Run (Func<Task> function, CancellationToken cancellationToken)
1007                 {
1008                         if (cancellationToken.IsCancellationRequested)
1009                                 return TaskConstants.Canceled;
1010
1011                         return TaskExtensionsImpl.Unwrap (Task.Factory.StartNew (function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default));
1012                 }
1013
1014                 public static Task<TResult> Run<TResult> (Func<TResult> function)
1015                 {
1016                         return Run (function, CancellationToken.None);
1017                 }
1018
1019                 public static Task<TResult> Run<TResult> (Func<TResult> function, CancellationToken cancellationToken)
1020                 {
1021                         if (cancellationToken.IsCancellationRequested)
1022                                 return TaskConstants<TResult>.Canceled;
1023
1024                         return Task.Factory.StartNew (function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
1025                 }
1026
1027                 public static Task<TResult> Run<TResult> (Func<Task<TResult>> function)
1028                 {
1029                         return Run (function, CancellationToken.None);
1030                 }
1031
1032                 public static Task<TResult> Run<TResult> (Func<Task<TResult>> function, CancellationToken cancellationToken)
1033                 {
1034                         if (cancellationToken.IsCancellationRequested)
1035                                 return TaskConstants<TResult>.Canceled;
1036
1037                         return TaskExtensionsImpl.Unwrap (Task.Factory.StartNew (function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default));
1038                 }
1039
1040                 public static Task WhenAll (params Task[] tasks)
1041                 {
1042                         if (tasks == null)
1043                                 throw new ArgumentNullException ("tasks");
1044
1045                         return WhenAllCore (tasks);
1046                 }
1047
1048                 public static Task WhenAll (IEnumerable<Task> tasks)
1049                 {
1050                         if (tasks == null)
1051                                 throw new ArgumentNullException ("tasks");
1052
1053                         // Call ToList on input enumeration or we end up
1054                         // enumerating it more than once
1055                         return WhenAllCore (new List<Task> (tasks));
1056                 }
1057
1058                 public static Task<TResult[]> WhenAll<TResult> (params Task<TResult>[] tasks)
1059                 {
1060                         if (tasks == null)
1061                                 throw new ArgumentNullException ("tasks");
1062
1063                         return WhenAllCore<TResult> (tasks);
1064                 }
1065
1066                 public static Task<TResult[]> WhenAll<TResult> (IEnumerable<Task<TResult>> tasks)
1067                 {
1068                         if (tasks == null)
1069                                 throw new ArgumentNullException ("tasks");
1070
1071                         // Call ToList on input enumeration or we end up
1072                         // enumerating it more than once
1073                         return WhenAllCore<TResult> (new List<Task<TResult>> (tasks));
1074                 }
1075
1076                 internal static Task<TResult[]> WhenAllCore<TResult> (IList<Task<TResult>> tasks)
1077                 {
1078                         foreach (var t in tasks) {
1079                                 if (t == null)
1080                                         throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1081                         }
1082
1083                         var task = new Task<TResult[]> (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1084                         task.SetupScheduler (TaskScheduler.Current);
1085
1086                         var continuation = new WhenAllContinuation<TResult> (task, tasks);
1087                         foreach (var t in tasks)
1088                                 t.ContinueWith (continuation);
1089
1090                         return task;
1091                 }
1092
1093                 public static Task<Task> WhenAny (params Task[] tasks)
1094                 {
1095                         if (tasks == null)
1096                                 throw new ArgumentNullException ("tasks");
1097
1098                         return WhenAnyCore (tasks);
1099                 }
1100
1101                 public static Task<Task> WhenAny (IEnumerable<Task> tasks)
1102                 {
1103                         if (tasks == null)
1104                                 throw new ArgumentNullException ("tasks");
1105
1106                         return WhenAnyCore (new List<Task> (tasks));
1107                 }
1108
1109                 public static Task<Task<TResult>> WhenAny<TResult> (params Task<TResult>[] tasks)
1110                 {
1111                         if (tasks == null)
1112                                 throw new ArgumentNullException ("tasks");
1113
1114                         return WhenAnyCore<TResult> (tasks);
1115                 }
1116
1117                 public static Task<Task<TResult>> WhenAny<TResult> (IEnumerable<Task<TResult>> tasks)
1118                 {
1119                         if (tasks == null)
1120                                 throw new ArgumentNullException ("tasks");
1121
1122                         return WhenAnyCore<TResult> (new List<Task<TResult>> (tasks));
1123                 }
1124
1125                 static Task<Task<TResult>> WhenAnyCore<TResult> (IList<Task<TResult>> tasks)
1126                 {
1127                         if (tasks.Count == 0)
1128                                 throw new ArgumentException ("The tasks argument contains no tasks", "tasks");
1129
1130                         int completed_index = -1;
1131                         for (int i = 0; i < tasks.Count; ++i) {
1132                                 var t = tasks[i];
1133                                 if (t == null)
1134                                         throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1135
1136                                 if (t.IsCompleted && completed_index < 0)
1137                                         completed_index = i;
1138                         }
1139
1140                         var task = new Task<Task<TResult>> (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1141
1142                         if (completed_index > 0) {
1143                                 task.TrySetResult (tasks[completed_index]);
1144                                 return task;
1145                         }
1146
1147                         task.SetupScheduler (TaskScheduler.Current);
1148
1149                         var continuation = new WhenAnyContinuation<Task<TResult>> (task, tasks);
1150                         foreach (var t in tasks)
1151                                 t.ContinueWith (continuation);
1152
1153                         return task;
1154                 }
1155
1156                 public static YieldAwaitable Yield ()
1157                 {
1158                         return new YieldAwaitable ();
1159                 }
1160 #endif
1161
1162                 internal static Task WhenAllCore (IList<Task> tasks)
1163                 {
1164                         bool all_completed = true;
1165                         foreach (var t in tasks) {
1166                                 if (t == null)
1167                                         throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1168
1169                                 all_completed &= t.Status == TaskStatus.RanToCompletion;
1170                         }
1171
1172                         if (all_completed)
1173                                 return TaskConstants.Finished;
1174
1175                         var task = new Task (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1176                         task.SetupScheduler (TaskScheduler.Current);
1177
1178                         var continuation = new WhenAllContinuation (task, tasks);
1179                         foreach (var t in tasks)
1180                                 t.ContinueWith (continuation);
1181
1182                         return task;
1183                 }
1184
1185                 internal static Task<Task> WhenAnyCore (IList<Task> tasks)
1186                 {
1187                         if (tasks.Count == 0)
1188                                 throw new ArgumentException ("The tasks argument contains no tasks", "tasks");
1189
1190                         int completed_index = -1;
1191                         for (int i = 0; i < tasks.Count; ++i) {
1192                                 var t = tasks [i];
1193                                 if (t == null)
1194                                         throw new ArgumentException ("tasks", "the tasks argument contains a null element");
1195
1196                                 if (t.IsCompleted && completed_index < 0)
1197                                         completed_index = i;
1198                         }
1199
1200                         var task = new Task<Task> (TaskActionInvoker.Empty, null, CancellationToken.None, TaskCreationOptions.None, null, TaskConstants.Finished);
1201
1202                         if (completed_index > 0) {
1203                                 task.TrySetResult (tasks[completed_index]);
1204                                 return task;
1205                         }
1206
1207                         task.SetupScheduler (TaskScheduler.Current);
1208
1209                         var continuation = new WhenAnyContinuation<Task> (task, tasks);
1210                         foreach (var t in tasks)
1211                                 t.ContinueWith (continuation);
1212
1213                         return task;
1214                 }
1215                 #region Properties
1216
1217                 internal CancellationToken CancellationToken {
1218                         get {
1219                                 return token;
1220                         }
1221                 }
1222
1223                 public static TaskFactory Factory {
1224                         get {
1225                                 return defaultFactory;
1226                         }
1227                 }
1228                 
1229                 public static int? CurrentId {
1230                         get {
1231                                 Task t = current;
1232                                 return t == null ? (int?)null : t.Id;
1233                         }
1234                 }
1235                 
1236                 public AggregateException Exception {
1237                         get {
1238                                 if (exSlot == null)
1239                                         return null;
1240                                 exSlot.Observed = true;
1241                                 return exSlot.Exception;
1242                         }
1243                 }
1244                 
1245                 public bool IsCanceled {
1246                         get {
1247                                 return status == TaskStatus.Canceled;
1248                         }
1249                 }
1250
1251                 public bool IsCompleted {
1252                         get {
1253                                 return status >= TaskStatus.RanToCompletion;
1254                         }
1255                 }
1256                 
1257                 public bool IsFaulted {
1258                         get {
1259                                 return status == TaskStatus.Faulted;
1260                         }
1261                 }
1262
1263                 public TaskCreationOptions CreationOptions {
1264                         get {
1265                                 return creationOptions & MaxTaskCreationOptions;
1266                         }
1267                 }
1268                 
1269                 public TaskStatus Status {
1270                         get {
1271                                 return status;
1272                         }
1273                         internal set {
1274                                 status = value;
1275                                 Thread.MemoryBarrier ();
1276                         }
1277                 }
1278
1279                 TaskExceptionSlot ExceptionSlot {
1280                         get {
1281                                 if (exSlot != null)
1282                                         return exSlot;
1283                                 Interlocked.CompareExchange (ref exSlot, new TaskExceptionSlot (this), null);
1284                                 return exSlot;
1285                         }
1286                 }
1287
1288                 public object AsyncState {
1289                         get {
1290                                 return state;
1291                         }
1292                 }
1293                 
1294                 bool IAsyncResult.CompletedSynchronously {
1295                         get {
1296                                 return true;
1297                         }
1298                 }
1299
1300                 WaitHandle IAsyncResult.AsyncWaitHandle {
1301                         get {
1302                                 if (invoker == null)
1303                                         throw new ObjectDisposedException (GetType ().ToString ());
1304
1305                                 if (wait_handle == null)
1306                                         Interlocked.CompareExchange (ref wait_handle, new ManualResetEvent (IsCompleted), null);
1307
1308                                 return wait_handle;
1309                         }
1310                 }
1311                 
1312                 public int Id {
1313                         get {
1314                                 return taskId;
1315                         }
1316                 }
1317
1318                 bool IsContinuation {
1319                         get {
1320                                 return contAncestor != null;
1321                         }
1322                 }
1323
1324                 internal Task ContinuationAncestor {
1325                         get {
1326                                 return contAncestor;
1327                         }
1328                 }
1329                 
1330                 internal string DisplayActionMethod {
1331                         get {
1332                                 Delegate d = invoker.Action;
1333                                 return d == null ? "<none>" : d.Method.ToString ();
1334                         }
1335                 }
1336                 
1337                 #endregion
1338         }
1339 }
1340 #endif