diff options
author | Jan Kotas <jkotas@microsoft.com> | 2018-12-22 10:01:00 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-12-22 10:01:00 -0800 |
commit | dc3f080b89b7d3c85afdb8b6d2b9086363c48c14 (patch) | |
tree | 21ff4ad69efdadb9ee1d323481b5e36b9a1dc7d7 /src/System.Private.CoreLib/shared/System/Threading/Tasks/ThreadPoolTaskScheduler.cs | |
parent | 0f8e9ee7a47423852b6112006e90504bc60e28e5 (diff) | |
download | coreclr-dc3f080b89b7d3c85afdb8b6d2b9086363c48c14.tar.gz coreclr-dc3f080b89b7d3c85afdb8b6d2b9086363c48c14.tar.bz2 coreclr-dc3f080b89b7d3c85afdb8b6d2b9086363c48c14.zip |
Move some Task related files to shared CoreLib partition (#21650)
Diffstat (limited to 'src/System.Private.CoreLib/shared/System/Threading/Tasks/ThreadPoolTaskScheduler.cs')
-rw-r--r-- | src/System.Private.CoreLib/shared/System/Threading/Tasks/ThreadPoolTaskScheduler.cs | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/ThreadPoolTaskScheduler.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/ThreadPoolTaskScheduler.cs new file mode 100644 index 0000000000..339a9d8fb5 --- /dev/null +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/ThreadPoolTaskScheduler.cs @@ -0,0 +1,128 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// +// TaskScheduler.cs +// +// +// This file contains the primary interface and management of tasks and queues. +// +// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +using System; +using System.Security; +using System.Diagnostics; +using System.Collections.Generic; +using System.Text; + +using Internal.Runtime.Augments; + +namespace System.Threading.Tasks +{ + /// <summary> + /// An implementation of TaskScheduler that uses the ThreadPool scheduler + /// </summary> + internal sealed class ThreadPoolTaskScheduler : TaskScheduler + { + /// <summary> + /// Constructs a new ThreadPool task scheduler object + /// </summary> + internal ThreadPoolTaskScheduler() + { + int id = base.Id; // force ID creation of the default scheduler + } + + // static delegate for threads allocated to handle LongRunning tasks. + private static readonly ParameterizedThreadStart s_longRunningThreadWork = s => ((Task)s).ExecuteEntryUnsafe(threadPoolThread: null); + + /// <summary> + /// Schedules a task to the ThreadPool. + /// </summary> + /// <param name="task">The task to schedule.</param> + protected internal override void QueueTask(Task task) + { + TaskCreationOptions options = task.Options; + if ((options & TaskCreationOptions.LongRunning) != 0) + { + // Run LongRunning tasks on their own dedicated thread. + RuntimeThread thread = RuntimeThread.Create(s_longRunningThreadWork); + thread.IsBackground = true; // Keep this thread from blocking process shutdown + thread.Start(task); + } + else + { + // Normal handling for non-LongRunning tasks. + bool preferLocal = ((options & TaskCreationOptions.PreferFairness) == 0); + ThreadPool.UnsafeQueueUserWorkItemInternal(task, preferLocal); + } + } + + /// <summary> + /// This internal function will do this: + /// (1) If the task had previously been queued, attempt to pop it and return false if that fails. + /// (2) Return whether the task is executed + /// + /// IMPORTANT NOTE: TryExecuteTaskInline will NOT throw task exceptions itself. Any wait code path using this function needs + /// to account for exceptions that need to be propagated, and throw themselves accordingly. + /// </summary> + protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued) + { + // If the task was previously scheduled, and we can't pop it, then return false. + if (taskWasPreviouslyQueued && !ThreadPool.TryPopCustomWorkItem(task)) + return false; + + try + { + task.ExecuteEntryUnsafe(threadPoolThread: null); // handles switching Task.Current etc. + } + finally + { + // Only call NWIP() if task was previously queued + if (taskWasPreviouslyQueued) NotifyWorkItemProgress(); + } + + return true; + } + + protected internal override bool TryDequeue(Task task) + { + // just delegate to TP + return ThreadPool.TryPopCustomWorkItem(task); + } + + protected override IEnumerable<Task> GetScheduledTasks() + { + return FilterTasksFromWorkItems(ThreadPool.GetQueuedWorkItems()); + } + + private IEnumerable<Task> FilterTasksFromWorkItems(IEnumerable<object> tpwItems) + { + foreach (object tpwi in tpwItems) + { + if (tpwi is Task t) + { + yield return t; + } + } + } + + /// <summary> + /// Notifies the scheduler that work is progressing (no-op). + /// </summary> + internal override void NotifyWorkItemProgress() + { + ThreadPool.NotifyWorkItemProgress(); + } + + /// <summary> + /// This is the only scheduler that returns false for this property, indicating that the task entry codepath is unsafe (CAS free) + /// since we know that the underlying scheduler already takes care of atomic transitions from queued to non-queued. + /// </summary> + internal override bool RequiresAtomicStartTransition + { + get { return false; } + } + } +} |