Move files around
[mono.git] / mcs / class / corlib / System.Threading.Tasks / TaskFactory_T.cs
1 // 
2 // TaskFactory_T.cs
3 //  
4 // Authors:
5 //       Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
6 //       Marek Safar <marek.safar@gmail.com>
7 // 
8 // Copyright (c) 2009 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 #if NET_4_0 || MOBILE
30
31 using System;
32 using System.Threading;
33
34 namespace System.Threading.Tasks
35 {
36         public class TaskFactory<TResult>
37         {
38                 readonly TaskScheduler scheduler;
39                 TaskCreationOptions creationOptions;
40                 TaskContinuationOptions continuationOptions;
41                 CancellationToken cancellationToken;
42                 
43                 TaskFactory parent;
44
45                 public TaskFactory ()
46                         : this (CancellationToken.None)
47                 {       
48                 }
49                 
50                 public TaskFactory (TaskScheduler scheduler)
51                         : this (CancellationToken.None, TaskCreationOptions.None, TaskContinuationOptions.None, scheduler)
52                 {       
53                 }
54                 
55                 public TaskFactory (CancellationToken cancellationToken)
56                         : this (cancellationToken, TaskCreationOptions.None, TaskContinuationOptions.None, null)
57                 {       
58                 }
59                 
60                 public TaskFactory (TaskCreationOptions creationOptions, TaskContinuationOptions continuationOptions)
61                         : this (CancellationToken.None, creationOptions, continuationOptions, null)
62                 {       
63                 }
64                 
65                 public TaskFactory (CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
66                 {
67                         this.cancellationToken = cancellationToken;
68                         this.scheduler = scheduler;
69                         this.creationOptions = creationOptions;
70                         this.continuationOptions = continuationOptions;
71
72                         TaskFactory.CheckContinuationOptions (continuationOptions);
73                         
74                         this.parent = new TaskFactory (cancellationToken, creationOptions, continuationOptions, scheduler);
75                 }
76
77                 public TaskScheduler Scheduler {
78                         get {
79                                 return scheduler;
80                         }
81                 }
82                 
83                 public TaskContinuationOptions ContinuationOptions {
84                         get {
85                                 return continuationOptions;
86                         }
87                 }
88                 
89                 public TaskCreationOptions CreationOptions {
90                         get {
91                                 return creationOptions;
92                         }
93                 }
94                 
95                 public CancellationToken CancellationToken {
96                         get {
97                                 return cancellationToken;
98                         }
99                 }
100                 
101                 #region StartNew for Task<TResult>      
102                 public Task<TResult> StartNew (Func<TResult> function)
103                 {
104                         return StartNew (function, cancellationToken, creationOptions, GetScheduler ());
105                 }
106                 
107                 public Task<TResult> StartNew (Func<TResult> function, TaskCreationOptions creationOptions)
108                 {
109                         return StartNew (function, cancellationToken, creationOptions, GetScheduler ());
110                 }
111                 
112                 public Task<TResult> StartNew (Func<TResult> function, CancellationToken cancellationToken)
113                 {
114                         return StartNew (function, cancellationToken, creationOptions, GetScheduler ());
115                 }
116                 
117                 public Task<TResult> StartNew (Func<TResult> function, 
118                                                CancellationToken cancellationToken,
119                                                TaskCreationOptions creationOptions,
120                                                TaskScheduler scheduler)
121                 {
122                         return StartNew ((o) => function (), null, cancellationToken, creationOptions, scheduler);
123                 }
124                 
125                 public Task<TResult> StartNew (Func<object, TResult> function, object state)
126                 {
127                         return StartNew (function, state, cancellationToken, creationOptions, GetScheduler ());
128                 }
129                 
130                 public Task<TResult> StartNew (Func<object, TResult> function, object state, TaskCreationOptions creationOptions)
131                 {
132                         return StartNew (function, state, cancellationToken, creationOptions, GetScheduler ());
133                 }
134                 
135                 public Task<TResult> StartNew (Func<object, TResult> function, object state, CancellationToken cancellationToken)
136                 {
137                         return StartNew (function, state, cancellationToken, creationOptions, GetScheduler ());
138                 }
139                 
140                 public Task<TResult> StartNew (Func<object, TResult> function, object state, 
141                                                CancellationToken cancellationToken,
142                                                TaskCreationOptions creationOptions,
143                                                TaskScheduler scheduler)
144                 {
145                         return parent.StartNew<TResult> (function, state, cancellationToken, creationOptions, scheduler);
146                 }
147                 #endregion
148                 
149                 #region Continue
150
151                 public Task<TResult> ContinueWhenAny (Task[] tasks,
152                                                       Func<Task, TResult> continuationFunction)
153                 {
154                         return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
155                 }
156
157                 public Task<TResult> ContinueWhenAny (Task[] tasks,
158                                                       Func<Task, TResult> continuationFunction,
159                                                       CancellationToken cancellationToken)
160                 {
161                         return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
162                 }
163
164                 public Task<TResult> ContinueWhenAny (Task[] tasks,
165                                                       Func<Task, TResult> continuationFunction,
166                                                       TaskContinuationOptions continuationOptions)
167                 {
168                         return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
169                 }
170
171                 public Task<TResult> ContinueWhenAny (Task[] tasks,
172                                                       Func<Task, TResult> continuationFunction,
173                                                       CancellationToken cancellationToken,
174                                                       TaskContinuationOptions continuationOptions,
175                                                       TaskScheduler scheduler)
176                 {
177                         return parent.ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, scheduler);
178                 }
179
180                 public Task<TResult> ContinueWhenAny<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
181                                                                          Func<Task<TAntecedentResult>, TResult> continuationFunction)
182                 {
183                         return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
184                 }
185
186                 public Task<TResult> ContinueWhenAny<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
187                                                                          Func<Task<TAntecedentResult>, TResult> continuationFunction,
188                                                                          CancellationToken cancellationToken)
189                 {
190                         return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
191                 }
192
193                 public Task<TResult> ContinueWhenAny<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
194                                                                          Func<Task<TAntecedentResult>, TResult> continuationFunction,
195                                                                          TaskContinuationOptions continuationOptions)
196                 {
197                         return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
198                 }
199
200                 public Task<TResult> ContinueWhenAny<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
201                                                                          Func<Task<TAntecedentResult>, TResult> continuationFunction,
202                                                                          CancellationToken cancellationToken,
203                                                                          TaskContinuationOptions continuationOptions,
204                                                                          TaskScheduler scheduler)
205                 {
206                         return parent.ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, scheduler);
207                 }
208                 
209                 public Task<TResult> ContinueWhenAll (Task[] tasks, Func<Task[], TResult> continuationFunction)
210                 {
211                         return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
212                 }
213                 
214                 public Task<TResult> ContinueWhenAll (Task[] tasks,
215                                                       Func<Task[], TResult> continuationFunction,
216                                                       TaskContinuationOptions continuationOptions)
217                 {
218                         return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
219                 }
220                 
221                 public Task<TResult> ContinueWhenAll (Task[] tasks,
222                                                       Func<Task[], TResult> continuationFunction,
223                                                       CancellationToken cancellationToken)
224                 {
225                         return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
226                 }
227                 
228                 public Task<TResult> ContinueWhenAll (Task[] tasks,
229                                                       Func<Task[], TResult> continuationFunction,
230                                                       CancellationToken cancellationToken,
231                                                       TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
232                 {
233                         return parent.ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, scheduler);
234                 }
235                 
236                 public Task<TResult> ContinueWhenAll<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
237                                                                          Func<Task<TAntecedentResult>[], TResult> continuationFunction)
238                 {
239                         return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
240                 }
241                 
242                 public Task<TResult> ContinueWhenAll<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
243                                                                          Func<Task<TAntecedentResult>[], TResult> continuationFunction,
244                                                                          TaskContinuationOptions continuationOptions)
245                 {
246                         return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
247                 }
248                 
249                 public Task<TResult> ContinueWhenAll<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
250                                                                          Func<Task<TAntecedentResult>[], TResult> continuationFunction,
251                                                                          CancellationToken cancellationToken)
252                 {
253                         return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
254                 }
255                 
256                 public Task<TResult> ContinueWhenAll<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
257                                                                          Func<Task<TAntecedentResult>[], TResult> continuationFunction,
258                                                                          CancellationToken cancellationToken,
259                                                                          TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
260                 {
261                         return parent.ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, scheduler);
262                 }
263
264                 #endregion
265                 
266                 #region FromAsync
267                 
268                 public Task<TResult> FromAsync (IAsyncResult asyncResult, Func<IAsyncResult, TResult> endMethod)
269                 {
270                         return FromAsync (asyncResult, endMethod, creationOptions);
271                 }
272                 
273                 public Task<TResult> FromAsync (IAsyncResult asyncResult, Func<IAsyncResult, TResult> endMethod, TaskCreationOptions creationOptions)
274                 {
275                         return FromAsync (asyncResult, endMethod, creationOptions, GetScheduler ());
276                 }
277                 
278                 public Task<TResult> FromAsync (IAsyncResult asyncResult, Func<IAsyncResult, TResult> endMethod, TaskCreationOptions creationOptions, TaskScheduler scheduler)
279                 {
280                         return FromIAsyncResult (asyncResult, endMethod, creationOptions, scheduler);
281                 }
282
283                 internal static Task<TResult> FromIAsyncResult (IAsyncResult asyncResult, Func<IAsyncResult, TResult> endMethod, TaskCreationOptions creationOptions, TaskScheduler scheduler)
284                 {
285                         if (asyncResult == null)
286                             throw new ArgumentNullException ("asyncResult");
287
288                         if (endMethod == null)
289                             throw new ArgumentNullException ("endMethod");
290
291                         if (scheduler == null)
292                                 throw new ArgumentNullException ("scheduler");
293
294                         if ((creationOptions & Task.WorkerTaskNotSupportedOptions) != 0)
295                                 throw new ArgumentOutOfRangeException ("creationOptions");
296
297                         var source = new CancellationTokenSource ();
298                         var task = new Task<TResult> (l => {
299                                 try {
300                                         return endMethod (asyncResult);
301                                 } catch (OperationCanceledException) {
302                                         source.Cancel ();
303                                         source.Token.ThrowIfCancellationRequested ();
304                                 }
305                                 return default (TResult);
306                         }, null, source.Token, creationOptions);
307
308                         // Take quick path for completed operations
309                         if (asyncResult.IsCompleted) {
310                                 task.RunSynchronously (scheduler);
311                         } else {
312                                 ThreadPool.RegisterWaitForSingleObject (asyncResult.AsyncWaitHandle,
313                                                                         (s, t) => task.RunSynchronously (scheduler),
314                                                                         null, Timeout.Infinite, true);
315                         }
316
317                         return task;
318                 }
319
320                 public Task<TResult> FromAsync (Func<AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
321                                                 object state)
322                 {
323                         return FromAsync (beginMethod, endMethod, state, creationOptions);
324                 }
325
326                 public Task<TResult> FromAsync (Func<AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
327                                                 object state, TaskCreationOptions creationOptions)
328                 {
329                         return FromAsyncBeginEnd (beginMethod, endMethod, state, creationOptions);
330                 }
331
332                 internal static Task<TResult> FromAsyncBeginEnd (Func<AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
333                                                                  object state, TaskCreationOptions creationOptions)
334                 {
335                         if (beginMethod == null)
336                                 throw new ArgumentNullException ("beginMethod");
337
338                         if (endMethod == null)
339                                 throw new ArgumentNullException ("endMethod");
340
341                         if ((creationOptions & Task.WorkerTaskNotSupportedOptions) != 0)
342                                 throw new ArgumentOutOfRangeException ("creationOptions");
343
344                         var tcs = new TaskCompletionSource<TResult> (state, creationOptions);
345                         beginMethod (l => InnerInvoke (tcs, endMethod, l), state);
346
347                         return tcs.Task;
348                 }
349
350                 public Task<TResult> FromAsync<TArg1> (Func<TArg1, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
351                                                        TArg1 arg1, object state)
352                 {
353                         return FromAsync (beginMethod, endMethod, arg1, state, creationOptions);
354                 }
355
356                 public Task<TResult> FromAsync<TArg1> (Func<TArg1, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
357                                                        TArg1 arg1, object state, TaskCreationOptions creationOptions)
358                 {
359                         return FromAsyncBeginEnd (beginMethod, endMethod, arg1, state, creationOptions);
360                 }
361
362                 internal static Task<TResult> FromAsyncBeginEnd<TArg1> (Func<TArg1, AsyncCallback, object, IAsyncResult> beginMethod,
363                                                                         Func<IAsyncResult, TResult> endMethod,
364                                                                         TArg1 arg1, object state, TaskCreationOptions creationOptions)
365                 {
366                         if (beginMethod == null)
367                                 throw new ArgumentNullException ("beginMethod");
368
369                         if (endMethod == null)
370                                 throw new ArgumentNullException ("endMethod");
371
372                         if ((creationOptions & Task.WorkerTaskNotSupportedOptions) != 0)
373                                 throw new ArgumentOutOfRangeException ("creationOptions");
374
375                         var tcs = new TaskCompletionSource<TResult> (state, creationOptions);
376                         beginMethod (arg1, l => InnerInvoke (tcs, endMethod, l), state);
377
378                         return tcs.Task;
379                 }
380
381                 public Task<TResult> FromAsync<TArg1, TArg2> (Func<TArg1, TArg2, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
382                                                               TArg1 arg1, TArg2 arg2, object state)
383                 {
384                         return FromAsync (beginMethod, endMethod, arg1, arg2, state, creationOptions);
385                 }
386
387                 public Task<TResult> FromAsync<TArg1, TArg2> (Func<TArg1, TArg2, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
388                                                               TArg1 arg1, TArg2 arg2, object state, TaskCreationOptions creationOptions)
389                 {
390                         return FromAsyncBeginEnd (beginMethod, endMethod, arg1, arg2, state, creationOptions);
391                 }
392
393                 internal static Task<TResult> FromAsyncBeginEnd<TArg1, TArg2> (Func<TArg1, TArg2, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
394                                                                                   TArg1 arg1, TArg2 arg2, object state, TaskCreationOptions creationOptions)
395                 {
396                         if (beginMethod == null)
397                                 throw new ArgumentNullException ("beginMethod");
398
399                         if (endMethod == null)
400                                 throw new ArgumentNullException ("endMethod");
401
402                         if ((creationOptions & Task.WorkerTaskNotSupportedOptions) != 0)
403                                 throw new ArgumentOutOfRangeException ("creationOptions");
404
405                         var tcs = new TaskCompletionSource<TResult> (state, creationOptions);
406                         beginMethod (arg1, arg2, l => InnerInvoke (tcs, endMethod, l), state);
407
408                         return tcs.Task;
409                 }
410
411                 public Task<TResult> FromAsync<TArg1, TArg2, TArg3> (Func<TArg1, TArg2, TArg3, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
412                                                                      TArg1 arg1, TArg2 arg2, TArg3 arg3, object state)
413                 {
414                         return FromAsync (beginMethod, endMethod, arg1, arg2, arg3, state, creationOptions);
415                 }
416
417                 public Task<TResult> FromAsync<TArg1, TArg2, TArg3> (Func<TArg1, TArg2, TArg3, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
418                                                                      TArg1 arg1, TArg2 arg2, TArg3 arg3, object state,
419                                                                      TaskCreationOptions creationOptions)
420                 {
421                         return FromAsyncBeginEnd (beginMethod, endMethod, arg1, arg2, arg3, state, creationOptions);
422                 }
423
424                 internal static Task<TResult> FromAsyncBeginEnd<TArg1, TArg2, TArg3> (Func<TArg1, TArg2, TArg3, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
425                                                                                   TArg1 arg1, TArg2 arg2, TArg3 arg3, object state, TaskCreationOptions creationOptions)
426                 {
427                         if (beginMethod == null)
428                                 throw new ArgumentNullException ("beginMethod");
429
430                         if (endMethod == null)
431                                 throw new ArgumentNullException ("endMethod");
432
433                         if ((creationOptions & Task.WorkerTaskNotSupportedOptions) != 0)
434                                 throw new ArgumentOutOfRangeException ("creationOptions");
435
436                         var tcs = new TaskCompletionSource<TResult> (state, creationOptions);
437                         beginMethod (arg1, arg2, arg3, l => InnerInvoke (tcs, endMethod, l), state);
438
439                         return tcs.Task;
440                 }
441
442                 #endregion
443
444                 TaskScheduler GetScheduler ()
445                 {
446                         return scheduler ?? TaskScheduler.Current;
447                 }
448
449                 static void InnerInvoke (TaskCompletionSource<TResult> tcs, Func<IAsyncResult, TResult> endMethod, IAsyncResult l)
450                 {
451                         try {
452                                 tcs.SetResult (endMethod (l));
453                         } catch (OperationCanceledException) {
454                                 tcs.SetCanceled ();
455                         } catch (Exception e) {
456                                 tcs.SetException (e);
457                         }
458                 }
459         }
460 }
461 #endif