File: system\threading\ThreadLocal.cs
Project: ndp\clr\src\bcl\mscorlib.csproj (mscorlib)
#pragma warning disable 0420
// ==++==
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// ==--==
// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
//
// ThreadLocal.cs
//
// <OWNER>Microsoft</OWNER>
//
// A class that provides a simple, lightweight implementation of thread-local lazy-initialization, where a value is initialized once per accessing 
// thread; this provides an alternative to using a ThreadStatic static variable and having 
// to check the variable prior to every access to see if it's been initialized.
//
// 
//
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 
using System.Diagnostics;
using System.Collections.Generic;
using System.Security.Permissions;
using System.Diagnostics.Contracts;
 
namespace System.Threading
{
    /// <summary>
    /// Provides thread-local storage of data.
    /// </summary>
    /// <typeparam name="T">Specifies the type of data stored per-thread.</typeparam>
    /// <remarks>
    /// <para>
    /// With the exception of <see cref="Dispose()"/>, all public and protected members of 
    /// <see cref="ThreadLocal{T}"/> are thread-safe and may be used
    /// concurrently from multiple threads.
    /// </para>
    /// </remarks>
    [DebuggerTypeProxy(typeof(SystemThreading_ThreadLocalDebugView<>))]
    [DebuggerDisplay("IsValueCreated={IsValueCreated}, Value={ValueForDebugDisplay}, Count={ValuesCountForDebugDisplay}")]
    [HostProtection(Synchronization = true, ExternalThreading = true)]
    public class ThreadLocal<T> : IDisposable
    {
 
        // a delegate that returns the created value, if null the created value will be default(T)
        private Func<T> m_valueFactory;
 
        //
        // ts_slotArray is a table of thread-local values for all ThreadLocal<T> instances
        //
        // So, when a thread reads ts_slotArray, it gets back an array of *all* ThreadLocal<T> values for this thread and this T.
        // The slot relevant to this particular ThreadLocal<T> instance is determined by the m_idComplement instance field stored in
        // the ThreadLocal<T> instance.
        //
        [ThreadStatic]
        static LinkedSlotVolatile[] ts_slotArray;
 
        [ThreadStatic]
        static FinalizationHelper ts_finalizationHelper;
 
        // Slot ID of this ThreadLocal<> instance. We store a bitwise complement of the ID (that is ~ID), which allows us to distinguish
        // between the case when ID is 0 and an incompletely initialized object, either due to a thread abort in the constructor, or
        // possibly due to a memory model issue in user code.
        private int m_idComplement;
 
        // This field is set to true when the constructor completes. That is helpful for recognizing whether a constructor
        // threw an exception - either due to invalid argument or due to a thread abort. Finally, the field is set to false
        // when the instance is disposed.
        private volatile bool m_initialized;
 
        // IdManager assigns and reuses slot IDs. Additionally, the object is also used as a global lock.
        private static IdManager s_idManager = new IdManager();
 
        // A linked list of all values associated with this ThreadLocal<T> instance.
        // We create a dummy head node. That allows us to remove any (non-dummy)  node without having to locate the m_linkedSlot field. 
        private LinkedSlot m_linkedSlot = new LinkedSlot(null);
 
        // Whether the Values property is supported
        private bool m_trackAllValues;
 
        /// <summary>
        /// Initializes the <see cref="System.Threading.ThreadLocal{T}"/> instance.
        /// </summary>
        public ThreadLocal()
        {
            Initialize(null, false);
        }
 
        /// <summary>
        /// Initializes the <see cref="System.Threading.ThreadLocal{T}"/> instance.
        /// </summary>
        /// <param name="trackAllValues">Whether to track all values set on the instance and expose them through the Values property.</param>
        public ThreadLocal(bool trackAllValues)
        {
            Initialize(null, trackAllValues);
        }
 
 
        /// <summary>
        /// Initializes the <see cref="System.Threading.ThreadLocal{T}"/> instance with the
        /// specified <paramref name="valueFactory"/> function.
        /// </summary>
        /// <param name="valueFactory">
        /// The <see cref="T:System.Func{T}"/> invoked to produce a lazily-initialized value when 
        /// an attempt is made to retrieve <see cref="Value"/> without it having been previously initialized.
        /// </param>
        /// <exception cref="T:System.ArgumentNullException">
        /// <paramref name="valueFactory"/> is a null reference (Nothing in Visual Basic).
        /// </exception>
        public ThreadLocal(Func<T> valueFactory)
        {
            if (valueFactory == null)
                throw new ArgumentNullException("valueFactory");
 
            Initialize(valueFactory, false);
        }
 
        /// <summary>
        /// Initializes the <see cref="System.Threading.ThreadLocal{T}"/> instance with the
        /// specified <paramref name="valueFactory"/> function.
        /// </summary>
        /// <param name="valueFactory">
        /// The <see cref="T:System.Func{T}"/> invoked to produce a lazily-initialized value when 
        /// an attempt is made to retrieve <see cref="Value"/> without it having been previously initialized.
        /// </param>
        /// <param name="trackAllValues">Whether to track all values set on the instance and expose them via the Values property.</param>
        /// <exception cref="T:System.ArgumentNullException">
        /// <paramref name="valueFactory"/> is a null reference (Nothing in Visual Basic).
        /// </exception>
        public ThreadLocal(Func<T> valueFactory, bool trackAllValues)
        {
            if (valueFactory == null)
                throw new ArgumentNullException("valueFactory");
 
            Initialize(valueFactory, trackAllValues);
        }
 
        private void Initialize(Func<T> valueFactory, bool trackAllValues)
        {
            m_valueFactory = valueFactory;
            m_trackAllValues = trackAllValues;
 
            // Assign the ID and mark the instance as initialized. To avoid leaking IDs, we assign the ID and set m_initialized
            // in a finally block, to avoid a thread abort in between the two statements.
            try { }
            finally
            {
                m_idComplement = ~s_idManager.GetId();
 
                // As the last step, mark the instance as fully initialized. (Otherwise, if m_initialized=false, we know that an exception
                // occurred in the constructor.)
                m_initialized = true;
            }
        }
 
        /// <summary>
        /// Releases the resources used by this <see cref="T:System.Threading.ThreadLocal{T}" /> instance.
        /// </summary>
        ~ThreadLocal()
        {
            // finalizer to return the type combination index to the pool
            Dispose(false);
        }
 
        #region IDisposable Members
 
        /// <summary>
        /// Releases the resources used by this <see cref="T:System.Threading.ThreadLocal{T}" /> instance.
        /// </summary>
        /// <remarks>
        /// Unlike most of the members of <see cref="T:System.Threading.ThreadLocal{T}"/>, this method is not thread-safe.
        /// </remarks>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
 
        /// <summary>
        /// Releases the resources used by this <see cref="T:System.Threading.ThreadLocal{T}" /> instance.
        /// </summary>
        /// <param name="disposing">
        /// A Boolean value that indicates whether this method is being called due to a call to <see cref="Dispose()"/>.
        /// </param>
        /// <remarks>
        /// Unlike most of the members of <see cref="T:System.Threading.ThreadLocal{T}"/>, this method is not thread-safe.
        /// </remarks>
        protected virtual void Dispose(bool disposing)
        {
            int id;
 
            lock (s_idManager)
            {
                id = ~m_idComplement;
                m_idComplement = 0;
 
                if (id < 0 || !m_initialized)
                {
                    Contract.Assert(id >= 0 || !m_initialized, "expected id >= 0 if initialized");
 
                    // Handle double Dispose calls or disposal of an instance whose constructor threw an exception.
                    return;
                }
                m_initialized = false;
 
                for (LinkedSlot linkedSlot = m_linkedSlot.Next; linkedSlot != null; linkedSlot = linkedSlot.Next)
                {
                    LinkedSlotVolatile[] slotArray = linkedSlot.SlotArray;
 
                    if (slotArray == null)
                    {
                        // The thread that owns this slotArray has already finished.
                        continue;
                    }
 
                    // Remove the reference from the LinkedSlot to the slot table.
                    linkedSlot.SlotArray = null;
 
                    // And clear the references from the slot table to the linked slot and the value so that
                    // both can get garbage collected.
                    slotArray[id].Value.Value = default(T);
                    slotArray[id].Value = null;
                }
            }
            m_linkedSlot = null;
            s_idManager.ReturnId(id);
        }
 
        #endregion
 
        /// <summary>Creates and returns a string representation of this instance for the current thread.</summary>
        /// <returns>The result of calling <see cref="System.Object.ToString"/> on the <see cref="Value"/>.</returns>
        /// <exception cref="T:System.NullReferenceException">
        /// The <see cref="Value"/> for the current thread is a null reference (Nothing in Visual Basic).
        /// </exception>
        /// <exception cref="T:System.InvalidOperationException">
        /// The initialization function referenced <see cref="Value"/> in an improper manner.
        /// </exception>
        /// <exception cref="T:System.ObjectDisposedException">
        /// The <see cref="ThreadLocal{T}"/> instance has been disposed.
        /// </exception>
        /// <remarks>
        /// Calling this method forces initialization for the current thread, as is the
        /// case with accessing <see cref="Value"/> directly.
        /// </remarks>
        public override string ToString()
        {
            return Value.ToString();
        }
 
        /// <summary>
        /// Gets or sets the value of this instance for the current thread.
        /// </summary>
        /// <exception cref="T:System.InvalidOperationException">
        /// The initialization function referenced <see cref="Value"/> in an improper manner.
        /// </exception>
        /// <exception cref="T:System.ObjectDisposedException">
        /// The <see cref="ThreadLocal{T}"/> instance has been disposed.
        /// </exception>
        /// <remarks>
        /// If this instance was not previously initialized for the current thread,
        /// accessing <see cref="Value"/> will attempt to initialize it. If an initialization function was 
        /// supplied during the construction, that initialization will happen by invoking the function 
        /// to retrieve the initial value for <see cref="Value"/>.  Otherwise, the default value of 
        /// <typeparamref name="T"/> will be used.
        /// </remarks>
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        public T Value
        {
            get
            {
                LinkedSlotVolatile[] slotArray = ts_slotArray;
                LinkedSlot slot;
                int id = ~m_idComplement;
 
                //
                // Attempt to get the value using the fast path
                //
                if (slotArray != null   // Has the slot array been initialized?
                    && id >= 0   // Is the ID non-negative (i.e., instance is not disposed)?
                    && id < slotArray.Length   // Is the table large enough?
                    && (slot = slotArray[id].Value) != null   // Has a LinkedSlot object has been allocated for this ID?
                    && m_initialized // Has the instance *still* not been disposed (important for ----s with Dispose)?
                ) 
                {
                    // We verified that the instance has not been disposed *after* we got a reference to the slot.
                    // This guarantees that we have a reference to the right slot.
                    // 
                    // Volatile read of the LinkedSlotVolatile.Value property ensures that the m_initialized read
                    // will not be reordered before the read of slotArray[id].
                    return slot.Value;
                }
 
                return GetValueSlow();
            }
            set
            {
                LinkedSlotVolatile[] slotArray = ts_slotArray;
                LinkedSlot slot;
                int id = ~m_idComplement;
 
                //
                // Attempt to set the value using the fast path
                //
                if (slotArray != null   // Has the slot array been initialized?
                    && id >= 0   // Is the ID non-negative (i.e., instance is not disposed)?
                    && id < slotArray.Length   // Is the table large enough?
                    && (slot = slotArray[id].Value) != null   // Has a LinkedSlot object has been allocated for this ID?
                    && m_initialized // Has the instance *still* not been disposed (important for ----s with Dispose)?
                    )
                {
                    // We verified that the instance has not been disposed *after* we got a reference to the slot.
                    // This guarantees that we have a reference to the right slot.
                    // 
                    // Volatile read of the LinkedSlotVolatile.Value property ensures that the m_initialized read
                    // will not be reordered before the read of slotArray[id].
                    slot.Value = value;
                }
                else
                {
                    SetValueSlow(value, slotArray);
                }
            }
        }
 
        private T GetValueSlow()
        {
            // If the object has been disposed, the id will be -1.
            int id = ~m_idComplement;
            if (id < 0)
            {
                throw new ObjectDisposedException(Environment.GetResourceString("ThreadLocal_Disposed"));
            }
 
            Debugger.NotifyOfCrossThreadDependency();
 
            // Determine the initial value
            T value;
            if (m_valueFactory == null)
            {
                value = default(T);
            }
            else
            {
                value = m_valueFactory();
 
                if (IsValueCreated)
                {
                    throw new InvalidOperationException(Environment.GetResourceString("ThreadLocal_Value_RecursiveCallsToValue"));
                }
            }
 
            // Since the value has been previously uninitialized, we also need to set it (according to the ThreadLocal semantics).
            Value = value;
            return value;
        }
 
        private void SetValueSlow(T value, LinkedSlotVolatile[] slotArray)
        {
            int id = ~m_idComplement;
 
            // If the object has been disposed, id will be -1.
            if (id < 0)
            {
                throw new ObjectDisposedException(Environment.GetResourceString("ThreadLocal_Disposed"));
            }
 
            // If a slot array has not been created on this thread yet, create it.
            if (slotArray == null)
            {
                slotArray = new LinkedSlotVolatile[GetNewTableSize(id + 1)];
                ts_finalizationHelper = new FinalizationHelper(slotArray, m_trackAllValues);
                ts_slotArray = slotArray;
            }
 
            // If the slot array is not big enough to hold this ID, increase the table size.
            if (id >= slotArray.Length)
            {
                GrowTable(ref slotArray, id + 1);
                ts_finalizationHelper.SlotArray = slotArray;
                ts_slotArray = slotArray;
            }
 
            // If we are using the slot in this table for the first time, create a new LinkedSlot and add it into
            // the linked list for this ThreadLocal instance.
            if (slotArray[id].Value == null)
            {
                CreateLinkedSlot(slotArray, id, value);
            }
            else
            {
                // Volatile read of the LinkedSlotVolatile.Value property ensures that the m_initialized read
                // that follows will not be reordered before the read of slotArray[id].
                LinkedSlot slot = slotArray[id].Value;
 
                // It is important to verify that the ThreadLocal instance has not been disposed. The check must come
                // after capturing slotArray[id], but before assigning the value into the slot. This ensures that
                // if this ThreadLocal instance was disposed on another thread and another ThreadLocal instance was
                // created, we definitely won't assign the value into the wrong instance.
 
                if (!m_initialized)
                {
                    throw new ObjectDisposedException(Environment.GetResourceString("ThreadLocal_Disposed"));
                }
 
                slot.Value = value;
            }
        }
 
        /// <summary>
        /// Creates a LinkedSlot and inserts it into the linked list for this ThreadLocal instance.
        /// </summary>
        private void CreateLinkedSlot(LinkedSlotVolatile[] slotArray, int id, T value)
        {
            // Create a LinkedSlot
            var linkedSlot = new LinkedSlot(slotArray);
 
            // Insert the LinkedSlot into the linked list maintained by this ThreadLocal<> instance and into the slot array
            lock (s_idManager)
            {
                // Check that the instance has not been disposed. It is important to check this under a lock, since
                // Dispose also executes under a lock.
                if (!m_initialized)
                {
                    throw new ObjectDisposedException(Environment.GetResourceString("ThreadLocal_Disposed"));
                }
 
                LinkedSlot firstRealNode = m_linkedSlot.Next;
 
                //
                // Insert linkedSlot between nodes m_linkedSlot and firstRealNode. 
                // (m_linkedSlot is the dummy head node that should always be in the front.)
                //
                linkedSlot.Next = firstRealNode;
                linkedSlot.Previous = m_linkedSlot;
                linkedSlot.Value = value;
 
                if (firstRealNode != null)
                {
                    firstRealNode.Previous = linkedSlot;
                }
                m_linkedSlot.Next = linkedSlot;
 
                // Assigning the slot under a lock prevents a ---- with Dispose (dispose also acquires the lock).
                // Otherwise, it would be possible that the ThreadLocal instance is disposed, another one gets created
                // with the same ID, and the write would go to the wrong instance.
                slotArray[id].Value = linkedSlot;
            }
        }
 
        /// <summary>
        /// Gets a list for all of the values currently stored by all of the threads that have accessed this instance.
        /// </summary>
        /// <exception cref="T:System.ObjectDisposedException">
        /// The <see cref="ThreadLocal{T}"/> instance has been disposed.
        /// </exception>
        public IList<T> Values
        {
            get
            {
                if (!m_trackAllValues)
                {
                    throw new InvalidOperationException(Environment.GetResourceString("ThreadLocal_ValuesNotAvailable"));
                }
 
                var list = GetValuesAsList(); // returns null if disposed
                if (list == null) throw new ObjectDisposedException(Environment.GetResourceString("ThreadLocal_Disposed"));
                return list;
            }
        }
 
        /// <summary>Gets all of the threads' values in a list.</summary>
        private List<T> GetValuesAsList()
        {
            List<T> valueList = new List<T>();
            int id = ~m_idComplement;
            if (id == -1)
            {
                return null;
            }
 
            // Walk over the linked list of slots and gather the values associated with this ThreadLocal instance.
            for (LinkedSlot linkedSlot = m_linkedSlot.Next; linkedSlot != null; linkedSlot = linkedSlot.Next)
            {
                // We can safely read linkedSlot.Value. Even if this ThreadLocal has been disposed in the meantime, the LinkedSlot
                // objects will never be assigned to another ThreadLocal instance.
                valueList.Add(linkedSlot.Value);
            }
 
            return valueList;
        }
 
        /// <summary>Gets the number of threads that have data in this instance.</summary>
        private int ValuesCountForDebugDisplay
        {
            get
            {
                int count = 0;
                for (LinkedSlot linkedSlot = m_linkedSlot.Next; linkedSlot != null; linkedSlot = linkedSlot.Next)
                {
                    count++;
                }
                return count;
            }
        }
 
        /// <summary>
        /// Gets whether <see cref="Value"/> is initialized on the current thread.
        /// </summary>
        /// <exception cref="T:System.ObjectDisposedException">
        /// The <see cref="ThreadLocal{T}"/> instance has been disposed.
        /// </exception>
        public bool IsValueCreated
        {
            get
            {
                int id = ~m_idComplement;
                if (id < 0)
                {
                    throw new ObjectDisposedException(Environment.GetResourceString("ThreadLocal_Disposed"));
                }
 
                LinkedSlotVolatile[] slotArray = ts_slotArray;
                return slotArray != null && id < slotArray.Length && slotArray[id].Value != null;
            }
        }
 
 
        /// <summary>Gets the value of the ThreadLocal&lt;T&gt; for debugging display purposes. It takes care of getting
        /// the value for the current thread in the ThreadLocal mode.</summary>
        internal T ValueForDebugDisplay
        {
            get
            {
                LinkedSlotVolatile[] slotArray = ts_slotArray;
                int id = ~m_idComplement;
 
                LinkedSlot slot;
                if (slotArray == null || id >= slotArray.Length || (slot = slotArray[id].Value) == null || !m_initialized)
                    return default(T);
                return slot.Value;
            }
        }
 
        /// <summary>Gets the values of all threads that accessed the ThreadLocal&lt;T&gt;.</summary>
        internal List<T> ValuesForDebugDisplay // same as Values property, but doesn't throw if disposed
        {
            get { return GetValuesAsList(); }
        }
 
        /// <summary>
        /// Resizes a table to a certain length (or larger).
        /// </summary>
        private void GrowTable(ref LinkedSlotVolatile[] table, int minLength)
        {
            Contract.Assert(table.Length < minLength);
 
            // Determine the size of the new table and allocate it.
            int newLen = GetNewTableSize(minLength);
            LinkedSlotVolatile[] newTable = new LinkedSlotVolatile[newLen];
 
            //
            // The lock is necessary to avoid a race with ThreadLocal.Dispose. GrowTable has to point all 
            // LinkedSlot instances referenced in the old table to reference the new table. Without locking, 
            // Dispose could use a stale SlotArray reference and clear out a slot in the old array only, while 
            // the value continues to be referenced from the new (larger) array.
            //
            lock (s_idManager)
            {
                for (int i = 0; i < table.Length; i++)
                {
                    LinkedSlot linkedSlot = table[i].Value;
                    if (linkedSlot != null && linkedSlot.SlotArray != null)
                    {
                        linkedSlot.SlotArray = newTable;
                        newTable[i] = table[i];
                    }
                }
            }
 
            table = newTable;
        }
 
        /// <summary>
        /// Chooses the next larger table size
        /// </summary>
        private static int GetNewTableSize(int minSize)
        {
            if ((uint)minSize > Array.MaxArrayLength)
            {
                // Intentionally return a value that will result in an OutOfMemoryException
                return int.MaxValue;
            }
            Contract.Assert(minSize > 0);
 
            //
            // Round up the size to the next power of 2
            //
            // The algorithm takes three steps: 
            //   input -> subtract one -> propagate 1-bits to the right -> add one
            //
            // Let's take a look at the 3 steps in both interesting cases: where the input 
            // is (Example 1) and isn't (Example 2) a power of 2.
            //
            //   Example 1: 100000 -> 011111 -> 011111 -> 100000
            //   Example 2: 011010 -> 011001 -> 011111 -> 100000
            // 
            int newSize = minSize;
 
            // Step 1: Decrement
            newSize--;
 
            // Step 2: Propagate 1-bits to the right.
            newSize |= newSize >> 1;
            newSize |= newSize >> 2;
            newSize |= newSize >> 4;
            newSize |= newSize >> 8;
            newSize |= newSize >> 16;
 
            // Step 3: Increment
            newSize++;
 
            // Don't set newSize to more than Array.MaxArrayLength
            if ((uint)newSize > Array.MaxArrayLength)
            {
                newSize = Array.MaxArrayLength;
            }
 
            return newSize;
        }
 
        /// <summary>
        /// A wrapper struct used as LinkedSlotVolatile[] - an array of LinkedSlot instances, but with volatile semantics
        /// on array accesses.
        /// </summary>
        private struct LinkedSlotVolatile
        {
            internal volatile LinkedSlot Value;
        }
 
        /// <summary>
        /// A node in the doubly-linked list stored in the ThreadLocal instance.
        /// 
        /// The value is stored in one of two places:
        /// 
        ///     1. If SlotArray is not null, the value is in SlotArray.Table[id]
        ///     2. If SlotArray is null, the value is in FinalValue.
        /// </summary>
        private sealed class LinkedSlot
        {
            internal LinkedSlot(LinkedSlotVolatile[] slotArray)
            {
                SlotArray = slotArray;
            }
 
            // The next LinkedSlot for this ThreadLocal<> instance
            internal volatile LinkedSlot Next;
 
            // The previous LinkedSlot for this ThreadLocal<> instance
            internal volatile LinkedSlot Previous;
 
            // The SlotArray that stores this LinkedSlot at SlotArray.Table[id].
            internal volatile LinkedSlotVolatile[] SlotArray;
 
            // The value for this slot.
            internal T Value;
        }
 
        /// <summary>
        /// A manager class that assigns IDs to ThreadLocal instances
        /// </summary>
        private class IdManager
        {
            // The next ID to try
            private int m_nextIdToTry = 0;
 
            // Stores whether each ID is free or not. Additionally, the object is also used as a lock for the IdManager.
            private List<bool> m_freeIds = new List<bool>();
 
            internal int GetId()
            {
                lock (m_freeIds)
                {
                    int availableId = m_nextIdToTry;
                    while (availableId < m_freeIds.Count)
                    {
                        if (m_freeIds[availableId]) { break; }
                        availableId++;
                    }
 
                    if (availableId == m_freeIds.Count)
                    {
                        m_freeIds.Add(false);
                    }
                    else
                    {
                        m_freeIds[availableId] = false;
                    }
 
                    m_nextIdToTry = availableId + 1;
 
                    return availableId;
                }
            }
 
            // Return an ID to the pool
            internal void ReturnId(int id)
            {
                lock (m_freeIds)
                {
                    m_freeIds[id] = true;
                    if (id < m_nextIdToTry) m_nextIdToTry = id;
                }
            }
        }
 
        /// <summary>
        /// A class that facilitates ThreadLocal cleanup after a thread exits.
        /// 
        /// After a thread with an associated thread-local table has exited, the FinalizationHelper 
        /// is reponsible for removing back-references to the table. Since an instance of FinalizationHelper 
        /// is only referenced from a single thread-local slot, the FinalizationHelper will be GC'd once
        /// the thread has exited.
        /// 
        /// The FinalizationHelper then locates all LinkedSlot instances with back-references to the table
        /// (all those LinkedSlot instances can be found by following references from the table slots) and
        /// releases the table so that it can get GC'd.
        /// </summary>
        private class FinalizationHelper
        {
            internal LinkedSlotVolatile[] SlotArray;
            private bool m_trackAllValues;
 
            internal FinalizationHelper(LinkedSlotVolatile[] slotArray, bool trackAllValues)
            {
                SlotArray = slotArray;
                m_trackAllValues = trackAllValues;
            }
 
            ~FinalizationHelper()
            {
                LinkedSlotVolatile[] slotArray = SlotArray;
                Contract.Assert(slotArray != null);
 
                for (int i = 0; i < slotArray.Length; i++)
                {
                    LinkedSlot linkedSlot = slotArray[i].Value;
                    if (linkedSlot == null)
                    {
                        // This slot in the table is empty
                        continue;
                    }
 
                    if (m_trackAllValues)
                    {
                        // Set the SlotArray field to null to release the slot array.
                        linkedSlot.SlotArray = null;
                    }
                    else
                    {
                        // Remove the LinkedSlot from the linked list. Once the FinalizationHelper is done, all back-references to
                        // the table will be have been removed, and so the table can get GC'd.
                        lock (s_idManager)
                        {
                            if (linkedSlot.Next != null)
                            {
                                linkedSlot.Next.Previous = linkedSlot.Previous;
                            }
 
                            // Since the list uses a dummy head node, the Previous reference should never be null.
                            Contract.Assert(linkedSlot.Previous != null);
                            linkedSlot.Previous.Next = linkedSlot.Next;
                        }
                    }
                }
            }
        }
    }
 
    /// <summary>A debugger view of the ThreadLocal&lt;T&gt; to surface additional debugging properties and 
    /// to ensure that the ThreadLocal&lt;T&gt; does not become initialized if it was not already.</summary>
    internal sealed class SystemThreading_ThreadLocalDebugView<T>
    {
        //The ThreadLocal object being viewed.
        private readonly ThreadLocal<T> m_tlocal;
 
        /// <summary>Constructs a new debugger view object for the provided ThreadLocal object.</summary>
        /// <param name="tlocal">A ThreadLocal object to browse in the debugger.</param>
        public SystemThreading_ThreadLocalDebugView(ThreadLocal<T> tlocal)
        {
            m_tlocal = tlocal;
        }
 
        /// <summary>Returns whether the ThreadLocal object is initialized or not.</summary>
        public bool IsValueCreated
        {
            get { return m_tlocal.IsValueCreated; }
        }
 
        /// <summary>Returns the value of the ThreadLocal object.</summary>
        public T Value
        {
            get
            {
                return m_tlocal.ValueForDebugDisplay;
            }
        }
 
        /// <summary>Return all values for all threads that have accessed this instance.</summary>
        public List<T> Values
        {
            get
            {
                return m_tlocal.ValuesForDebugDisplay;
            }
        }
    }
}