/// <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; }
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; } }