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