You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
86 lines
3.9 KiB
86 lines
3.9 KiB
#if NET20 || NET30 || NET35 || !NET_4_6 |
|
|
|
using System.Diagnostics.Contracts; |
|
using System.Security; |
|
|
|
namespace System.Threading.Tasks |
|
{ |
|
/// <summary>Task continuation for awaiting with a task scheduler.</summary> |
|
internal sealed class TaskSchedulerAwaitTaskContinuation : AwaitTaskContinuation |
|
{ |
|
/// <summary>The scheduler on which to run the action.</summary> |
|
private readonly TaskScheduler _scheduler; |
|
|
|
/// <summary>Initializes the TaskSchedulerAwaitTaskContinuation.</summary> |
|
/// <param name="scheduler">The task scheduler with which to invoke the action. Must not be null.</param> |
|
/// <param name="action">The action to invoke. Must not be null.</param> |
|
/// <param name="flowExecutionContext">Whether to capture and restore ExecutionContext.</param> |
|
[SecurityCritical] |
|
internal TaskSchedulerAwaitTaskContinuation(TaskScheduler scheduler, Action action, bool flowExecutionContext) |
|
: base(action, flowExecutionContext) |
|
{ |
|
Contract.Assert(scheduler != null); |
|
_scheduler = scheduler; |
|
} |
|
|
|
/// <summary>Inlines or schedules the continuation.</summary> |
|
/// <param name="completedTask">The antecedent task, which is ignored.</param> |
|
/// <param name="canInlineContinuationTask">true if inlining is permitted; otherwise, false.</param> |
|
internal override void Run(Task completedTask, bool canInlineContinuationTask) |
|
{ |
|
// If we're targeting the default scheduler, we can use the faster path provided by the base class. |
|
if (_scheduler == TaskScheduler.Default) |
|
{ |
|
base.Run(completedTask, canInlineContinuationTask); |
|
} |
|
else |
|
{ |
|
// We permit inlining if the caller allows us to, and |
|
// either we're on a thread pool thread (in which case we're fine running arbitrary code) |
|
// or we're already on the target scheduler (in which case we'll just ask the scheduler |
|
// whether it's ok to run here). We include the IsThreadPoolThread check here, whereas |
|
// we don't in AwaitTaskContinuation.Run, since here it expands what's allowed as opposed |
|
// to in AwaitTaskContinuation.Run where it restricts what's allowed. |
|
var inlineIfPossible = canInlineContinuationTask && (TaskScheduler.Current == _scheduler || Thread.CurrentThread.IsThreadPoolThread); |
|
|
|
// Create the continuation task task. If we're allowed to inline, try to do so. |
|
// The target scheduler may still deny us from executing on this thread, in which case this'll be queued. |
|
var task = CreateTask |
|
( |
|
state => |
|
{ |
|
try |
|
{ |
|
((Action)state)(); |
|
} |
|
catch (Exception exc) |
|
{ |
|
ThrowAsyncIfNecessary(exc); |
|
} |
|
}, |
|
Action, |
|
_scheduler |
|
); |
|
if (inlineIfPossible) |
|
{ |
|
InlineIfPossibleOrElseQueue(task); |
|
} |
|
else |
|
{ |
|
// We need to run asynchronously, so just schedule the task. |
|
try |
|
{ |
|
task.TryStart(task.ExecutingTaskScheduler, false); |
|
} |
|
catch (TaskSchedulerException exception) |
|
{ |
|
// No further action is necessary, as ScheduleAndStart already transitioned task to faulted |
|
GC.KeepAlive(exception); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
#endif |