Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / whidbey / netfxsp / ndp / clr / src / BCL / System / Runtime / InteropServices / GCHandleCookieTable.cs / 1 / GCHandleCookieTable.cs
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
#if MDA_SUPPORTED
namespace System.Runtime.InteropServices
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using ObjectHandle = IntPtr;
using GCHandleCookie = IntPtr;
// Internal class used to map a GCHandle to an IntPtr. Instead of handing out the underlying CLR
// handle, we now hand out a cookie that can later be converted back to the CLR handle it
// is associated with.
internal class GCHandleCookieTable
{
private const int MaxListSize = 0xFFFFFF;
private const uint CookieMaskIndex = 0x00FFFFFF;
private const uint CookieMaskSentinal = 0xFF000000;
internal GCHandleCookieTable()
{
m_HandleList = new ObjectHandle[10];
m_CycleCounts = new byte[10];
m_HandleToCookieMap = new Hashtable();
m_FreeIndex = 1;
for (int i=0; i < 10; i++)
{
m_HandleList[i] = ObjectHandle.Zero;
m_CycleCounts[i] = 0;
}
}
// Retrieve a cookie for the passed in handle. If no cookie has yet been allocated for
// this handle, one will be created. This method is thread safe.
internal GCHandleCookie FindOrAddHandle(ObjectHandle handle)
{
// Don't accept a null object handle
if (handle == ObjectHandle.Zero)
return GCHandleCookie.Zero;
// First see if we already have a cookie for this handle.
object tempobj = null;
tempobj = m_HandleToCookieMap[handle];
if (tempobj != null)
return (GCHandleCookie)tempobj;
GCHandleCookie cookie = GCHandleCookie.Zero;
// First, try the m_FreeIndex as a quick check
int idx = m_FreeIndex;
if ((idx < m_HandleList.Length) && (m_HandleList[idx] == ObjectHandle.Zero))
{
if (Interlocked.CompareExchange(ref m_HandleList[idx], handle, ObjectHandle.Zero) == ObjectHandle.Zero)
{
cookie = GetCookieFromData((uint)idx, m_CycleCounts[idx]);
// Set our next guess just one higher if valid as this index is no longer a good guess.
if (idx+1 < m_HandleList.Length)
m_FreeIndex = idx+1;
}
}
// Free index was taken...find an empty entry in the objecthandle list and fill it with the handle
if (cookie == GCHandleCookie.Zero)
{
for (idx = 1; idx < MaxListSize; idx++)
{
// If we found an empty entry, try to use it.
if (m_HandleList[idx] == ObjectHandle.Zero)
{
if (Interlocked.CompareExchange(ref m_HandleList[idx], handle, ObjectHandle.Zero) == ObjectHandle.Zero)
{
cookie = GetCookieFromData((uint)idx, m_CycleCounts[idx]);
// Set our next guess just one higher if we ended up traversing the array.
if (idx+1 < m_HandleList.Length)
m_FreeIndex = idx+1;
break;
}
}
// Make sure we have enough space in the list to continue the search.
if (idx+1 >= m_HandleList.Length)
{
lock(this)
{
if (idx+1 >= m_HandleList.Length)
{
GrowArrays();
}
}
}
}
}
// If we overflowed the array, we're out of memory.
if (cookie == GCHandleCookie.Zero)
throw new OutOfMemoryException(Environment.GetResourceString("OutOfMemory_GCHandleMDA"));
// Now that we have a cookie - remember it in our hash table.
lock (this)
{
// First check to see if another thread already added the handle.
tempobj = m_HandleToCookieMap[handle];
if (tempobj != null)
{
// The handle has already been added so release the cookie
m_HandleList[idx] = ObjectHandle.Zero;
cookie = (GCHandleCookie)tempobj;
}
else
{
// This handle hasn't been added to the map yet so add it.
m_HandleToCookieMap[handle] = cookie;
}
}
return cookie;
}
// Get a handle.
internal ObjectHandle GetHandle(GCHandleCookie cookie)
{
ObjectHandle oh = ObjectHandle.Zero;
if (!ValidateCookie(cookie))
return ObjectHandle.Zero;
oh = m_HandleList[GetIndexFromCookie(cookie)];
return oh;
}
// Remove the handle from the cookie table if it is present.
//
// IMPORTANT: This method is NOT synchronized so the caller of this function must ensure
// it is only called once for a given handle.
internal void RemoveHandleIfPresent(ObjectHandle handle)
{
if (handle == ObjectHandle.Zero)
return;
object tempobj = m_HandleToCookieMap[handle];
if (tempobj != null)
{
GCHandleCookie cookie = (GCHandleCookie)tempobj;
// Remove it from the array first
if (!ValidateCookie(cookie))
return;
int index = GetIndexFromCookie(cookie);
m_CycleCounts[index]++;
m_HandleList[index] = ObjectHandle.Zero;
// Remove it from the hashtable last
m_HandleToCookieMap.Remove(handle);
// Update our guess
m_FreeIndex = index;
}
}
private bool ValidateCookie(GCHandleCookie cookie)
{
int index;
byte xorData;
GetDataFromCookie(cookie, out index, out xorData);
// Validate the index
if (index >= MaxListSize)
return false;
if (index >= m_HandleList.Length)
return false;
if (m_HandleList[index] == ObjectHandle.Zero)
return false;
// Validate the xorData byte (this contains the cycle count and appdomain id).
byte ADID = (byte)(AppDomain.CurrentDomain.Id % 0xFF);
byte goodData = (byte)(m_CycleCounts[index] ^ ADID);
if (xorData != goodData)
return false;
return true;
}
// Double the size of our arrays - must be called with the lock taken.
private void GrowArrays()
{
int CurrLength = m_HandleList.Length;
ObjectHandle[] newHandleList = new ObjectHandle[CurrLength*2];
byte[] newCycleCounts = new byte[CurrLength*2];
Array.Copy(m_HandleList, newHandleList, CurrLength);
Array.Copy(m_CycleCounts, newCycleCounts, CurrLength);
m_HandleList = newHandleList;
m_CycleCounts = newCycleCounts;
}
// Generate a cookie based on the index, cyclecount, and current domain id.
private GCHandleCookie GetCookieFromData(uint index, byte cycleCount)
{
byte ADID = (byte) (AppDomain.CurrentDomain.Id % 0xFF);
return (GCHandleCookie) (((cycleCount ^ ADID) << 24) + index + 1);
}
// Break down the cookie into its parts
private void GetDataFromCookie(GCHandleCookie cookie, out int index, out byte xorData)
{
uint intCookie = (uint)cookie;
index = (int)(intCookie & CookieMaskIndex) - 1;
xorData = (byte)((intCookie & CookieMaskSentinal) >> 24);
}
// Just get the index from the cookie
private int GetIndexFromCookie(GCHandleCookie cookie)
{
uint intCookie = (uint)cookie;
return (int)(intCookie & CookieMaskIndex) - 1;
}
private Hashtable m_HandleToCookieMap;
private ObjectHandle[] m_HandleList;
private byte[] m_CycleCounts;
int m_FreeIndex;
}
}
#endif
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
#if MDA_SUPPORTED
namespace System.Runtime.InteropServices
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using ObjectHandle = IntPtr;
using GCHandleCookie = IntPtr;
// Internal class used to map a GCHandle to an IntPtr. Instead of handing out the underlying CLR
// handle, we now hand out a cookie that can later be converted back to the CLR handle it
// is associated with.
internal class GCHandleCookieTable
{
private const int MaxListSize = 0xFFFFFF;
private const uint CookieMaskIndex = 0x00FFFFFF;
private const uint CookieMaskSentinal = 0xFF000000;
internal GCHandleCookieTable()
{
m_HandleList = new ObjectHandle[10];
m_CycleCounts = new byte[10];
m_HandleToCookieMap = new Hashtable();
m_FreeIndex = 1;
for (int i=0; i < 10; i++)
{
m_HandleList[i] = ObjectHandle.Zero;
m_CycleCounts[i] = 0;
}
}
// Retrieve a cookie for the passed in handle. If no cookie has yet been allocated for
// this handle, one will be created. This method is thread safe.
internal GCHandleCookie FindOrAddHandle(ObjectHandle handle)
{
// Don't accept a null object handle
if (handle == ObjectHandle.Zero)
return GCHandleCookie.Zero;
// First see if we already have a cookie for this handle.
object tempobj = null;
tempobj = m_HandleToCookieMap[handle];
if (tempobj != null)
return (GCHandleCookie)tempobj;
GCHandleCookie cookie = GCHandleCookie.Zero;
// First, try the m_FreeIndex as a quick check
int idx = m_FreeIndex;
if ((idx < m_HandleList.Length) && (m_HandleList[idx] == ObjectHandle.Zero))
{
if (Interlocked.CompareExchange(ref m_HandleList[idx], handle, ObjectHandle.Zero) == ObjectHandle.Zero)
{
cookie = GetCookieFromData((uint)idx, m_CycleCounts[idx]);
// Set our next guess just one higher if valid as this index is no longer a good guess.
if (idx+1 < m_HandleList.Length)
m_FreeIndex = idx+1;
}
}
// Free index was taken...find an empty entry in the objecthandle list and fill it with the handle
if (cookie == GCHandleCookie.Zero)
{
for (idx = 1; idx < MaxListSize; idx++)
{
// If we found an empty entry, try to use it.
if (m_HandleList[idx] == ObjectHandle.Zero)
{
if (Interlocked.CompareExchange(ref m_HandleList[idx], handle, ObjectHandle.Zero) == ObjectHandle.Zero)
{
cookie = GetCookieFromData((uint)idx, m_CycleCounts[idx]);
// Set our next guess just one higher if we ended up traversing the array.
if (idx+1 < m_HandleList.Length)
m_FreeIndex = idx+1;
break;
}
}
// Make sure we have enough space in the list to continue the search.
if (idx+1 >= m_HandleList.Length)
{
lock(this)
{
if (idx+1 >= m_HandleList.Length)
{
GrowArrays();
}
}
}
}
}
// If we overflowed the array, we're out of memory.
if (cookie == GCHandleCookie.Zero)
throw new OutOfMemoryException(Environment.GetResourceString("OutOfMemory_GCHandleMDA"));
// Now that we have a cookie - remember it in our hash table.
lock (this)
{
// First check to see if another thread already added the handle.
tempobj = m_HandleToCookieMap[handle];
if (tempobj != null)
{
// The handle has already been added so release the cookie
m_HandleList[idx] = ObjectHandle.Zero;
cookie = (GCHandleCookie)tempobj;
}
else
{
// This handle hasn't been added to the map yet so add it.
m_HandleToCookieMap[handle] = cookie;
}
}
return cookie;
}
// Get a handle.
internal ObjectHandle GetHandle(GCHandleCookie cookie)
{
ObjectHandle oh = ObjectHandle.Zero;
if (!ValidateCookie(cookie))
return ObjectHandle.Zero;
oh = m_HandleList[GetIndexFromCookie(cookie)];
return oh;
}
// Remove the handle from the cookie table if it is present.
//
// IMPORTANT: This method is NOT synchronized so the caller of this function must ensure
// it is only called once for a given handle.
internal void RemoveHandleIfPresent(ObjectHandle handle)
{
if (handle == ObjectHandle.Zero)
return;
object tempobj = m_HandleToCookieMap[handle];
if (tempobj != null)
{
GCHandleCookie cookie = (GCHandleCookie)tempobj;
// Remove it from the array first
if (!ValidateCookie(cookie))
return;
int index = GetIndexFromCookie(cookie);
m_CycleCounts[index]++;
m_HandleList[index] = ObjectHandle.Zero;
// Remove it from the hashtable last
m_HandleToCookieMap.Remove(handle);
// Update our guess
m_FreeIndex = index;
}
}
private bool ValidateCookie(GCHandleCookie cookie)
{
int index;
byte xorData;
GetDataFromCookie(cookie, out index, out xorData);
// Validate the index
if (index >= MaxListSize)
return false;
if (index >= m_HandleList.Length)
return false;
if (m_HandleList[index] == ObjectHandle.Zero)
return false;
// Validate the xorData byte (this contains the cycle count and appdomain id).
byte ADID = (byte)(AppDomain.CurrentDomain.Id % 0xFF);
byte goodData = (byte)(m_CycleCounts[index] ^ ADID);
if (xorData != goodData)
return false;
return true;
}
// Double the size of our arrays - must be called with the lock taken.
private void GrowArrays()
{
int CurrLength = m_HandleList.Length;
ObjectHandle[] newHandleList = new ObjectHandle[CurrLength*2];
byte[] newCycleCounts = new byte[CurrLength*2];
Array.Copy(m_HandleList, newHandleList, CurrLength);
Array.Copy(m_CycleCounts, newCycleCounts, CurrLength);
m_HandleList = newHandleList;
m_CycleCounts = newCycleCounts;
}
// Generate a cookie based on the index, cyclecount, and current domain id.
private GCHandleCookie GetCookieFromData(uint index, byte cycleCount)
{
byte ADID = (byte) (AppDomain.CurrentDomain.Id % 0xFF);
return (GCHandleCookie) (((cycleCount ^ ADID) << 24) + index + 1);
}
// Break down the cookie into its parts
private void GetDataFromCookie(GCHandleCookie cookie, out int index, out byte xorData)
{
uint intCookie = (uint)cookie;
index = (int)(intCookie & CookieMaskIndex) - 1;
xorData = (byte)((intCookie & CookieMaskSentinal) >> 24);
}
// Just get the index from the cookie
private int GetIndexFromCookie(GCHandleCookie cookie)
{
uint intCookie = (uint)cookie;
return (int)(intCookie & CookieMaskIndex) - 1;
}
private Hashtable m_HandleToCookieMap;
private ObjectHandle[] m_HandleList;
private byte[] m_CycleCounts;
int m_FreeIndex;
}
}
#endif
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- Debug.cs
- ContextStack.cs
- IListConverters.cs
- StylusPointPropertyId.cs
- ProviderConnectionPoint.cs
- MetadataArtifactLoaderResource.cs
- BrowserDefinition.cs
- Deflater.cs
- RangeBase.cs
- SqlDataSourceFilteringEventArgs.cs
- ValidatorCollection.cs
- XPathBinder.cs
- EventNotify.cs
- BoolExpression.cs
- HttpRuntimeSection.cs
- MimeParameters.cs
- TaskSchedulerException.cs
- InputManager.cs
- CompositionTarget.cs
- AssemblyAssociatedContentFileAttribute.cs
- FreezableOperations.cs
- LZCodec.cs
- ArglessEventHandlerProxy.cs
- DbMetaDataFactory.cs
- MappingModelBuildProvider.cs
- TemplateXamlTreeBuilder.cs
- MessageBodyMemberAttribute.cs
- DialogResultConverter.cs
- FunctionNode.cs
- PageSettings.cs
- SMSvcHost.cs
- Calendar.cs
- DataGridViewCellCancelEventArgs.cs
- ComponentCommands.cs
- DeflateEmulationStream.cs
- TextShapeableCharacters.cs
- GenericRootAutomationPeer.cs
- InvalidFilterCriteriaException.cs
- NetworkAddressChange.cs
- InternalException.cs
- ColumnPropertiesGroup.cs
- Sentence.cs
- CompositeCollection.cs
- TypeSystem.cs
- FileEnumerator.cs
- WmlSelectionListAdapter.cs
- XmlSchemaComplexType.cs
- StackOverflowException.cs
- XmlNotation.cs
- TypeUtil.cs
- FixedTextPointer.cs
- XmlSchemaCompilationSettings.cs
- GridEntry.cs
- CompiledELinqQueryState.cs
- Expression.cs
- DeviceContext2.cs
- SqlDataSourceConnectionPanel.cs
- ConstraintStruct.cs
- PartBasedPackageProperties.cs
- CopyAction.cs
- CodeEntryPointMethod.cs
- XmlUtilWriter.cs
- GridViewCellAutomationPeer.cs
- TableLayoutPanel.cs
- _emptywebproxy.cs
- HashCodeCombiner.cs
- EntityDataSourceUtil.cs
- StringBuilder.cs
- SelectionListComponentEditor.cs
- WindowsIPAddress.cs
- DispatcherHookEventArgs.cs
- EventListener.cs
- Context.cs
- sitestring.cs
- AsnEncodedData.cs
- WorkflowMarkupElementEventArgs.cs
- ExpanderAutomationPeer.cs
- CurrentChangedEventManager.cs
- DiscoveryClient.cs
- DurationConverter.cs
- CheckBoxField.cs
- WindowsRegion.cs
- MethodCallTranslator.cs
- MasterPageBuildProvider.cs
- RectangleF.cs
- Win32Native.cs
- WsdlImporterElementCollection.cs
- HttpModuleAction.cs
- XmlEncodedRawTextWriter.cs
- BamlLocalizerErrorNotifyEventArgs.cs
- _SingleItemRequestCache.cs
- StrictAndMessageFilter.cs
- NavigationWindowAutomationPeer.cs
- AppLevelCompilationSectionCache.cs
- CompressStream.cs
- DesignSurface.cs
- AuthenticationSection.cs
- CodeDirectionExpression.cs
- FilterEventArgs.cs
- DrawingDrawingContext.cs