1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
|
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*=============================================================================
**
** Class: LocalDataStore
**
**
** Purpose: Class that stores local data. This class is used in cooperation
** with the _LocalDataStoreMgr class.
**
**
=============================================================================*/
namespace System {
using System;
using System.Threading;
using System.Runtime.CompilerServices;
using System.Diagnostics.Contracts;
// Helper class to aid removal of LocalDataStore from the LocalDataStoreMgr
// LocalDataStoreMgr does not holds references to LocalDataStoreHolder. It holds
// references to LocalDataStore only. LocalDataStoreHolder finalizer will run once
// the only outstanding reference to the store is in LocalDataStoreMgr.
sealed internal class LocalDataStoreHolder
{
private LocalDataStore m_Store;
public LocalDataStoreHolder(LocalDataStore store)
{
m_Store = store;
}
~LocalDataStoreHolder()
{
LocalDataStore store = m_Store;
if (store == null)
return;
store.Dispose();
}
public LocalDataStore Store
{
get
{
return m_Store;
}
}
}
sealed internal class LocalDataStoreElement
{
private Object m_value;
private long m_cookie; // This is immutable cookie of the slot used to verify that
// the value is indeed indeed owned by the slot. Necessary
// to avoid resurection holes.
public LocalDataStoreElement(long cookie)
{
m_cookie = cookie;
}
public Object Value
{
get
{
return m_value;
}
set
{
m_value = value;
}
}
public long Cookie
{
get
{
return m_cookie;
}
}
}
// This class will not be marked serializable
sealed internal class LocalDataStore
{
private LocalDataStoreElement[] m_DataTable;
private LocalDataStoreMgr m_Manager;
/*=========================================================================
** Initialize the data store.
=========================================================================*/
public LocalDataStore(LocalDataStoreMgr mgr, int InitialCapacity)
{
// Store the manager of the local data store.
m_Manager = mgr;
// Allocate the array that will contain the data.
m_DataTable = new LocalDataStoreElement[InitialCapacity];
}
/*=========================================================================
** Delete this store from its manager
=========================================================================*/
internal void Dispose()
{
m_Manager.DeleteLocalDataStore(this);
}
/*=========================================================================
** Retrieves the value from the specified slot.
=========================================================================*/
public Object GetData(LocalDataStoreSlot slot)
{
// Validate the slot.
m_Manager.ValidateSlot(slot);
// Cache the slot index to avoid synchronization issues.
int slotIdx = slot.Slot;
if (slotIdx >= 0)
{
// Delay expansion of m_DataTable if we can
if (slotIdx >= m_DataTable.Length)
return null;
// Retrieve the data from the given slot.
LocalDataStoreElement element = m_DataTable[slotIdx];
//Initially we prepopulate the elements to be null.
if (element == null)
return null;
// Check that the element is owned by this slot by comparing cookies.
// This is necesary to avoid resurection ----s.
if (element.Cookie == slot.Cookie)
return element.Value;
// Fall thru and throw exception
}
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_SlotHasBeenFreed"));
}
/*=========================================================================
** Sets the data in the specified slot.
=========================================================================*/
public void SetData(LocalDataStoreSlot slot, Object data)
{
// Validate the slot.
m_Manager.ValidateSlot(slot);
// Cache the slot index to avoid synchronization issues.
int slotIdx = slot.Slot;
if (slotIdx >= 0)
{
LocalDataStoreElement element = (slotIdx < m_DataTable.Length) ? m_DataTable[slotIdx] : null;
if (element == null)
{
element = PopulateElement(slot);
}
// Check that the element is owned by this slot by comparing cookies.
// This is necesary to avoid resurection ----s.
if (element.Cookie == slot.Cookie)
{
// Set the data on the given slot.
element.Value = data;
return;
}
// Fall thru and throw exception
}
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_SlotHasBeenFreed"));
}
/*=========================================================================
** This method does clears the unused slot.
* Assumes lock on m_Manager is taken
=========================================================================*/
internal void FreeData(int slot, long cookie)
{
// We try to delay allocate the dataTable (in cases like the manager clearing a
// just-freed slot in all stores
if (slot >= m_DataTable.Length)
return;
LocalDataStoreElement element = m_DataTable[slot];
if (element != null && element.Cookie == cookie)
m_DataTable[slot] = null;
}
/*=========================================================================
** Method used to expand the capacity of the local data store.
=========================================================================*/
[System.Security.SecuritySafeCritical] // auto-generated
private LocalDataStoreElement PopulateElement(LocalDataStoreSlot slot)
{
bool tookLock = false;
RuntimeHelpers.PrepareConstrainedRegions();
try {
Monitor.Enter(m_Manager, ref tookLock);
// Make sure that the slot was not freed in the meantime
int slotIdx = slot.Slot;
if (slotIdx < 0)
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_SlotHasBeenFreed"));
if (slotIdx >= m_DataTable.Length)
{
int capacity = m_Manager.GetSlotTableLength();
// Validate that the specified capacity is larger than the current one.
Contract.Assert(capacity >= m_DataTable.Length, "LocalDataStore corrupted: capacity >= m_DataTable.Length");
// Allocate the new data table.
LocalDataStoreElement[] NewDataTable = new LocalDataStoreElement[capacity];
// Copy all the objects into the new table.
Array.Copy(m_DataTable, NewDataTable, m_DataTable.Length);
// Save the new table.
m_DataTable = NewDataTable;
}
// Validate that there is enough space in the local data store now
Contract.Assert(slotIdx < m_DataTable.Length, "LocalDataStore corrupted: slotIdx < m_DataTable.Length");
if (m_DataTable[slotIdx] == null)
m_DataTable[slotIdx] = new LocalDataStoreElement(slot.Cookie);
return m_DataTable[slotIdx];
}
finally {
if (tookLock)
Monitor.Exit(m_Manager);
}
}
}
}
|