From 150836d593540d2bb8ab6e627c699506d85f26dc Mon Sep 17 00:00:00 2001 From: Marek Safar Date: Fri, 25 Jan 2019 16:58:14 +0100 Subject: [PATCH] Reduce Task's static ctor dependencies (#22172) * Reduce Task's static ctor dependencies * Remove defensive check * Revert "Remove defensive check" This reverts commit df15ab0350e8f44fc5cbb1a18c5211cd1de11989. --- .../shared/System/Threading/Tasks/Task.cs | 62 ++++++++-------------- 1 file changed, 22 insertions(+), 40 deletions(-) diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs index 37fce39..3f580c4 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs @@ -209,8 +209,7 @@ namespace System.Threading.Tasks // This dictonary relates the task id, from an operation id located in the Async Causality log to the actual // task. This is to be used by the debugger ONLY. Task in this dictionary represent current active tasks. - private static readonly Dictionary s_currentActiveTasks = new Dictionary(); - private static readonly object s_activeTasksLock = new object(); + private static Dictionary s_currentActiveTasks; // These methods are a way to access the dictionary both from this class and for other classes that also // activate dummy tasks. Specifically the AsyncTaskMethodBuilder and AsyncTaskMethodBuilder<> @@ -218,8 +217,10 @@ namespace System.Threading.Tasks { Debug.Assert(task != null, "Null Task objects can't be added to the ActiveTasks collection"); + LazyInitializer.EnsureInitialized(ref s_currentActiveTasks, () => new Dictionary()); + int taskId = task.Id; - lock (s_activeTasksLock) + lock (s_currentActiveTasks) { s_currentActiveTasks[taskId] = task; } @@ -229,8 +230,11 @@ namespace System.Threading.Tasks internal static void RemoveFromActiveTasks(Task task) { + if (s_currentActiveTasks == null) + return; + int taskId = task.Id; - lock (s_activeTasksLock) + lock (s_currentActiveTasks) { s_currentActiveTasks.Remove(taskId); } @@ -640,15 +644,24 @@ namespace System.Threading.Tasks if (antecedent == null) { // if no antecedent was specified, use this task's reference as the cancellation state object - ctr = cancellationToken.UnsafeRegister(s_taskCancelCallback, this); + ctr = cancellationToken.UnsafeRegister(t => ((Task)t).InternalCancel(false), this); } else { // If an antecedent was specified, pack this task, its antecedent and the TaskContinuation together as a tuple // and use it as the cancellation state object. This will be unpacked in the cancellation callback so that // antecedent.RemoveCancellation(continuation) can be invoked. - ctr = cancellationToken.UnsafeRegister(s_taskCancelCallback, - new Tuple(this, antecedent, continuation)); + ctr = cancellationToken.UnsafeRegister(t => + { + var tuple = (Tuple)t; + + Task targetTask = tuple.Item1; + Task antecedentTask = tuple.Item2; + + antecedentTask.RemoveContinuation(tuple.Item3); + targetTask.InternalCancel(false); + }, + new Tuple(this, antecedent, continuation)); } props.m_cancellationRegistration = new Shared(ctr); @@ -670,29 +683,6 @@ namespace System.Threading.Tasks } } - - // Static delegate to be used as a cancellation callback on unstarted tasks that have a valid cancellation token. - // This is necessary to transition them into canceled state if their cancellation token is signalled while they are still not queued - private readonly static Action s_taskCancelCallback = new Action(TaskCancelCallback); - private static void TaskCancelCallback(object o) - { - var targetTask = o as Task; - if (targetTask == null) - { - if (o is Tuple tuple) - { - targetTask = tuple.Item1; - - Task antecedentTask = tuple.Item2; - TaskContinuation continuation = tuple.Item3; - antecedentTask.RemoveContinuation(continuation); - } - } - Debug.Assert(targetTask != null, - "targetTask should have been non-null, with the supplied argument being a task or a tuple containing one"); - targetTask.InternalCancel(false); - } - // Debugger support private string DebuggerDisplayMethodDescription { @@ -2117,15 +2107,12 @@ namespace System.Threading.Tasks { lock (exceptionalChildren) { - exceptionalChildren.RemoveAll(s_IsExceptionObservedByParentPredicate); // RemoveAll has better performance than doing it ourselves + exceptionalChildren.RemoveAll(t => t.IsExceptionObservedByParent); // RemoveAll has better performance than doing it ourselves } } } } - // statically allocated delegate for the removeall expression in Finish() - private readonly static Predicate s_IsExceptionObservedByParentPredicate = new Predicate((t) => { return t.IsExceptionObservedByParent; }); - /// /// FinishStageTwo is to be executed as soon as we known there are no more children to complete. /// It can happen i) either on the thread that originally executed this task (if no children were spawned, or they all completed by the time this task's delegate quit) @@ -4350,7 +4337,7 @@ namespace System.Threading.Tasks // result from RemoveContinuations() if (list.Count == list.Capacity) { - list.RemoveAll(s_IsTaskContinuationNullPredicate); + list.RemoveAll(l => l == null); } if (addBeforeOthers) @@ -4437,11 +4424,6 @@ namespace System.Threading.Tasks } } - // statically allocated delegate for the RemoveAll expression in RemoveContinuations() and AddContinuationComplex() - private readonly static Predicate s_IsTaskContinuationNullPredicate = - new Predicate((tc) => { return (tc == null); }); - - // // Wait methods // -- 2.7.4