when i read the source code , i wonder, if the gc is trigger when one preemptive disable thread fall into the code (exactly method ofSpinUntil which is higlight as below),that will cause the app hang ,because all preemptive enabel threads is suspend, no handle is create or free.
------Handletablecache.cpp------------
void SyncTransferCacheHandles(OBJECTHANDLE *pDst, OBJECTHANDLE *pSrc, UINT uCount)
{
WRAPPER_CONTRACT;
/*
NOTHROW;
GC_NOTRIGGER;
MODE_ANY;
*/
// set up to loop
// we loop backwards since that is the order handles are added to the bank
// this is designed to reduce the chance that we will have to spin on a handle
OBJECTHANDLE *pBase = pDst;
pSrc += uCount;
pDst += uCount;
// loop until we've copied all of them
while (pDst > pBase)
{
// advance to the next slot
pDst--;
pSrc--;
// this version spins if there is no handle to read or no place to write it
if (*pDst || !*pSrc)
{
SpinUntil(pSrc, TRUE);
SpinUntil(pDst, FALSE);
}
// copy the handle and zero it from the source
*pDst = *pSrc;
*pSrc = 0;
}
}
void SpinUntil(void *pCond, BOOL fNonZero)
{
WRAPPER_CONTRACT;
/*
NOTHROW;
GC_NOTRIGGER;
MODE_ANY;
*/
// if we have to sleep then we will keep track of a sleep period
DWORD dwThisSleepPeriod = 1; // first just give up our timeslice
DWORD dwNextSleepPeriod = 10; // next try a real delay
#ifdef _DEBUG
DWORD dwTotalSlept = 0;
DWORD dwNextComplain = 1000;
#endif //_DEBUG
// on MP machines, allow ourselves some spin time before sleeping
UINT uNonSleepSpins = 8 * (g_SystemInfo.dwNumberOfProcessors - 1);
// spin until the specificed condition is met
while ((*(UINT_PTR *)pCond != 0) != (fNonZero != 0))
{
// have we exhausted the non-sleep spin count?
if (!uNonSleepSpins)
{
#ifdef _DEBUG
// yes, missed again - before sleeping, check our current sleep time
if (dwTotalSlept >= dwNextComplain)
{
//
// THIS SHOULD NOT NORMALLY HAPPEN
//
// The only time this assert can be ignored is if you have
// another thread intentionally suspended in a way that either
// directly or indirectly leaves a thread suspended in the
// handle table while the current thread (this assert) is
// running normally.
//
// Otherwise, this assert should be investigated as a bug.
//
_ASSERTE(FALSE);
// slow down the assert rate so people can investigate
dwNextComplain = 3 * dwNextComplain;
}
// now update our total sleep time
dwTotalSlept += dwThisSleepPeriod;
#endif //_DEBUG
// sleep for a little while
__SwitchToThread(dwThisSleepPeriod);
// now update our sleep period
dwThisSleepPeriod = dwNextSleepPeriod;
// now increase the next sleep period if it is still small
if (dwNextSleepPeriod < 1000)
dwNextSleepPeriod += 10;
}
else
{
// nope - just spin again
YieldProcessor(); // indicate to the processor that we are spining
uNonSleepSpins--;
}
}
}