예제 #1
0
파일: canary.cpp 프로젝트: Afshintm/coreclr
//-----------------------------------------------------------------------------
// Real OS thread proc for Canary thread.
// param - 'this' pointer for HelperCanary
// return value - meaningless, but threads need to return something.
//-----------------------------------------------------------------------------
DWORD HelperCanary::ThreadProc(LPVOID param)
{
    _ASSERTE(!ThisIsHelperThreadWorker());
    
    STRESS_LOG0(LF_CORDB, LL_ALWAYS, "Canary thread spun up\n");
    HelperCanary * pThis = reinterpret_cast<HelperCanary*> (param);    
    pThis->ThreadProc();
    _ASSERTE(pThis->m_fStop);
    STRESS_LOG0(LF_CORDB, LL_ALWAYS, "Canary thread exiting\n");

    return 0;
}
예제 #2
0
void StackFrameIterator::InternalInitForStackTrace()
{
    STRESS_LOG0(LF_STACKWALK, LL_INFO10000, "----Init---- [ StackTrace ]\n");
    Thread * pThreadToWalk = ThreadStore::GetCurrentThread();
    PTR_VOID pFrame = pThreadToWalk->GetTransitionFrameForStackTrace();
    InternalInit(pThreadToWalk, GetPInvokeTransitionFrame(pFrame));
}
예제 #3
0
void StackFrameIterator::InternalInitForEH(Thread * pThreadToWalk, PAL_LIMITED_CONTEXT * pCtx)
{
    STRESS_LOG0(LF_STACKWALK, LL_INFO10000, "----Init---- [ EH ]\n");
    StackFrameIterator::InternalInit(pThreadToWalk, pCtx, ApplyReturnAddressAdjustment);

    STRESS_LOG1(LF_STACKWALK, LL_INFO10000, "   %p\n", m_ControlPC);
}
예제 #4
0
StackFrameIterator::StackFrameIterator(Thread * pThreadToWalk, PTR_PAL_LIMITED_CONTEXT pCtx)
{
    STRESS_LOG0(LF_STACKWALK, LL_INFO10000, "----Init---- [ hijack ]\n");
    InternalInit(pThreadToWalk, pCtx, 0);
}
예제 #5
0
StackFrameIterator::StackFrameIterator(Thread * pThreadToWalk, PTR_VOID pInitialTransitionFrame)
{
    STRESS_LOG0(LF_STACKWALK, LL_INFO10000, "----Init---- [ GC ]\n");
    ASSERT(!pThreadToWalk->DangerousCrossThreadIsHijacked());
    InternalInit(pThreadToWalk, GetPInvokeTransitionFrame(pInitialTransitionFrame));
}
예제 #6
0
파일: canary.cpp 프로젝트: Afshintm/coreclr
//-----------------------------------------------------------------------------
// Does real work for AreLocksAvailable(), minus caching.
//-----------------------------------------------------------------------------
bool HelperCanary::AreLocksAvailableWorker()
{
#if _DEBUG
    // For debugging, allow a way to force the canary to fail, and thus test our 
    // failure paths.
    static BOOL fShortcut= -1;
    if (fShortcut == -1)
    {
        fShortcut = UnsafeGetConfigDWORD(CLRConfig::INTERNAL_DbgShortcutCanary);
    }
    if (fShortcut == 1)
    {
        return false;
    }
    if (fShortcut == 2)
    {
        return true;
    }
#endif

    // We used to do lazy init but that is dangerous... CreateThread
    // allocates some memory which can block on a lock, exactly the
    // situation we are attempting to detect and not block on.
    // Instead we spin up the canary in advance and if that failed then
    // assume unsafe
    if(m_CanaryThreadId == 0)
    {
        _ASSERTE(!"We shouldn't be lazy initing the canary anymore");
        return false;
    }

    // Canary will take the locks of interest and then set the Answer counter equal to our request counter. 
    m_RequestCounter = m_RequestCounter + 1;
    ResetEvent(m_hWaitEvent);
    SetEvent(m_hPingEvent);

    // Spin waiting for answer. If canary gets back to us, then the locks must be free and so it's safe for helper-thread.
    // If we timeout, then we err on the side of safety and assume canary blocked on a lock and so it's not safe
    // for the helper thread to take those locks.
    // We explicitly have a simple spin-wait instead of using win32 events because we want something simple and 
    // provably correct. Since we already need the spin-wait for the counters, adding an extra win32 event 
    // to get rid of the sleep would be additional complexity and race windows without a clear benefit.
    
    // We need to track what iteration of "AreLocksAvailable" the helper is on. Say canary sniffs two locks, now Imagine if:
    // 1) Helper calls AreLocksAvailable, 
    // 2) the canary does get blocked on lock #1, 
    // 3) process resumes, canary now gets + releases lock #1, 
    // 4) another random thread takes lock #1
    // 5) then helper calls AreLocksAvailable again later
    // 6) then the canary finally finishes. Note it's never tested lock #1 on the 2nd iteration.
    // We don't want the canary's response initiated from the 1st request to impact the Helper's 2nd request.
    // Thus we keep a request / answer counter to make sure that the canary tests all locks on the same iteration.
    DWORD retry = 0;

    const DWORD msSleepSteadyState = 150; // sleep time in ms
    const DWORD maxRetry = 15; // number of times to try. 
    DWORD msSleep = 80; // how much to sleep on first iteration. 
    
    while(m_RequestCounter != m_AnswerCounter)
    {
        retry ++;
        if (retry > maxRetry) 
        {
            STRESS_LOG0(LF_CORDB, LL_ALWAYS, "Canary timed out!\n");
            return false;
        }

        // We'll either timeout (in which case it's like a Sleep(), or
        // get the event, which shortcuts the sleep.
        WaitForSingleObject(m_hWaitEvent, msSleep);

        // In case a stale answer sets the wait event high, reset it now to avoid us doing
        // a live spin-lock.
        ResetEvent(m_hWaitEvent);

        
        msSleep = msSleepSteadyState;
    }

    // Canary made it on same Request iteration, so it must be safe!
    return true;
}