From: stephentoub Date: Sun, 1 May 2016 22:25:07 +0000 (-0400) Subject: Move Task's m_parent to ContingentProperties X-Git-Tag: accepted/tizen/base/20180629.140029~4470^2~2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=eae354bb59a357bc512c37f74db79e484933be4a;p=platform%2Fupstream%2Fcoreclr.git Move Task's m_parent to ContingentProperties Shrinks the size of Task by 10% in the common case (when ContingentProperties doesn't need to be expanded). --- diff --git a/src/mscorlib/src/System/Threading/Tasks/Task.cs b/src/mscorlib/src/System/Threading/Tasks/Task.cs index 6031457..1afb644 100644 --- a/src/mscorlib/src/System/Threading/Tasks/Task.cs +++ b/src/mscorlib/src/System/Threading/Tasks/Task.cs @@ -164,11 +164,9 @@ namespace System.Threading.Tasks internal object m_stateObject; // A state object that can be optionally supplied, passed to action. internal TaskScheduler m_taskScheduler; // The task scheduler this task runs under. - internal readonly Task m_parent; // A task's parent, or null if parent-less. - internal volatile int m_stateFlags; - private Task ParentForDebugger => m_parent; // Private property used by a debugger to access this Task's parent + private Task ParentForDebugger => m_contingentProperties?.m_parent; // Private property used by a debugger to access this Task's parent private int StateFlagsForDebugger => m_stateFlags; // Private property used by a debugger to access this Task's state flags // State constants for m_stateFlags; @@ -275,6 +273,8 @@ namespace System.Threading.Tasks // A list of child tasks that threw an exception (TCEs don't count), // but haven't yet been waited on by the parent, lazily initialized. internal volatile List m_exceptionalChildren; + // A task's parent, or null if parent-less. + internal Task m_parent; /// /// Sets the internal completion event. @@ -358,10 +358,9 @@ namespace System.Threading.Tasks throw new ArgumentOutOfRangeException("creationOptions"); } - // m_parent is readonly, and so must be set in the constructor. // Only set a parent if AttachedToParent is specified. if ((creationOptions & TaskCreationOptions.AttachedToParent) != 0) - m_parent = Task.InternalCurrent; + EnsureContingentPropertiesInitialized(needsProtection: false).m_parent = Task.InternalCurrent; TaskConstructorCore(null, state, default(CancellationToken), creationOptions, InternalTaskOptions.PromiseTask, null); } @@ -569,7 +568,7 @@ namespace System.Threading.Tasks ((internalOptions & InternalTaskOptions.SelfReplicating) != 0) ) { - m_parent = parent; + EnsureContingentPropertiesInitialized(needsProtection: false).m_parent = parent; } TaskConstructorCore(action, state, cancellationToken, creationOptions, internalOptions, scheduler); @@ -642,12 +641,13 @@ namespace System.Threading.Tasks // We can safely call the creator task's AddNewChild() method to register it, // because at this point we are already on its thread of execution. - if (m_parent != null + Task parent = m_contingentProperties?.m_parent; + if (parent != null && ((creationOptions & TaskCreationOptions.AttachedToParent) != 0) - && ((m_parent.CreationOptions & TaskCreationOptions.DenyChildAttach) == 0) + && ((parent.CreationOptions & TaskCreationOptions.DenyChildAttach) == 0) ) { - m_parent.AddNewChild(); + parent.AddNewChild(); } // if we have a non-null cancellationToken, allocate the contingent properties to save it @@ -718,11 +718,12 @@ namespace System.Threading.Tasks { // If we have an exception related to our CancellationToken, then we need to subtract ourselves // from our parent before throwing it. - if ((m_parent != null) && + Task parent = m_contingentProperties?.m_parent; + if ((parent != null) && ((Options & TaskCreationOptions.AttachedToParent) != 0) - && ((m_parent.Options & TaskCreationOptions.DenyChildAttach) == 0)) + && ((parent.Options & TaskCreationOptions.DenyChildAttach) == 0)) { - m_parent.DisregardChild(); + parent.DisregardChild(); } throw; } @@ -975,7 +976,7 @@ namespace System.Threading.Tasks m_stateFlags |= Task.TASK_STATE_TASKSCHEDULED_WAS_FIRED; Task currentTask = Task.InternalCurrent; - Task parentTask = this.m_parent; + Task parentTask = m_contingentProperties?.m_parent; etwLog.TaskScheduled(ts.Id, currentTask == null ? 0 : currentTask.Id, this.Id, parentTask == null ? 0 : parentTask.Id, (int)this.Options, System.Threading.Thread.GetDomainID()); @@ -2162,10 +2163,11 @@ namespace System.Threading.Tasks /// internal void UpdateExceptionObservedStatus() { - if ((m_parent != null) + Task parent = m_contingentProperties?.m_parent; + if ((parent != null) && ((Options & TaskCreationOptions.AttachedToParent) != 0) - && ((m_parent.CreationOptions & TaskCreationOptions.DenyChildAttach) == 0) - && Task.InternalCurrent == m_parent) + && ((parent.CreationOptions & TaskCreationOptions.DenyChildAttach) == 0) + && Task.InternalCurrent == parent) { m_stateFlags |= TASK_STATE_EXCEPTIONOBSERVEDBYPARENT; } @@ -2346,11 +2348,12 @@ namespace System.Threading.Tasks m_action = null; // Notify parent if this was an attached task - if (m_parent != null - && ((m_parent.CreationOptions & TaskCreationOptions.DenyChildAttach) == 0) + Task parent = m_contingentProperties?.m_parent; + if (parent != null + && ((parent.CreationOptions & TaskCreationOptions.DenyChildAttach) == 0) && (((TaskCreationOptions)(m_stateFlags & OptionsMask)) & TaskCreationOptions.AttachedToParent) != 0) { - m_parent.ProcessChildCompletion(this); + parent.ProcessChildCompletion(this); } // Activate continuations (if any). @@ -2365,7 +2368,7 @@ namespace System.Threading.Tasks Contract.Requires(childTask != null); Contract.Requires(childTask.IsCompleted, "ProcessChildCompletion was called for an uncompleted task"); - Contract.Assert(childTask.m_parent == this, "ProcessChildCompletion should only be called for a child of this task"); + Contract.Assert(childTask.m_contingentProperties?.m_parent == this, "ProcessChildCompletion should only be called for a child of this task"); var props = m_contingentProperties; diff --git a/src/mscorlib/src/System/Threading/Tasks/future.cs b/src/mscorlib/src/System/Threading/Tasks/future.cs index 1207828..9ce7ab6 100644 --- a/src/mscorlib/src/System/Threading/Tasks/future.cs +++ b/src/mscorlib/src/System/Threading/Tasks/future.cs @@ -500,7 +500,7 @@ namespace System.Threading.Tasks Contract.Assert(!IsCompleted, "The promise must not yet be completed."); // If we have a parent, we need to notify it of the completion. Take the slow path to handle that. - if (m_parent != null) + if (m_contingentProperties?.m_parent != null) { bool success = TrySetResult(result); @@ -593,7 +593,7 @@ namespace System.Threading.Tasks // // The lazy initialization may not be strictly necessary, but I'd like to keep it here // anyway. Some downstream logic may depend upon an inflated m_contingentProperties. - EnsureContingentPropertiesInitialized(needsProtection: true); + EnsureContingentPropertiesInitialized(); if (AtomicStateUpdate(TASK_STATE_COMPLETION_RESERVED, TASK_STATE_COMPLETION_RESERVED | TASK_STATE_RAN_TO_COMPLETION | TASK_STATE_FAULTED | TASK_STATE_CANCELED)) {