Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/corert.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAnipik <anirudhagnihotry098@gmail.com>2018-08-11 02:32:09 +0300
committerJan Kotas <jkotas@microsoft.com>2018-08-11 03:48:06 +0300
commit106c32100761ef21d67b74e59fa509fd81312d65 (patch)
tree5f085b259be6de13f859a63207068713721cc371 /src
parent40af11f5d52b5097304f6f143e219035b5796ee1 (diff)
Moved to shared
Diffstat (limited to 'src')
-rw-r--r--src/System.Private.CoreLib/src/System.Private.CoreLib.csproj1
-rw-r--r--src/System.Private.CoreLib/src/System/Threading/ThreadLocal.cs816
2 files changed, 0 insertions, 817 deletions
diff --git a/src/System.Private.CoreLib/src/System.Private.CoreLib.csproj b/src/System.Private.CoreLib/src/System.Private.CoreLib.csproj
index d978b8ddd..a6b3b2c5b 100644
--- a/src/System.Private.CoreLib/src/System.Private.CoreLib.csproj
+++ b/src/System.Private.CoreLib/src/System.Private.CoreLib.csproj
@@ -319,7 +319,6 @@
<Compile Include="System\Threading\Tasks\TaskFactory.cs" />
<Compile Include="System\Threading\Tasks\TaskScheduler.cs" />
<Compile Include="System\Threading\Tasks\ThreadPoolTaskScheduler.cs" />
- <Compile Include="System\Threading\ThreadLocal.cs" />
<Compile Include="System\Threading\ThreadPool.cs" />
<Compile Include="System\Threading\ThreadPoolCallbackWrapper.cs" />
<Compile Include="System\Threading\Timer.cs" />
diff --git a/src/System.Private.CoreLib/src/System/Threading/ThreadLocal.cs b/src/System.Private.CoreLib/src/System/Threading/ThreadLocal.cs
deleted file mode 100644
index ad6da89a9..000000000
--- a/src/System.Private.CoreLib/src/System/Threading/ThreadLocal.cs
+++ /dev/null
@@ -1,816 +0,0 @@
-// 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.
-#pragma warning disable 0420
-
-// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
-//
-//
-
-//
-// 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;
-
-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}")]
- 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]
- private static LinkedSlotVolatile[] ts_slotArray;
-
- [ThreadStatic]
- private 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(nameof(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(nameof(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;
-
- using (LockHolder.Hold(s_idManager.m_lock))
- {
- id = ~m_idComplement;
- m_idComplement = 0;
-
- if (id < 0 || !m_initialized)
- {
- Debug.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 races 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 races 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(SR.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(SR.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(SR.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(SR.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
- using (LockHolder.Hold(s_idManager.m_lock))
- {
- // 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(SR.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 race 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(SR.ThreadLocal_ValuesNotAvailable);
- }
-
- var list = GetValuesAsList(); // returns null if disposed
- if (list == null) throw new ObjectDisposedException(SR.ThreadLocal_Disposed);
- return list;
- }
- }
-
- /// <summary>Gets all of the threads' values in a list.</summary>
- private LowLevelListWithIList<T> GetValuesAsList()
- {
- LowLevelListWithIList<T> valueList = new LowLevelListWithIList<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(SR.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 IList<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)
- {
- Debug.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.
- //
- using (LockHolder.Hold(s_idManager.m_lock))
- {
- 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;
- }
-
- private const int MaxArrayLength = int.MaxValue;
-
- /// <summary>
- /// Chooses the next larger table size
- /// </summary>
- private static int GetNewTableSize(int minSize)
- {
- if ((uint)minSize > MaxArrayLength)
- {
- // Intentionally return a value that will result in an OutOfMemoryException
- return int.MaxValue;
- }
- Debug.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 > MaxArrayLength)
- {
- newSize = MaxArrayLength;
- }
-
- return newSize;
- }
-
- /// <summary>
- /// A wrapper struct used as LinkedSlotVolatile[] - an array of LinkedSlot instances, but with volatile semantics
- /// on array accesses.
- /// </summary>
- internal 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>
- internal 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 LowLevelList<bool> m_freeIds = new LowLevelList<bool>();
-
- internal Lock m_lock = new Lock();
-
- internal int GetId()
- {
- using (LockHolder.Hold(m_lock))
- {
- 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)
- {
- using (LockHolder.Hold(m_lock))
- {
- 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>
- internal class FinalizationHelper
- {
- internal LinkedSlotVolatile[] SlotArray;
- private bool m_trackAllValues;
-
- internal FinalizationHelper(LinkedSlotVolatile[] slotArray, bool trackAllValues)
- {
- SlotArray = slotArray;
- m_trackAllValues = trackAllValues;
- }
-
- ~FinalizationHelper()
- {
- LinkedSlotVolatile[] slotArray = SlotArray;
- Debug.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.
- using (LockHolder.Hold(s_idManager.m_lock))
- {
- if (linkedSlot.Next != null)
- {
- linkedSlot.Next.Previous = linkedSlot.Previous;
- }
-
- // Since the list uses a dummy head node, the Previous reference should never be null.
- Debug.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 IList<T> Values
- {
- get
- {
- return m_tlocal.ValuesForDebugDisplay;
- }
- }
- }
-}