The Labs \ Source Viewer \ SSCLI \ System \ LocalDataStoreMgr

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. /*=============================================================================
  16. **
  17. ** Class: LocalDataStoreMgr
  18. **
  19. **
  20. ** Purpose: Class that manages stores of local data. This class is used in
  21. **          cooperation with the LocalDataStore class.
  22. **
  23. **
  24. =============================================================================*/
  25. namespace System
  26. {
  27.    
  28.     using System;
  29.     using System.Collections;
  30.     using System.Threading;
  31.     using System.Runtime.CompilerServices;
  32.    
  33.     // This is a cheesy internal helper class that is used to make sure memory
  34.     // is actually being accessed and not some cached copy of a field in a
  35.     // register.
  36.     // WARNING: If we every do type analysis to eliminate virtual functions,
  37.     // this will break.
  38.     // This class will not be marked serializable
  39.     internal class LdsSyncHelper
  40.     {
  41.         internal virtual int Get(ref int slot)
  42.         {
  43.             return slot;
  44.         }
  45.     }
  46.    
  47.     // This class is an encapsulation of a slot so that it is managed in a secure fashion.
  48.     // It is constructed by the LocalDataStoreManager, holds the slot and the manager
  49.     // and cleans up when it is finalized.
  50.     // This class will not be marked serializable
  51.     [System.Runtime.InteropServices.ComVisible(true)]
  52.     public sealed class LocalDataStoreSlot
  53.     {
  54.         private static LdsSyncHelper m_helper = new LdsSyncHelper();
  55.        
  56.         private LocalDataStoreMgr m_mgr;
  57.         private int m_slot;
  58.        
  59.         // Construct the object to encapsulate the slot.
  60.         internal LocalDataStoreSlot(LocalDataStoreMgr mgr, int slot)
  61.         {
  62.             m_mgr = mgr;
  63.             m_slot = slot;
  64.         }
  65.        
  66.         // Accessors for the two fields of this class.
  67.         internal LocalDataStoreMgr Manager {
  68.             get { return m_mgr; }
  69.         }
  70.         internal int Slot {
  71.             get { return m_slot; }
  72.         }
  73.        
  74.         // This is used to make sure we are actually reading and writing to
  75.         // memory to fetch the slot (rather than possibly using a value
  76.         // cached in a register).
  77.         internal bool IsValid()
  78.         {
  79.             return m_helper.Get(ref m_slot) != -1;
  80.         }
  81.        
  82.         // Release the slot reserved by this object when this object goes away.
  83.         // There is a race condition that can happen in the face of
  84.         // resurrection where another thread is fetching values or assigning
  85.         // while the finalizer thread is here. We are counting on the fact
  86.         // that code that fetches values calls IsValid after fetching a value
  87.         // and before giving it to anyone. See LocalDataStore for the other
  88.         // half of this. We are also counting on code that sets values locks
  89.         // the manager.
  90.         ~LocalDataStoreSlot()
  91.         {
  92.             int slot = m_slot;
  93.            
  94.             // This lock fixes synchronization with the assignment of values.
  95.             bool tookLock = false;
  96.             RuntimeHelpers.PrepareConstrainedRegions();
  97.             try {
  98.                 Monitor.ReliableEnter(m_mgr, ref tookLock);
  99.                 // Mark the slot as free.
  100.                 m_slot = -1;
  101.                
  102.                 m_mgr.FreeDataSlot(slot);
  103.             }
  104.             finally {
  105.                 if (tookLock)
  106.                     Monitor.Exit(m_mgr);
  107.             }
  108.         }
  109.     }
  110.    
  111.     // This class will not be marked serializable
  112.     internal class LocalDataStoreMgr
  113.     {
  114.         private const byte DataSlotOccupied = 1;
  115.        
  116.         private const int InitialSlotTableSize = 64;
  117.         private const int SlotTableDoubleThreshold = 512;
  118.         private const int LargeSlotTableSizeIncrease = 128;
  119.        
  120. /*=========================================================================
  121.         ** Create a data store to be managed by this manager and add it to the
  122. ** list. The initial size of the new store matches the number of slots
  123. ** allocated in this manager.
  124.         =========================================================================*/       
  125.         public LocalDataStore CreateLocalDataStore()
  126.         {
  127.             // Create a new local data store.
  128.             LocalDataStore Store = new LocalDataStore(this, m_SlotInfoTable.Length);
  129.            
  130.             bool tookLock = false;
  131.             RuntimeHelpers.PrepareConstrainedRegions();
  132.             try {
  133.                 Monitor.ReliableEnter(this, ref tookLock);
  134.                 // Add the store to the array list and return it.
  135.                 m_ManagedLocalDataStores.Add(Store);
  136.             }
  137.             finally {
  138.                 if (tookLock)
  139.                     Monitor.Exit(this);
  140.             }
  141.             return Store;
  142.         }
  143.        
  144. /*=========================================================================
  145. * Remove the specified store from the list of managed stores..
  146.         =========================================================================*/       
  147.         public void DeleteLocalDataStore(LocalDataStore store)
  148.         {
  149.             bool tookLock = false;
  150.             RuntimeHelpers.PrepareConstrainedRegions();
  151.             try {
  152.                 Monitor.ReliableEnter(this, ref tookLock);
  153.                 // Remove the store to the array list and return it.
  154.                 m_ManagedLocalDataStores.Remove(store);
  155.             }
  156.             finally {
  157.                 if (tookLock)
  158.                     Monitor.Exit(this);
  159.             }
  160.         }
  161.        
  162. /*=========================================================================
  163.         ** Allocates a data slot by finding an available index and wrapping it
  164. ** an object to prevent clients from manipulating it directly, allowing us
  165. ** to make assumptions its integrity.
  166.         =========================================================================*/       
  167.         public LocalDataStoreSlot AllocateDataSlot()
  168.         {
  169.             bool tookLock = false;
  170.             RuntimeHelpers.PrepareConstrainedRegions();
  171.             try {
  172.                 Monitor.ReliableEnter(this, ref tookLock);
  173.                 int i;
  174.                 LocalDataStoreSlot slot;
  175.                
  176.                 // Retrieve the current size of the table.
  177.                 int SlotTableSize = m_SlotInfoTable.Length;
  178.                
  179.                 // Check if there are any slots left.
  180.                 if (m_FirstAvailableSlot < SlotTableSize) {
  181.                     // Save the first available slot.
  182.                     slot = new LocalDataStoreSlot(this, m_FirstAvailableSlot);
  183.                     m_SlotInfoTable[m_FirstAvailableSlot] = DataSlotOccupied;
  184.                    
  185.                     // Find the next available slot.
  186.                     for (i = m_FirstAvailableSlot + 1; i < SlotTableSize; ++i)
  187.                         if (0 == (m_SlotInfoTable[i] & DataSlotOccupied))
  188.                             break;
  189.                    
  190.                     // Save the new "first available slot".
  191.                     m_FirstAvailableSlot = i;
  192.                    
  193.                     // Return the slot index.
  194.                     return slot;
  195.                 }
  196.                
  197.                 // The table is full so we need to increase its size.
  198.                 int NewSlotTableSize;
  199.                 if (SlotTableSize < SlotTableDoubleThreshold) {
  200.                     // The table is still relatively small so double it.
  201.                     NewSlotTableSize = SlotTableSize * 2;
  202.                 }
  203.                 else {
  204.                     // The table is relatively large so simply increase its size by a given amount.
  205.                     NewSlotTableSize = SlotTableSize + LargeSlotTableSizeIncrease;
  206.                 }
  207.                
  208.                 // Allocate the new slot info table.
  209.                 byte[] NewSlotInfoTable = new byte[NewSlotTableSize];
  210.                
  211.                 // Copy the old array into the new one.
  212.                 Array.Copy(m_SlotInfoTable, NewSlotInfoTable, SlotTableSize);
  213.                 m_SlotInfoTable = NewSlotInfoTable;
  214.                
  215.                 // SlotTableSize is the index of the first empty slot in the expanded table.
  216.                 slot = new LocalDataStoreSlot(this, SlotTableSize);
  217.                 m_SlotInfoTable[SlotTableSize] = DataSlotOccupied;
  218.                 m_FirstAvailableSlot = SlotTableSize + 1;
  219.                
  220.                 // Return the selected slot
  221.                 return slot;
  222.             }
  223.             finally {
  224.                 if (tookLock)
  225.                     Monitor.Exit(this);
  226.             }
  227.         }
  228.        
  229. /*=========================================================================
  230. ** Allocate a slot and associate a name with it.
  231.         =========================================================================*/       
  232.         public LocalDataStoreSlot AllocateNamedDataSlot(string name)
  233.         {
  234.             bool tookLock = false;
  235.             RuntimeHelpers.PrepareConstrainedRegions();
  236.             try {
  237.                 Monitor.ReliableEnter(this, ref tookLock);
  238.                 // Allocate a normal data slot.
  239.                 LocalDataStoreSlot slot = AllocateDataSlot();
  240.                
  241.                 // Insert the association between the name and the data slot number
  242.                 // in the hash table.
  243.                 m_KeyToSlotMap.Add(name, slot);
  244.                 return slot;
  245.             }
  246.             finally {
  247.                 if (tookLock)
  248.                     Monitor.Exit(this);
  249.             }
  250.         }
  251.        
  252. /*=========================================================================
  253. ** Retrieve the slot associated with a name, allocating it if no such
  254. ** association has been defined.
  255.         =========================================================================*/       
  256.         public LocalDataStoreSlot GetNamedDataSlot(string name)
  257.         {
  258.             bool tookLock = false;
  259.             RuntimeHelpers.PrepareConstrainedRegions();
  260.             try {
  261.                 Monitor.ReliableEnter(this, ref tookLock);
  262.                 // Lookup in the hashtable to try find a slot for the name.
  263.                 LocalDataStoreSlot slot = (LocalDataStoreSlot)m_KeyToSlotMap[name];
  264.                
  265.                 // If the name is not yet in the hashtable then add it.
  266.                 if (null == slot)
  267.                     return AllocateNamedDataSlot(name);
  268.                
  269.                 // The name was in the hashtable so return the associated slot.
  270.                 return slot;
  271.             }
  272.             finally {
  273.                 if (tookLock)
  274.                     Monitor.Exit(this);
  275.             }
  276.         }
  277.        
  278. /*=========================================================================
  279. ** Eliminate the association of a name with a slot.  The actual slot will
  280. ** be reclaimed when the finalizer for the slot object runs.
  281.         =========================================================================*/       
  282.         public void FreeNamedDataSlot(string name)
  283.         {
  284.             bool tookLock = false;
  285.             RuntimeHelpers.PrepareConstrainedRegions();
  286.             try {
  287.                 Monitor.ReliableEnter(this, ref tookLock);
  288.                 // Remove the name slot association from the hashtable.
  289.                 m_KeyToSlotMap.Remove(name);
  290.             }
  291.             finally {
  292.                 if (tookLock)
  293.                     Monitor.Exit(this);
  294.             }
  295.         }
  296.        
  297. /*=========================================================================
  298.         ** Free's a previously allocated data slot on ALL the managed data stores.
  299.         =========================================================================*/       
  300.         internal void FreeDataSlot(int slot)
  301.         {
  302.             bool tookLock = false;
  303.             RuntimeHelpers.PrepareConstrainedRegions();
  304.             try {
  305.                 Monitor.ReliableEnter(this, ref tookLock);
  306.                 // Go thru all the managed stores and set the data on the specified slot to 0.
  307.                 for (int i = 0; i < m_ManagedLocalDataStores.Count; i++) {
  308.                     ((LocalDataStore)m_ManagedLocalDataStores[i]).SetDataInternal(slot, null, false);
  309.                 }
  310.                
  311.                 // Mark the slot as being no longer occupied.
  312.                 m_SlotInfoTable[slot] = 0;
  313.                 if (slot < m_FirstAvailableSlot)
  314.                     m_FirstAvailableSlot = slot;
  315.             }
  316.             finally {
  317.                 if (tookLock)
  318.                     Monitor.Exit(this);
  319.             }
  320.         }
  321.        
  322. /*=========================================================================
  323.         ** Return the number of allocated slots in this manager.
  324.         =========================================================================*/       
  325.         public void ValidateSlot(LocalDataStoreSlot slot)
  326.         {
  327.             // Make sure the slot was allocated for this store.
  328.             if (slot == null || slot.Manager != this)
  329.                 throw new ArgumentException(Environment.GetResourceString("Argument_ALSInvalidSlot"));
  330.         }
  331.        
  332. /*=========================================================================
  333.         ** Return the number of allocated slots in this manager.
  334.         =========================================================================*/       
  335.         internal int GetSlotTableLength()
  336.         {
  337.             return m_SlotInfoTable.Length;
  338.         }
  339.        
  340.         private byte[] m_SlotInfoTable = new byte[InitialSlotTableSize];
  341.         private int m_FirstAvailableSlot = 0;
  342.         private ArrayList m_ManagedLocalDataStores = new ArrayList();
  343.         private Hashtable m_KeyToSlotMap = new Hashtable();
  344.     }
  345. }

Developer Fusion