2 // TaskCompletionSource.cs
5 // Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
6 // Marek Safar <marek.safar@gmail.com>
8 // Copyright (c) 2009 Jérémie "Garuma" Laval
9 // Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
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:
18 // The above copyright notice and this permission notice shall be included in
19 // all copies or substantial portions of the Software.
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
31 using System.Collections.Generic;
33 namespace System.Threading.Tasks
35 public class TaskCompletionSource<TResult>
37 static readonly Func<TResult> emptyFunction = () => default (TResult);
38 static readonly Func<object, TResult> emptyParamFunction = (_) => default (TResult);
40 static readonly Action<Task<TResult>, TResult> setResultAction = SetResultAction;
41 static readonly Action<Task<TResult>, AggregateException> setExceptionAction = SetExceptionAction;
42 static readonly Action<Task<TResult>, object> setCanceledAction = SetCanceledAction;
44 readonly Task<TResult> source;
45 SpinLock opLock = new SpinLock (false);
47 public TaskCompletionSource ()
49 source = new Task<TResult> (emptyFunction);
50 source.SetupScheduler (TaskScheduler.Current);
53 public TaskCompletionSource (object state)
55 source = new Task<TResult> (emptyParamFunction, state);
56 source.SetupScheduler (TaskScheduler.Current);
59 public TaskCompletionSource (TaskCreationOptions creationOptions)
60 : this (null, creationOptions)
64 public TaskCompletionSource (object state, TaskCreationOptions creationOptions)
66 if ((creationOptions & System.Threading.Tasks.Task.WorkerTaskNotSupportedOptions) != 0)
67 throw new ArgumentOutOfRangeException ("creationOptions");
69 source = new Task<TResult> (emptyParamFunction, state, creationOptions);
70 source.SetupScheduler (TaskScheduler.Current);
73 public void SetCanceled ()
75 if (!TrySetCanceled ())
76 ThrowInvalidException ();
79 public void SetException (Exception exception)
81 if (exception == null)
82 throw new ArgumentNullException ("exception");
84 SetException (new Exception[] { exception });
87 public void SetException (IEnumerable<Exception> exceptions)
89 if (!TrySetException (exceptions))
90 ThrowInvalidException ();
93 public void SetResult (TResult result)
95 if (!TrySetResult (result))
96 ThrowInvalidException ();
99 static void ThrowInvalidException ()
101 throw new InvalidOperationException ("The underlying Task is already in one of the three final states: RanToCompletion, Faulted, or Canceled.");
104 public bool TrySetCanceled ()
106 return ApplyOperation (setCanceledAction, null);
109 public bool TrySetException (Exception exception)
111 if (exception == null)
112 throw new ArgumentNullException ("exception");
114 return TrySetException (new Exception[] { exception });
117 public bool TrySetException (IEnumerable<Exception> exceptions)
119 if (exceptions == null)
120 throw new ArgumentNullException ("exceptions");
122 var aggregate = new AggregateException (exceptions);
123 if (aggregate.InnerExceptions.Count == 0)
124 throw new ArgumentNullException ("exceptions");
126 return ApplyOperation (setExceptionAction, aggregate);
129 public bool TrySetResult (TResult result)
131 return ApplyOperation (setResultAction, result);
134 bool ApplyOperation<TState> (Action<Task<TResult>, TState> action, TState state)
138 opLock.Enter (ref taken);
139 if (CheckInvalidState ())
142 source.Status = TaskStatus.Running;
145 action (source, state);
156 bool CheckInvalidState ()
158 return source.Status == TaskStatus.RanToCompletion ||
159 source.Status == TaskStatus.Faulted ||
160 source.Status == TaskStatus.Canceled;
163 static void SetResultAction (Task<TResult> source, TResult result)
165 source.Result = result;
168 static void SetExceptionAction (Task<TResult> source, AggregateException aggregate)
170 source.HandleGenericException (aggregate);
173 static void SetCanceledAction (Task<TResult> source, object unused)
175 source.CancelReal ();
178 public Task<TResult> Task {