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.
183 lines
7.0 KiB
183 lines
7.0 KiB
5 years ago
|
#if NET20 || NET30 || NET35 || !NET_4_6
|
||
|
|
||
|
// 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.
|
||
|
|
||
|
using System.Collections.Generic;
|
||
|
using System.Diagnostics;
|
||
|
|
||
|
namespace System.Threading.Tasks
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// Represents an abstract scheduler for tasks.
|
||
|
/// </summary>
|
||
|
/// <remarks>
|
||
|
/// <para>
|
||
|
/// <see cref="System.Threading.Tasks.TaskScheduler">TaskScheduler</see> acts as the extension point for all
|
||
|
/// pluggable scheduling logic. This includes mechanisms such as how to schedule a task for execution, and
|
||
|
/// how scheduled tasks should be exposed to debuggers.
|
||
|
/// </para>
|
||
|
/// <para>
|
||
|
/// All members of the abstract <see cref="TaskScheduler"/> type are thread-safe
|
||
|
/// and may be used from multiple threads concurrently.
|
||
|
/// </para>
|
||
|
/// </remarks>
|
||
|
[DebuggerDisplay("Id={Id}")]
|
||
|
[DebuggerTypeProxy(typeof(SystemThreadingTasksTaskSchedulerDebugView))]
|
||
|
public abstract partial class TaskScheduler
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// Indicates the maximum concurrency level this
|
||
|
/// <see cref="TaskScheduler"/> is able to support.
|
||
|
/// </summary>
|
||
|
public virtual int MaximumConcurrencyLevel
|
||
|
{
|
||
|
get { return int.MaxValue; }
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Notifies the scheduler that a work item has made progress.
|
||
|
/// </summary>
|
||
|
internal virtual void NotifyWorkItemProgress()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
#pragma warning disable 0414
|
||
|
// An AppDomain-wide default manager.
|
||
|
private static readonly TaskScheduler _defaultTaskScheduler = new ThreadPoolTaskScheduler();
|
||
|
#pragma warning restore 0414
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets the <see cref="System.Threading.Tasks.TaskScheduler">TaskScheduler</see>
|
||
|
/// associated with the currently executing task.
|
||
|
/// </summary>
|
||
|
/// <remarks>
|
||
|
/// When not called from within a task, <see cref="InternalCurrent"/> will return null.
|
||
|
/// </remarks>
|
||
|
internal static TaskScheduler InternalCurrent
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
var currentTask = Task.InternalCurrent;
|
||
|
return ((currentTask != null)
|
||
|
&& ((currentTask.CreationOptions & TaskCreationOptions.HideScheduler) == 0)
|
||
|
) ? currentTask.ExecutingTaskScheduler : null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static readonly object _unobservedTaskExceptionLockObject = new object();
|
||
|
private static EventHandler<UnobservedTaskExceptionEventArgs> _unobservedTaskException;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Occurs when a faulted <see cref="System.Threading.Tasks.Task"/>'s unobserved exception is about to trigger exception escalation
|
||
|
/// policy, which, by default, would terminate the process.
|
||
|
/// </summary>
|
||
|
/// <remarks>
|
||
|
/// This AppDomain-wide event provides a mechanism to prevent exception
|
||
|
/// escalation policy (which, by default, terminates the process) from triggering.
|
||
|
/// Each handler is passed a <see cref="T:System.Threading.Tasks.UnobservedTaskExceptionEventArgs"/>
|
||
|
/// instance, which may be used to examine the exception and to mark it as observed.
|
||
|
/// </remarks>
|
||
|
public static event EventHandler<UnobservedTaskExceptionEventArgs> UnobservedTaskException
|
||
|
{
|
||
|
[Security.SecurityCritical]
|
||
|
add
|
||
|
{
|
||
|
if (value != null)
|
||
|
{
|
||
|
lock (_unobservedTaskExceptionLockObject)
|
||
|
{
|
||
|
_unobservedTaskException += value;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
[Security.SecurityCritical]
|
||
|
remove
|
||
|
{
|
||
|
lock (_unobservedTaskExceptionLockObject)
|
||
|
{
|
||
|
_unobservedTaskException -= value;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal static void PublishUnobservedTaskException(Task sender, UnobservedTaskExceptionEventArgs ueea)
|
||
|
{
|
||
|
// Lock this logic to prevent just-unregistered handlers from being called.
|
||
|
lock (_unobservedTaskExceptionLockObject)
|
||
|
{
|
||
|
// Since we are under lock, it is technically no longer necessary
|
||
|
// to make a copy. It is done here for convenience.
|
||
|
var handler = _unobservedTaskException;
|
||
|
if (handler != null)
|
||
|
{
|
||
|
handler(sender, ueea);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Provides an array of all queued <see cref="System.Threading.Tasks.Task">Task</see> instances
|
||
|
/// for the debugger.
|
||
|
/// </summary>
|
||
|
/// <remarks>
|
||
|
/// The returned array is populated through a call to <see cref="GetScheduledTasks"/>.
|
||
|
/// Note that this function is only meant to be invoked by a debugger remotely.
|
||
|
/// It should not be called by any other codepaths.
|
||
|
/// </remarks>
|
||
|
/// <returns>An array of <see cref="System.Threading.Tasks.Task">Task</see> instances.</returns>
|
||
|
/// <exception cref="T:System.NotSupportedException">
|
||
|
/// This scheduler is unable to generate a list of queued tasks at this time.
|
||
|
/// </exception>
|
||
|
internal Task[] GetScheduledTasksForDebugger()
|
||
|
{
|
||
|
// this can throw InvalidOperationException indicating that they are unable to provide the info
|
||
|
// at the moment. We should let the debugger receive that exception so that it can indicate it in the UI
|
||
|
var activeTasksSource = GetScheduledTasks();
|
||
|
|
||
|
if (activeTasksSource == null)
|
||
|
{
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
// If it can be cast to an array, use it directly
|
||
|
var activeTasksArray = activeTasksSource as Task[] ?? (new List<Task>(activeTasksSource)).ToArray();
|
||
|
|
||
|
// touch all Task.Id fields so that the debugger doesn't need to do a lot of cross-proc calls to generate them
|
||
|
foreach (var t in activeTasksArray)
|
||
|
{
|
||
|
GC.KeepAlive(t.Id);
|
||
|
}
|
||
|
|
||
|
return activeTasksArray;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Nested class that provides debugger view for TaskScheduler
|
||
|
/// </summary>
|
||
|
internal sealed class SystemThreadingTasksTaskSchedulerDebugView
|
||
|
{
|
||
|
private readonly TaskScheduler _taskScheduler;
|
||
|
|
||
|
public SystemThreadingTasksTaskSchedulerDebugView(TaskScheduler scheduler)
|
||
|
{
|
||
|
_taskScheduler = scheduler;
|
||
|
}
|
||
|
|
||
|
// returns the scheduler's Id
|
||
|
public int Id
|
||
|
{
|
||
|
get { return _taskScheduler.Id; }
|
||
|
}
|
||
|
|
||
|
// returns the scheduler's GetScheduledTasks
|
||
|
public IEnumerable<Task> ScheduledTasks
|
||
|
{
|
||
|
get { return _taskScheduler.GetScheduledTasks(); }
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif
|