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