|
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*=============================================================================
**
** Class: LocalDataStoreMgr
**
**
** Purpose: Class that manages stores of local data. This class is used in
** cooperation with the LocalDataStore class.
**
**
=============================================================================*/
namespace System {
using System;
using System.Collections.Generic;
using System.Threading;
using System.Runtime.CompilerServices;
using System.Diagnostics.Contracts;
// This class is an encapsulation of a slot so that it is managed in a secure fashion.
// It is constructed by the LocalDataStoreManager, holds the slot and the manager
// and cleans up when it is finalized.
// This class will not be marked serializable
[System.Runtime.InteropServices.ComVisible(true)]
public sealed class LocalDataStoreSlot
{
private LocalDataStoreMgr m_mgr;
private int m_slot;
private long m_cookie;
// Construct the object to encapsulate the slot.
internal LocalDataStoreSlot(LocalDataStoreMgr mgr, int slot, long cookie)
{
m_mgr = mgr;
m_slot = slot;
m_cookie = cookie;
}
// Accessors for the two fields of this class.
internal LocalDataStoreMgr Manager
{
get
{
return m_mgr;
}
}
internal int Slot
{
get
{
return m_slot;
}
}
internal long Cookie
{
get
{
return m_cookie;
}
}
// Release the slot reserved by this object when this object goes away.
~LocalDataStoreSlot()
{
LocalDataStoreMgr mgr = m_mgr;
if (mgr == null)
return;
int slot = m_slot;
// Mark the slot as free.
m_slot = -1;
mgr.FreeDataSlot(slot, m_cookie);
}
}
// This class will not be marked serializable
sealed internal class LocalDataStoreMgr
{
private const int InitialSlotTableSize = 64;
private const int SlotTableDoubleThreshold = 512;
private const int LargeSlotTableSizeIncrease = 128;
/*=========================================================================
** Create a data store to be managed by this manager and add it to the
** list. The initial size of the new store matches the number of slots
** allocated in this manager.
=========================================================================*/
[System.Security.SecuritySafeCritical] // auto-generated
public LocalDataStoreHolder CreateLocalDataStore()
{
// Create a new local data store.
LocalDataStore store = new LocalDataStore(this, m_SlotInfoTable.Length);
LocalDataStoreHolder holder = new LocalDataStoreHolder(store);
bool tookLock = false;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
Monitor.Enter(this, ref tookLock);
// Add the store to the array list and return it.
m_ManagedLocalDataStores.Add(store);
}
finally
{
if (tookLock)
Monitor.Exit(this);
}
return holder;
}
/*=========================================================================
* Remove the specified store from the list of managed stores..
=========================================================================*/
[System.Security.SecuritySafeCritical] // auto-generated
public void DeleteLocalDataStore(LocalDataStore store)
{
bool tookLock = false;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
Monitor.Enter(this, ref tookLock);
// Remove the store to the array list and return it.
m_ManagedLocalDataStores.Remove(store);
}
finally
{
if (tookLock)
Monitor.Exit(this);
}
}
/*=========================================================================
** Allocates a data slot by finding an available index and wrapping it
** an object to prevent clients from manipulating it directly, allowing us
** to make assumptions its integrity.
=========================================================================*/
[System.Security.SecuritySafeCritical] // auto-generated
public LocalDataStoreSlot AllocateDataSlot()
{
bool tookLock = false;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
Monitor.Enter(this, ref tookLock);
LocalDataStoreSlot slot;
int slotTableSize = m_SlotInfoTable.Length;
// In case FreeDataSlot has moved the pointer back, the next slot may not be available.
// Find the first actually available slot.
int availableSlot = m_FirstAvailableSlot;
while (availableSlot < slotTableSize)
{
if (!m_SlotInfoTable[availableSlot])
break;
availableSlot++;
}
// Check if there are any slots left.
if (availableSlot >= slotTableSize)
{
// The table is full so we need to increase its size.
int newSlotTableSize;
if (slotTableSize < SlotTableDoubleThreshold)
{
// The table is still relatively small so double it.
newSlotTableSize = slotTableSize * 2;
}
else
{
// The table is relatively large so simply increase its size by a given amount.
newSlotTableSize = slotTableSize + LargeSlotTableSizeIncrease;
}
// Allocate the new slot info table.
bool[] newSlotInfoTable = new bool[newSlotTableSize];
// Copy the old array into the new one.
Array.Copy(m_SlotInfoTable, newSlotInfoTable, slotTableSize);
m_SlotInfoTable = newSlotInfoTable;
}
// availableSlot is the index of the empty slot.
m_SlotInfoTable[availableSlot] = true;
// We do not need to worry about overflowing m_CookieGenerator. It would take centuries
// of intensive slot allocations on current machines to get the 2^64 counter to overflow.
// We will perform the increment with overflow check just to play it on the safe side.
slot = new LocalDataStoreSlot(this, availableSlot, checked(m_CookieGenerator++));
// Save the new "first available slot".hint
m_FirstAvailableSlot = availableSlot + 1;
// Return the selected slot
return slot;
}
finally
{
if (tookLock)
Monitor.Exit(this);
}
}
/*=========================================================================
** Allocate a slot and associate a name with it.
=========================================================================*/
[System.Security.SecuritySafeCritical] // auto-generated
public LocalDataStoreSlot AllocateNamedDataSlot(String name)
{
bool tookLock = false;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
Monitor.Enter(this, ref tookLock);
// Allocate a normal data slot.
LocalDataStoreSlot slot = AllocateDataSlot();
// Insert the association between the name and the data slot number
// in the hash table.
m_KeyToSlotMap.Add(name, slot);
return slot;
}
finally
{
if (tookLock)
Monitor.Exit(this);
}
}
/*=========================================================================
** Retrieve the slot associated with a name, allocating it if no such
** association has been defined.
=========================================================================*/
[System.Security.SecuritySafeCritical] // auto-generated
public LocalDataStoreSlot GetNamedDataSlot(String name)
{
bool tookLock = false;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
Monitor.Enter(this, ref tookLock);
// Lookup in the hashtable to try find a slot for the name.
LocalDataStoreSlot slot = m_KeyToSlotMap.GetValueOrDefault(name);
// If the name is not yet in the hashtable then add it.
if (null == slot)
return AllocateNamedDataSlot(name);
// The name was in the hashtable so return the associated slot.
return slot;
}
finally
{
if (tookLock)
Monitor.Exit(this);
}
}
/*=========================================================================
** Eliminate the association of a name with a slot. The actual slot will
** be reclaimed when the finalizer for the slot object runs.
=========================================================================*/
[System.Security.SecuritySafeCritical] // auto-generated
public void FreeNamedDataSlot(String name)
{
bool tookLock = false;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
Monitor.Enter(this, ref tookLock);
// Remove the name slot association from the hashtable.
m_KeyToSlotMap.Remove(name);
}
finally
{
if (tookLock)
Monitor.Exit(this);
}
}
/*=========================================================================
** Free's a previously allocated data slot on ALL the managed data stores.
=========================================================================*/
[System.Security.SecuritySafeCritical] // auto-generated
internal void FreeDataSlot(int slot, long cookie)
{
bool tookLock = false;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
Monitor.Enter(this, ref tookLock);
// Go thru all the managed stores and set the data on the specified slot to 0.
for (int i = 0; i < m_ManagedLocalDataStores.Count; i++)
{
((LocalDataStore)m_ManagedLocalDataStores[i]).FreeData(slot, cookie);
}
// Mark the slot as being no longer occupied.
m_SlotInfoTable[slot] = false;
if (slot < m_FirstAvailableSlot)
m_FirstAvailableSlot = slot;
}
finally
{
if (tookLock)
Monitor.Exit(this);
}
}
/*=========================================================================
** Check that this is a valid slot for this store
=========================================================================*/
public void ValidateSlot(LocalDataStoreSlot slot)
{
// Make sure the slot was allocated for this store.
if (slot == null || slot.Manager != this)
throw new ArgumentException(Environment.GetResourceString("Argument_ALSInvalidSlot"));
Contract.EndContractBlock();
}
/*=========================================================================
** Return the number of allocated slots in this manager.
=========================================================================*/
internal int GetSlotTableLength()
{
return m_SlotInfoTable.Length;
}
private bool[] m_SlotInfoTable = new bool[InitialSlotTableSize];
private int m_FirstAvailableSlot;
private List<LocalDataStore> m_ManagedLocalDataStores = new List<LocalDataStore>();
private Dictionary<String, LocalDataStoreSlot> m_KeyToSlotMap = new Dictionary<String, LocalDataStoreSlot>();
private long m_CookieGenerator;
}
}
|