do not check order sequence if option /order was not used
[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 = false;
343                         var iar = beginMethod (l => {
344                                 alreadyInvoked = true;
345                                 InnerInvoke (tcs, endMethod, l);
346                         }, state);
347                         if (iar != null && !alreadyInvoked && iar.CompletedSynchronously) {
348                                 InnerInvoke (tcs, endMethod, iar);
349                         }
350
351                         return tcs.Task;
352                 }
353
354                 public Task<TResult> FromAsync<TArg1> (Func<TArg1, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
355                                                        TArg1 arg1, object state)
356                 {
357                         return FromAsync (beginMethod, endMethod, arg1, state, creationOptions);
358                 }
359
360                 public Task<TResult> FromAsync<TArg1> (Func<TArg1, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
361                                                        TArg1 arg1, object state, TaskCreationOptions creationOptions)
362                 {
363                         return FromAsyncBeginEnd (beginMethod, endMethod, arg1, state, creationOptions);
364                 }
365
366                 internal static Task<TResult> FromAsyncBeginEnd<TArg1> (Func<TArg1, AsyncCallback, object, IAsyncResult> beginMethod,
367                                                                         Func<IAsyncResult, TResult> endMethod,
368                                                                         TArg1 arg1, object state, TaskCreationOptions creationOptions)
369                 {
370                         if (beginMethod == null)
371                                 throw new ArgumentNullException ("beginMethod");
372
373                         if (endMethod == null)
374                                 throw new ArgumentNullException ("endMethod");
375
376                         if ((creationOptions & Task.WorkerTaskNotSupportedOptions) != 0)
377                                 throw new ArgumentOutOfRangeException ("creationOptions");
378
379                         var tcs = new TaskCompletionSource<TResult> (state, creationOptions);
380                         var alreadyInvoked = false;
381                         var iar = beginMethod (arg1, l => {
382                                 alreadyInvoked = true;
383                                 InnerInvoke (tcs, endMethod, l);
384                         }, state);
385                         if (iar != null && !alreadyInvoked && iar.CompletedSynchronously) {
386                                 InnerInvoke (tcs, endMethod, iar);
387                         }
388
389                         return tcs.Task;
390                 }
391
392                 public Task<TResult> FromAsync<TArg1, TArg2> (Func<TArg1, TArg2, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
393                                                               TArg1 arg1, TArg2 arg2, object state)
394                 {
395                         return FromAsync (beginMethod, endMethod, arg1, arg2, state, creationOptions);
396                 }
397
398                 public Task<TResult> FromAsync<TArg1, TArg2> (Func<TArg1, TArg2, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
399                                                               TArg1 arg1, TArg2 arg2, object state, TaskCreationOptions creationOptions)
400                 {
401                         return FromAsyncBeginEnd (beginMethod, endMethod, arg1, arg2, state, creationOptions);
402                 }
403
404                 internal static Task<TResult> FromAsyncBeginEnd<TArg1, TArg2> (Func<TArg1, TArg2, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
405                                                                                   TArg1 arg1, TArg2 arg2, object state, TaskCreationOptions creationOptions)
406                 {
407                         if (beginMethod == null)
408                                 throw new ArgumentNullException ("beginMethod");
409
410                         if (endMethod == null)
411                                 throw new ArgumentNullException ("endMethod");
412
413                         if ((creationOptions & Task.WorkerTaskNotSupportedOptions) != 0)
414                                 throw new ArgumentOutOfRangeException ("creationOptions");
415
416                         var tcs = new TaskCompletionSource<TResult> (state, creationOptions);
417                         var alreadyInvoked = false;
418                         var iar = beginMethod (arg1, arg2, l => {
419                                 alreadyInvoked = true;
420                                 InnerInvoke (tcs, endMethod, l);
421                         }, state);
422                         if (iar != null && !alreadyInvoked && iar.CompletedSynchronously) {
423                                 InnerInvoke (tcs, endMethod, iar);
424                         }
425
426                         return tcs.Task;
427                 }
428
429                 public Task<TResult> FromAsync<TArg1, TArg2, TArg3> (Func<TArg1, TArg2, TArg3, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
430                                                                      TArg1 arg1, TArg2 arg2, TArg3 arg3, object state)
431                 {
432                         return FromAsync (beginMethod, endMethod, arg1, arg2, arg3, state, creationOptions);
433                 }
434
435                 public Task<TResult> FromAsync<TArg1, TArg2, TArg3> (Func<TArg1, TArg2, TArg3, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
436                                                                      TArg1 arg1, TArg2 arg2, TArg3 arg3, object state,
437                                                                      TaskCreationOptions creationOptions)
438                 {
439                         return FromAsyncBeginEnd (beginMethod, endMethod, arg1, arg2, arg3, state, creationOptions);
440                 }
441
442                 internal static Task<TResult> FromAsyncBeginEnd<TArg1, TArg2, TArg3> (Func<TArg1, TArg2, TArg3, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
443                                                                                   TArg1 arg1, TArg2 arg2, TArg3 arg3, object state, TaskCreationOptions creationOptions)
444                 {
445                         if (beginMethod == null)
446                                 throw new ArgumentNullException ("beginMethod");
447
448                         if (endMethod == null)
449                                 throw new ArgumentNullException ("endMethod");
450
451                         if ((creationOptions & Task.WorkerTaskNotSupportedOptions) != 0)
452                                 throw new ArgumentOutOfRangeException ("creationOptions");
453
454                         var tcs = new TaskCompletionSource<TResult> (state, creationOptions);
455                         bool alreadyInvoked = false;
456                         var iar = beginMethod (arg1, arg2, arg3, l => {
457                                 alreadyInvoked = true;
458                                 InnerInvoke (tcs, endMethod, l);
459                         }, state);
460                         if (iar != null && !alreadyInvoked && iar.CompletedSynchronously) {
461                                 InnerInvoke (tcs, endMethod, iar);
462                         }
463
464                         return tcs.Task;
465                 }
466
467                 #endregion
468
469                 TaskScheduler GetScheduler ()
470                 {
471                         return scheduler ?? TaskScheduler.Current;
472                 }
473
474                 static void InnerInvoke (TaskCompletionSource<TResult> tcs, Func<IAsyncResult, TResult> endMethod, IAsyncResult l)
475                 {
476                         try {
477                                 tcs.SetResult (endMethod (l));
478                         } catch (OperationCanceledException) {
479                                 tcs.SetCanceled ();
480                         } catch (Exception e) {
481                                 tcs.SetException (e);
482                         }
483                 }
484         }
485 }
486 #endif