#if NET20 || NET30 || NET35 || !NET_4_6 using System.Diagnostics.Contracts; using System.Security; namespace System.Threading.Tasks { /// Task continuation for awaiting with a task scheduler. internal sealed class TaskSchedulerAwaitTaskContinuation : AwaitTaskContinuation { /// The scheduler on which to run the action. private readonly TaskScheduler _scheduler; /// Initializes the TaskSchedulerAwaitTaskContinuation. /// The task scheduler with which to invoke the action. Must not be null. /// The action to invoke. Must not be null. /// Whether to capture and restore ExecutionContext. [SecurityCritical] internal TaskSchedulerAwaitTaskContinuation(TaskScheduler scheduler, Action action, bool flowExecutionContext) : base(action, flowExecutionContext) { Contract.Assert(scheduler != null); _scheduler = scheduler; } /// Inlines or schedules the continuation. /// The antecedent task, which is ignored. /// true if inlining is permitted; otherwise, false. 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