Beispiel #1
0
//=========================================================================
// Asserts if lock mode is PREEMPTIVE and thread in a GC_NOTRIGGER contract
//=========================================================================        
void SimpleRWLock::CheckGCNoTrigger()
{
    STATIC_CONTRACT_NOTHROW;

    // On PREEMPTIVE locks we'll toggle the GC mode, so we better not be in a GC_NOTRIGGERS region
    if (m_gcMode == PREEMPTIVE)
    {
        ClrDebugState *pClrDebugState = CheckClrDebugState();
        if (pClrDebugState)
        {
            if (pClrDebugState->GetGCNoTriggerCount())
            {
                // If we have no thread object, we won't be toggling the GC.  This is the case, 
                // for example, on the debugger helper thread which is always GC_NOTRIGGERS.
                if (GetThreadNULLOk() != NULL) 
                {
                    if (!( (GCViolation|BadDebugState) & pClrDebugState->ViolationMask()))
                    {
                        CONTRACT_ASSERT("You cannot enter a lock in a GC_NOTRIGGER region.",
                                        Contract::GC_NoTrigger,
                                        Contract::GC_Mask,
                                        __FUNCTION__,
                                        __FILE__,
                                        __LINE__);
                    }
                }
            }

            // The mode checks and enforcement of GC_NOTRIGGER during the lock are done in SimpleRWLock::PostEnter().
        }
    }
}
Beispiel #2
0
// This is effectively an implicit probe, because we are guaranteeing that we have
// enought stack to run and will not take an SO.  So we enter SO-intolerant code when
// we install one of these.
BaseStackMarker::BaseStackMarker(float numPages, BOOL fAllowDisabling)
    : m_prevWasSOTolerant(FALSE), m_pDebugState(CheckClrDebugState()), m_fMarkerSet(FALSE)
    , m_fTemporarilyDisabled(FALSE), m_fAddedToStack(FALSE), m_pPrevious(NULL)
    , m_numPages(0.0), m_pMarker(NULL)
    , m_fProtectedStackPage(FALSE), m_fAllowDisabling(fAllowDisabling)
{
    WRAPPER_CONTRACT;
    STATIC_CONTRACT_DEBUG_ONLY;

    // If backout stack validation isn't enabled then we are done.
    if (!g_EnableBackoutStackValidation)
    {
        return;
    }

    // If we can't talk to other markers then the markers could get in each others way
    if (!m_pDebugState)
    {
        return;
    }

    // Allow only the lowest marker to be active at any one time. Yes, this means that
    // the stack will only ever have one element in it. However having multiple markers
    // is problematic for debugging and conflicts with the VirtualProtect option. It
    // adds little value, in that small backout checks stop happening in exception
    // codepaths, but these get plenty of coverage in success cases and the lowest
    // placed marked is the one that could actually indicate a stack overflow.
    if (!m_pDebugState->m_StackMarkerStack.IsEmpty())
    {
        return;
    }

    // Switch the SO tolerance mode
    m_prevWasSOTolerant = m_pDebugState->SetSOTolerance(FALSE);

    // If we have less then numPages left before the end of the stack then there is
    // no point in adding a marker since we will take an SO anyway if we use too much
    // stack. Putting the marker is actually very bad since it artificially forces an
    // SO in cases where it wouldn't normally occur if we use less than num pages of stack.
    if (g_fpCheckNStackPagesAvailable &&
            !g_fpCheckNStackPagesAvailable(numPages < 1 ? 1 : (unsigned int)numPages))
    {
        return;
    }

    if (m_fAllowDisabling)
    {
        // Push ourselves on to the stack of stack markers on the CLR debug state.
        m_pDebugState->m_StackMarkerStack.PushStackMarker(this);
        m_fAddedToStack = TRUE;
    }

    // Set the actual stack guard marker if we have enough stack to do so.
    SetMarker(numPages);

    if (m_fMarkerSet && m_fAllowDisabling)
    {
        ProtectMarkerPageInDebugger();
    }
}