//
// TaskFactory_T.cs
//
-// Author:
+// Authors:
// Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
+// Marek Safar <marek.safar@gmail.com>
//
// Copyright (c) 2009 Jérémie "Garuma" Laval
+// Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
#if NET_4_0 || MOBILE
-using System;
-using System.Threading;
-
namespace System.Threading.Tasks
{
public class TaskFactory<TResult>
{
- TaskScheduler scheduler;
+ readonly TaskScheduler scheduler;
TaskCreationOptions creationOptions;
TaskContinuationOptions continuationOptions;
CancellationToken cancellationToken;
TaskFactory parent;
-
- #region ctors
+
public TaskFactory ()
- : this (CancellationToken.None, TaskCreationOptions.None, TaskContinuationOptions.None, TaskScheduler.Current)
+ : this (CancellationToken.None)
{
}
}
public TaskFactory (CancellationToken cancellationToken)
- : this (cancellationToken, TaskCreationOptions.None, TaskContinuationOptions.None, TaskScheduler.Current)
+ : this (cancellationToken, TaskCreationOptions.None, TaskContinuationOptions.None, null)
{
}
public TaskFactory (TaskCreationOptions creationOptions, TaskContinuationOptions continuationOptions)
- : this (CancellationToken.None, creationOptions, continuationOptions, TaskScheduler.Current)
+ : this (CancellationToken.None, creationOptions, continuationOptions, null)
{
}
- public TaskFactory (CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskContinuationOptions continuationOptions,
- TaskScheduler scheduler)
+ public TaskFactory (CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskContinuationOptions continuationOptions, TaskScheduler scheduler)
{
this.cancellationToken = cancellationToken;
this.scheduler = scheduler;
this.creationOptions = creationOptions;
this.continuationOptions = continuationOptions;
+
+ TaskFactory.CheckContinuationOptions (continuationOptions);
this.parent = new TaskFactory (cancellationToken, creationOptions, continuationOptions, scheduler);
}
+
+ public TaskScheduler Scheduler {
+ get {
+ return scheduler;
+ }
+ }
- #endregion
+ public TaskContinuationOptions ContinuationOptions {
+ get {
+ return continuationOptions;
+ }
+ }
+
+ public TaskCreationOptions CreationOptions {
+ get {
+ return creationOptions;
+ }
+ }
+
+ public CancellationToken CancellationToken {
+ get {
+ return cancellationToken;
+ }
+ }
#region StartNew for Task<TResult>
public Task<TResult> StartNew (Func<TResult> function)
{
- return StartNew (function, cancellationToken, creationOptions, scheduler);
+ return StartNew (function, cancellationToken, creationOptions, GetScheduler ());
}
public Task<TResult> StartNew (Func<TResult> function, TaskCreationOptions creationOptions)
{
- return StartNew (function, cancellationToken, creationOptions, scheduler);
+ return StartNew (function, cancellationToken, creationOptions, GetScheduler ());
}
public Task<TResult> StartNew (Func<TResult> function, CancellationToken cancellationToken)
{
- return StartNew (function, cancellationToken, creationOptions, scheduler);
+ return StartNew (function, cancellationToken, creationOptions, GetScheduler ());
}
public Task<TResult> StartNew (Func<TResult> function,
public Task<TResult> StartNew (Func<object, TResult> function, object state)
{
- return StartNew (function, state, cancellationToken, creationOptions, scheduler);
+ return StartNew (function, state, cancellationToken, creationOptions, GetScheduler ());
}
public Task<TResult> StartNew (Func<object, TResult> function, object state, TaskCreationOptions creationOptions)
{
- return StartNew (function, state, cancellationToken, creationOptions, scheduler);
+ return StartNew (function, state, cancellationToken, creationOptions, GetScheduler ());
}
public Task<TResult> StartNew (Func<object, TResult> function, object state, CancellationToken cancellationToken)
{
- return StartNew (function, state, cancellationToken, creationOptions, scheduler);
+ return StartNew (function, state, cancellationToken, creationOptions, GetScheduler ());
}
public Task<TResult> StartNew (Func<object, TResult> function, object state,
public Task<TResult> ContinueWhenAny (Task[] tasks,
Func<Task, TResult> continuationFunction)
{
- return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, scheduler);
+ return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
}
public Task<TResult> ContinueWhenAny (Task[] tasks,
Func<Task, TResult> continuationFunction,
CancellationToken cancellationToken)
{
- return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, scheduler);
+ return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
}
public Task<TResult> ContinueWhenAny (Task[] tasks,
Func<Task, TResult> continuationFunction,
TaskContinuationOptions continuationOptions)
{
- return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, scheduler);
+ return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
}
public Task<TResult> ContinueWhenAny (Task[] tasks,
public Task<TResult> ContinueWhenAny<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
Func<Task<TAntecedentResult>, TResult> continuationFunction)
{
- return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, scheduler);
+ return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
}
public Task<TResult> ContinueWhenAny<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
Func<Task<TAntecedentResult>, TResult> continuationFunction,
CancellationToken cancellationToken)
{
- return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, scheduler);
+ return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
}
public Task<TResult> ContinueWhenAny<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
Func<Task<TAntecedentResult>, TResult> continuationFunction,
TaskContinuationOptions continuationOptions)
{
- return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, scheduler);
+ return ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
}
public Task<TResult> ContinueWhenAny<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
return parent.ContinueWhenAny (tasks, continuationFunction, cancellationToken, continuationOptions, scheduler);
}
- public Task<TResult> ContinueWhenAll (Task[] tasks,
- Func<Task[], TResult> continuationFunction)
+ public Task<TResult> ContinueWhenAll (Task[] tasks, Func<Task[], TResult> continuationFunction)
{
- return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, scheduler);
+ return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
}
public Task<TResult> ContinueWhenAll (Task[] tasks,
Func<Task[], TResult> continuationFunction,
TaskContinuationOptions continuationOptions)
{
- return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, scheduler);
+ return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
}
public Task<TResult> ContinueWhenAll (Task[] tasks,
Func<Task[], TResult> continuationFunction,
CancellationToken cancellationToken)
{
- return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, scheduler);
+ return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
}
public Task<TResult> ContinueWhenAll (Task[] tasks,
public Task<TResult> ContinueWhenAll<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
Func<Task<TAntecedentResult>[], TResult> continuationFunction)
{
- return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, scheduler);
+ return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
}
public Task<TResult> ContinueWhenAll<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
Func<Task<TAntecedentResult>[], TResult> continuationFunction,
TaskContinuationOptions continuationOptions)
{
- return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, scheduler);
+ return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
}
public Task<TResult> ContinueWhenAll<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
Func<Task<TAntecedentResult>[], TResult> continuationFunction,
CancellationToken cancellationToken)
{
- return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, scheduler);
+ return ContinueWhenAll (tasks, continuationFunction, cancellationToken, continuationOptions, GetScheduler ());
}
public Task<TResult> ContinueWhenAll<TAntecedentResult> (Task<TAntecedentResult>[] tasks,
#endregion
#region FromAsync
- const string errorMsg = "Mono's thread pool doesn't support this operation yet";
- [MonoLimitation(errorMsg)]
public Task<TResult> FromAsync (IAsyncResult asyncResult, Func<IAsyncResult, TResult> endMethod)
{
return FromAsync (asyncResult, endMethod, creationOptions);
}
- [MonoLimitation(errorMsg)]
- public Task<TResult> FromAsync (IAsyncResult asyncResult, Func<IAsyncResult, TResult> endMethod,
- TaskCreationOptions creationOptions)
+ public Task<TResult> FromAsync (IAsyncResult asyncResult, Func<IAsyncResult, TResult> endMethod, TaskCreationOptions creationOptions)
{
- return FromAsync (asyncResult, endMethod, creationOptions);
+ return FromAsync (asyncResult, endMethod, creationOptions, GetScheduler ());
}
- [MonoLimitation(errorMsg)]
- public Task<TResult> FromAsync (IAsyncResult asyncResult, Func<IAsyncResult, TResult> endMethod,
- TaskCreationOptions creationOptions, TaskScheduler scheduler)
+ public Task<TResult> FromAsync (IAsyncResult asyncResult, Func<IAsyncResult, TResult> endMethod, TaskCreationOptions creationOptions, TaskScheduler scheduler)
{
- throw new NotSupportedException (errorMsg);
+ return FromIAsyncResult (asyncResult, endMethod, creationOptions, scheduler);
}
-
- [MonoLimitation(errorMsg)]
- public Task<TResult> FromAsync (Func<AsyncCallback, Object, IAsyncResult> beginMethod,
- Func<IAsyncResult, TResult> endMethod,
+
+ internal static Task<TResult> FromIAsyncResult (IAsyncResult asyncResult, Func<IAsyncResult, TResult> endMethod, TaskCreationOptions creationOptions, TaskScheduler scheduler)
+ {
+ if (asyncResult == null)
+ throw new ArgumentNullException ("asyncResult");
+
+ if (endMethod == null)
+ throw new ArgumentNullException ("endMethod");
+
+ if (scheduler == null)
+ throw new ArgumentNullException ("scheduler");
+
+ if ((creationOptions & Task.WorkerTaskNotSupportedOptions) != 0)
+ throw new ArgumentOutOfRangeException ("creationOptions");
+
+ var source = new CancellationTokenSource ();
+ var task = new Task<TResult> (l => {
+ try {
+ return endMethod (asyncResult);
+ } catch (OperationCanceledException) {
+ source.Cancel ();
+ source.Token.ThrowIfCancellationRequested ();
+ }
+ return default (TResult);
+ }, null, source.Token, creationOptions);
+
+ // Take quick path for completed operations
+ if (asyncResult.IsCompleted) {
+ task.RunSynchronously (scheduler);
+ } else {
+ ThreadPool.RegisterWaitForSingleObject (asyncResult.AsyncWaitHandle,
+ (s, t) => task.RunSynchronously (scheduler),
+ null, Timeout.Infinite, true);
+ }
+
+ return task;
+ }
+
+ public Task<TResult> FromAsync (Func<AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
object state)
{
- throw new NotSupportedException (errorMsg);
+ return FromAsync (beginMethod, endMethod, state, creationOptions);
}
-
- [MonoLimitation(errorMsg)]
- public Task<TResult> FromAsync (Func<AsyncCallback, Object, IAsyncResult> beginMethod,
- Func<IAsyncResult, TResult> endMethod,
+
+ public Task<TResult> FromAsync (Func<AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
object state, TaskCreationOptions creationOptions)
{
- throw new NotSupportedException (errorMsg);
+ return FromAsyncBeginEnd (beginMethod, endMethod, state, creationOptions);
}
-
- [MonoLimitation(errorMsg)]
- public Task<TResult> FromAsync<TArg1> (Func<TArg1, AsyncCallback, Object, IAsyncResult> beginMethod,
- Func<IAsyncResult, TResult> endMethod,
+
+ internal static Task<TResult> FromAsyncBeginEnd (Func<AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
+ object state, TaskCreationOptions creationOptions)
+ {
+ if (beginMethod == null)
+ throw new ArgumentNullException ("beginMethod");
+
+ if (endMethod == null)
+ throw new ArgumentNullException ("endMethod");
+
+ if ((creationOptions & Task.WorkerTaskNotSupportedOptions) != 0)
+ throw new ArgumentOutOfRangeException ("creationOptions");
+
+ var tcs = new TaskCompletionSource<TResult> (state, creationOptions);
+ var alreadyInvoked = new AtomicBoolean ();
+ var iar = beginMethod (l => {
+ if (alreadyInvoked.TryRelaxedSet ())
+ InnerInvoke (tcs, endMethod, l);
+ }, state);
+ if (iar != null && iar.CompletedSynchronously && alreadyInvoked.TryRelaxedSet ())
+ InnerInvoke (tcs, endMethod, iar);
+
+ return tcs.Task;
+ }
+
+ public Task<TResult> FromAsync<TArg1> (Func<TArg1, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
TArg1 arg1, object state)
{
- throw new NotSupportedException (errorMsg);
+ return FromAsync (beginMethod, endMethod, arg1, state, creationOptions);
}
-
- [MonoLimitation(errorMsg)]
- public Task<TResult> FromAsync<TArg1> (Func<TArg1, AsyncCallback, Object, IAsyncResult> beginMethod,
- Func<IAsyncResult, TResult> endMethod,
+
+ public Task<TResult> FromAsync<TArg1> (Func<TArg1, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
TArg1 arg1, object state, TaskCreationOptions creationOptions)
{
- throw new NotSupportedException (errorMsg);
+ return FromAsyncBeginEnd (beginMethod, endMethod, arg1, state, creationOptions);
}
-
- [MonoLimitation(errorMsg)]
- public Task<TResult> FromAsync<TArg1, TArg2> (Func<TArg1, TArg2, AsyncCallback, Object, IAsyncResult> beginMethod,
- Func<IAsyncResult, TResult> endMethod,
+
+ internal static Task<TResult> FromAsyncBeginEnd<TArg1> (Func<TArg1, AsyncCallback, object, IAsyncResult> beginMethod,
+ Func<IAsyncResult, TResult> endMethod,
+ TArg1 arg1, object state, TaskCreationOptions creationOptions)
+ {
+ if (beginMethod == null)
+ throw new ArgumentNullException ("beginMethod");
+
+ if (endMethod == null)
+ throw new ArgumentNullException ("endMethod");
+
+ if ((creationOptions & Task.WorkerTaskNotSupportedOptions) != 0)
+ throw new ArgumentOutOfRangeException ("creationOptions");
+
+ var tcs = new TaskCompletionSource<TResult> (state, creationOptions);
+ var alreadyInvoked = new AtomicBoolean ();
+ var iar = beginMethod (arg1, l => {
+ if (alreadyInvoked.TryRelaxedSet ())
+ InnerInvoke (tcs, endMethod, l);
+ }, state);
+ if (iar != null && iar.CompletedSynchronously && alreadyInvoked.TryRelaxedSet ())
+ InnerInvoke (tcs, endMethod, iar);
+
+ return tcs.Task;
+ }
+
+ public Task<TResult> FromAsync<TArg1, TArg2> (Func<TArg1, TArg2, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
TArg1 arg1, TArg2 arg2, object state)
{
- throw new NotSupportedException (errorMsg);
+ return FromAsync (beginMethod, endMethod, arg1, arg2, state, creationOptions);
}
-
- [MonoLimitation(errorMsg)]
- public Task<TResult> FromAsync<TArg1, TArg2> (Func<TArg1, TArg2, AsyncCallback, Object, IAsyncResult> beginMethod,
- Func<IAsyncResult, TResult> endMethod,
+
+ public Task<TResult> FromAsync<TArg1, TArg2> (Func<TArg1, TArg2, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
TArg1 arg1, TArg2 arg2, object state, TaskCreationOptions creationOptions)
{
- throw new NotSupportedException (errorMsg);
+ return FromAsyncBeginEnd (beginMethod, endMethod, arg1, arg2, state, creationOptions);
}
-
- [MonoLimitation(errorMsg)]
- public Task<TResult> FromAsync<TArg1, TArg2, TArg3> (Func<TArg1, TArg2, TArg3, AsyncCallback, Object, IAsyncResult> beginMethod,
- Func<IAsyncResult, TResult> endMethod,
+
+ internal static Task<TResult> FromAsyncBeginEnd<TArg1, TArg2> (Func<TArg1, TArg2, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
+ TArg1 arg1, TArg2 arg2, object state, TaskCreationOptions creationOptions)
+ {
+ if (beginMethod == null)
+ throw new ArgumentNullException ("beginMethod");
+
+ if (endMethod == null)
+ throw new ArgumentNullException ("endMethod");
+
+ if ((creationOptions & Task.WorkerTaskNotSupportedOptions) != 0)
+ throw new ArgumentOutOfRangeException ("creationOptions");
+
+ var tcs = new TaskCompletionSource<TResult> (state, creationOptions);
+ var alreadyInvoked = new AtomicBoolean ();
+ var iar = beginMethod (arg1, arg2, l => {
+ if (alreadyInvoked.TryRelaxedSet ())
+ InnerInvoke (tcs, endMethod, l);
+ }, state);
+ if (iar != null && iar.CompletedSynchronously && alreadyInvoked.TryRelaxedSet ())
+ InnerInvoke (tcs, endMethod, iar);
+
+ return tcs.Task;
+ }
+
+ public Task<TResult> FromAsync<TArg1, TArg2, TArg3> (Func<TArg1, TArg2, TArg3, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
TArg1 arg1, TArg2 arg2, TArg3 arg3, object state)
{
- throw new NotSupportedException (errorMsg);
+ return FromAsync (beginMethod, endMethod, arg1, arg2, arg3, state, creationOptions);
}
-
- [MonoLimitation(errorMsg)]
- public Task<TResult> FromAsync<TArg1, TArg2, TArg3> (Func<TArg1, TArg2, TArg3, AsyncCallback, Object, IAsyncResult> beginMethod,
- Func<IAsyncResult, TResult> endMethod,
+
+ public Task<TResult> FromAsync<TArg1, TArg2, TArg3> (Func<TArg1, TArg2, TArg3, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
TArg1 arg1, TArg2 arg2, TArg3 arg3, object state,
TaskCreationOptions creationOptions)
{
- throw new NotSupportedException (errorMsg);
- }
- #endregion
-
- public TaskScheduler Scheduler {
- get {
- return scheduler;
- }
+ return FromAsyncBeginEnd (beginMethod, endMethod, arg1, arg2, arg3, state, creationOptions);
}
-
- public TaskContinuationOptions ContinuationOptions {
- get {
- return continuationOptions;
- }
+
+ internal static Task<TResult> FromAsyncBeginEnd<TArg1, TArg2, TArg3> (Func<TArg1, TArg2, TArg3, AsyncCallback, object, IAsyncResult> beginMethod, Func<IAsyncResult, TResult> endMethod,
+ TArg1 arg1, TArg2 arg2, TArg3 arg3, object state, TaskCreationOptions creationOptions)
+ {
+ if (beginMethod == null)
+ throw new ArgumentNullException ("beginMethod");
+
+ if (endMethod == null)
+ throw new ArgumentNullException ("endMethod");
+
+ if ((creationOptions & Task.WorkerTaskNotSupportedOptions) != 0)
+ throw new ArgumentOutOfRangeException ("creationOptions");
+
+ var tcs = new TaskCompletionSource<TResult> (state, creationOptions);
+ var alreadyInvoked = new AtomicBoolean ();
+ var iar = beginMethod (arg1, arg2, arg3, l => {
+ if (alreadyInvoked.TryRelaxedSet ())
+ InnerInvoke (tcs, endMethod, l);
+ }, state);
+ if (iar != null && iar.CompletedSynchronously && alreadyInvoked.TryRelaxedSet ())
+ InnerInvoke (tcs, endMethod, iar);
+
+ return tcs.Task;
}
-
- public TaskCreationOptions CreationOptions {
- get {
- return creationOptions;
- }
+
+ #endregion
+
+ TaskScheduler GetScheduler ()
+ {
+ return scheduler ?? TaskScheduler.Current;
}
-
- public CancellationToken CancellationToken {
- get {
- return cancellationToken;
+
+ static void InnerInvoke (TaskCompletionSource<TResult> tcs, Func<IAsyncResult, TResult> endMethod, IAsyncResult l)
+ {
+ try {
+ tcs.SetResult (endMethod (l));
+ } catch (OperationCanceledException) {
+ tcs.SetCanceled ();
+ } catch (Exception e) {
+ tcs.SetException (e);
}
}
}