#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
{
///
/// Represents an abstract scheduler for tasks.
///
///
///
/// TaskScheduler 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.
///
///
/// All members of the abstract type are thread-safe
/// and may be used from multiple threads concurrently.
///
///
[DebuggerDisplay("Id={Id}")]
[DebuggerTypeProxy(typeof(SystemThreadingTasksTaskSchedulerDebugView))]
public abstract partial class TaskScheduler
{
///
/// Indicates the maximum concurrency level this
/// is able to support.
///
public virtual int MaximumConcurrencyLevel
{
get { return int.MaxValue; }
}
///
/// Notifies the scheduler that a work item has made progress.
///
internal virtual void NotifyWorkItemProgress()
{
}
#pragma warning disable 0414
// An AppDomain-wide default manager.
private static readonly TaskScheduler _defaultTaskScheduler = new ThreadPoolTaskScheduler();
#pragma warning restore 0414
///
/// Gets the TaskScheduler
/// associated with the currently executing task.
///
///
/// When not called from within a task, will return null.
///
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 _unobservedTaskException;
///
/// Occurs when a faulted 's unobserved exception is about to trigger exception escalation
/// policy, which, by default, would terminate the process.
///
///
/// 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
/// instance, which may be used to examine the exception and to mark it as observed.
///
public static event EventHandler 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);
}
}
}
///
/// Provides an array of all queued Task instances
/// for the debugger.
///
///
/// The returned array is populated through a call to .
/// Note that this function is only meant to be invoked by a debugger remotely.
/// It should not be called by any other codepaths.
///
/// An array of Task instances.
///
/// This scheduler is unable to generate a list of queued tasks at this time.
///
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(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;
}
///
/// Nested class that provides debugger view for TaskScheduler
///
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 ScheduledTasks
{
get { return _taskScheduler.GetScheduledTasks(); }
}
}
}
}
#endif