📄 contextbase.cpp
字号:
/// <summary>
/// When schedulers are nested on the same thread, the nested scheduler creates a new external context that overrides
/// the previous context. PopContextFromTls will restore the previous context by setting the TLS value appropriately.
/// </summary>
ContextBase* ContextBase::PopContextFromTls()
{
ContextBase* pPreviousContext = m_pParentContext;
TlsSetValue(SchedulerBase::t_dwContextIndex, pPreviousContext);
m_pParentContext = NULL;
return pPreviousContext;
}
/// <summary>
/// When schedulers are nested on the same thread, the nested scheduler creates a new external context that overrides
/// the previous context. PushContextToTls will store the previous context and set the new context into TLS.
/// </summary>
void ContextBase::PushContextToTls(ContextBase* pParentContext)
{
m_pParentContext = pParentContext;
// For the first context on a thread, we expect the TLS values to be null. If there is a parent context,
// the TLS value should have been cleared right before nesting.
ASSERT(TlsGetValue(SchedulerBase::t_dwContextIndex) == NULL);
TlsSetValue(SchedulerBase::t_dwContextIndex, this);
}
/// <summary>
/// Context TLS is cleared during nesting on internal contexts before the external context TLS is correctly setup. If not,
/// code that executes between the clear and setting the new TLS could get confused.
/// </summary>
void ContextBase::ClearContextTls()
{
ASSERT(TlsGetValue(SchedulerBase::t_dwContextIndex) != NULL);
TlsSetValue(SchedulerBase::t_dwContextIndex, NULL);
}
/// <summary>
/// Returns the scheduler the specified context is associated with.
/// </summary>
SchedulerBase* ContextBase::GetScheduler() const
{
return m_pScheduler;
}
/// <summary>
/// Returns the schedule group the specified context is associated with.
/// </summary>
ScheduleGroupBase* ContextBase::GetScheduleGroup() const
{
return m_pGroup;
}
/// <summary>
/// Gets the indirect alias.
/// </summary>
Concurrency::details::_TaskCollection *ContextBase::GetIndirectAlias() const
{
return m_pIndirectAlias;
}
/// <summary>
/// Sets the indirect alias.
/// </summary>
void ContextBase::SetIndirectAlias(_TaskCollection *pAlias)
{
m_pIndirectAlias = pAlias;
}
/// <summary>
/// Sweeps the alias table removing anything that's marked for delete. This is done every time we create a new direct alias
/// in order to avoid growing the table arbitrarily for a context which isn't going away. Note -- passing a task collection between
/// threads is expensive the first time it's used.
/// </summary>
void ContextBase::SweepAliasTable()
{
int x;
Hash<_TaskCollection*, _TaskCollection*>::ListNode *pNode = m_aliasTable.First(&x);
while (pNode != NULL)
{
Hash<_TaskCollection*, _TaskCollection*>::ListNode *pNextNode = m_aliasTable.Next(&x, pNode);
if (pNode->m_value->_IsStaleAlias())
{
_TaskCollection *pCollection = pNode->m_value;
m_aliasTable.Delete(pCollection->_OriginalCollection()); // may delete pNode
delete pCollection;
}
pNode = pNextNode;
}
}
/// <summary>
/// Clears the alias table.
/// </summary>
void ContextBase::ClearAliasTable()
{
int x;
Hash<_TaskCollection*, _TaskCollection*>::ListNode *pNode = m_aliasTable.First(&x);
while (pNode != NULL)
{
pNode->m_value->_ReleaseAlias();
pNode = m_aliasTable.Next(&x, pNode);
}
m_aliasTable.Wipe();
}
/// <summary>
/// Called in order to indicate that a collection executing on this context was canceled. This will often cause cancellation
/// and unwinding of the entire context (up to the point where we get to the canceled collection.
/// </summary>
void ContextBase::CancelCollection(int inliningDepth)
{
InterlockedIncrement(&m_canceledCount);
long curDepth = m_minCancellationDepth;
//
// Keep track of the minimum cancellation depth.
//
for(;;)
{
if (curDepth != -1 && inliningDepth > curDepth)
break;
long xchgDepth = InterlockedCompareExchange(&m_minCancellationDepth, inliningDepth, curDepth);
if (xchgDepth == curDepth)
break;
curDepth = xchgDepth;
}
}
/// <summary>
/// When a cancellation bubbles up to the collection being canceled, this function is called in order to stop propagation of
/// the cancellation further up the work tree.
/// </summary>
bool ContextBase::CollectionCancelComplete(int inliningDepth)
{
ASSERT(m_canceledCount > 0);
//
// Keep track of minimum cancellation depth.
//
InterlockedCompareExchange(&m_minCancellationDepth, -1, inliningDepth);
return (InterlockedDecrement(&m_canceledCount) == 0);
}
/// <summary>
/// Send a context ETW event.
/// </summary>
void ContextBase::ThrowContextEvent(ConcRT_EventType eventType, UCHAR level, DWORD schedulerId, DWORD contextId)
{
if (g_pEtw != NULL)
{
CONCRT_TRACE_EVENT_HEADER_COMMON concrtHeader = {0};
concrtHeader.header.Size = sizeof concrtHeader;
concrtHeader.header.Flags = WNODE_FLAG_TRACED_GUID;
concrtHeader.header.Class.Type = (UCHAR)eventType;
concrtHeader.header.Class.Level = level;
concrtHeader.header.Guid = ContextEventGuid;
concrtHeader.SchedulerID = schedulerId;
concrtHeader.ContextID = contextId;
g_pEtw->Trace(g_ConcRTSessionHandle, &concrtHeader.header);
}
}
/// <summary>
/// Enters a critical region of the scheduler. Calling this guarantees that the virtual processor on which this context lives
/// is guaranteed to be stable throughout the critical region. For some context types, this is virtually a NOP. For others
/// (UMS), this makes it appear that blocking on the context actually blocks the UMS thread instead of triggering return to
/// primary. Note that critical regions suppress asynchronous blocking but not synchronous blocking.
/// </summary>
int ContextBase::EnterCriticalRegion()
{
if (m_pScheduler->IsUMSScheduler())
{
return EnterCriticalRegionHelper();
}
return 0;
}
/// <summary>
/// Exits a critical region of the scheduler.
/// </summary>
int ContextBase::ExitCriticalRegion()
{
if (m_pScheduler->IsUMSScheduler())
{
return ExitCriticalRegionHelper();
}
return 0;
}
/// <summary>
/// Enters a hyper-critical region of the scheduler. Calling this guarantees not only the conditions of a critical region but it
/// guarantees that synchronous blocking is suppressed as well. This allows for lock sharing between the primary and hyper-critical
/// regions running on UTs. No lock sharing can occur between the inside of this region type and the outside of this region type
/// on a UT.
/// </summary>
int ContextBase::EnterHyperCriticalRegion()
{
if (m_pScheduler->IsUMSScheduler())
{
return EnterHyperCriticalRegionHelper();
}
return 0;
}
/// <summary>
/// Exits a hyper-critical region of the scheduler.
/// </summary>
int ContextBase::ExitHyperCriticalRegion()
{
if (m_pScheduler->IsUMSScheduler())
{
return ExitHyperCriticalRegionHelper();
}
return 0;
}
/// <summary>
/// Static version of EnterCriticalRegion.
/// </summary>
void ContextBase::StaticEnterCriticalRegion()
{
ContextBase *pContext = SchedulerBase::FastCurrentContext();
if (pContext != NULL)
pContext->EnterCriticalRegion();
}
/// <summary>
/// Static version of EnterHyperCriticalRegion.
/// </summary>
void ContextBase::StaticEnterHyperCriticalRegion()
{
ContextBase *pContext = SchedulerBase::FastCurrentContext();
if (pContext != NULL)
pContext->EnterHyperCriticalRegion();
}
/// <summary>
/// Static version of ExitCriticalRegion.
/// </summary>
void ContextBase::StaticExitCriticalRegion()
{
ContextBase *pContext = SchedulerBase::FastCurrentContext();
if (pContext != NULL)
pContext->ExitCriticalRegion();
}
/// <summary>
/// Static version of ExitHyperCriticalRegion.
/// </summary>
void ContextBase::StaticExitHyperCriticalRegion()
{
ContextBase *pContext = SchedulerBase::FastCurrentContext();
if (pContext != NULL)
pContext->ExitHyperCriticalRegion();
}
/// <summary>
/// Static version of GetCriticalRegionType.
/// </summary>
CriticalRegionType ContextBase::StaticGetCriticalRegionType()
{
ContextBase *pContext = SchedulerBase::FastCurrentContext();
if (pContext != NULL)
return pContext->GetCriticalRegionType();
return OutsideCriticalRegion;
}
/// <summary>
/// Since critical region counts are turned off for thread schedulers, this method is used
/// where the return value is expected to be true. For a thread scheduler, it always returns true.
/// For a UMS scheduler it returns (GetCriticalRegionType() != OutsideCriticalRegion).
/// </summary>
bool ContextBase::IsInsideCriticalRegion() const
{
if (m_pScheduler->IsUMSScheduler())
return (GetCriticalRegionType() != OutsideCriticalRegion);
return true;
}
} // namespace details
} // namespace Concurrency
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -