📄 umsthreadvirtualprocessor.cpp
字号:
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
//
// UMSThreadVirtualProcessor.cpp
//
// Source file containing the UMSThreadVirtualProcessor implementation.
//
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
#include "concrtinternal.h"
namespace Concurrency
{
namespace details
{
/// <summary>
/// Construct an UMS virtual processor
/// </summary>
UMSThreadVirtualProcessor::UMSThreadVirtualProcessor(SchedulingNode *pOwningNode, IVirtualProcessorRoot *pOwningRoot) :
m_pSchedulingContext(NULL)
{
// Defer to Initialize
Initialize(pOwningNode, pOwningRoot);
}
/// <summary>
/// Destroy the UMS virtual processor
/// </summary>
UMSThreadVirtualProcessor::~UMSThreadVirtualProcessor()
{
delete m_pSchedulingContext;
}
/// <summary>
/// Initializes the virtual processor. This API is called by the constructor, and when a virtual processor is to
/// be re-initialized, when it is pulled of the free pool in the list array.
/// </summary>
/// <param name="pOwningNode">
/// The owning schedule node for this virtual processor
/// </param>
/// <param name="pOwningRoot">
/// The owning IVirtualProcessorRoot
/// </param>
void UMSThreadVirtualProcessor::Initialize(SchedulingNode *pOwningNode, IVirtualProcessorRoot *pOwningRoot)
{
// Initialize the base class
VirtualProcessor::Initialize(pOwningNode, pOwningRoot);
m_pCriticalContext = NULL;
m_fCriticalIsReady = FALSE;
//
// Much as I'd love to defer these to StartupWorkerContext, it cannot be. That can be called from moving the completion list
// to runnables which *MUST* be inside a hyper-critical region to avoid deadlock in the case of blocking between grabbing
// the list and putting it on the runnables.
//
SchedulerBase *pScheduler = m_pOwningNode->GetScheduler();
if (m_pSchedulingContext != NULL)
delete m_pSchedulingContext;
m_pSchedulingContext = new UMSSchedulingContext(static_cast<UMSThreadScheduler *>(pScheduler), this);
}
/// <summary>
/// Start a worker context executing on this.virtual processor.
/// </summary>
void UMSThreadVirtualProcessor::StartupWorkerContext(ScheduleGroupBase* pGroup)
{
TRACE(TRACE_SCHEDULER, L"UMSThreadVirtualProcessor::StartupWorkerContext");
//
// This virtual processor might already have a context attached to it from the Dispatch loop, where it is waiting for work
// to come in. If this is the case, there is no need to spin off another internal context to do the work.
//
// If it does not -- there is a subtle difference between UMS utilization of the RM and Win32 thread utilization of the RM.
// The first context which we pass to the root to activate with is the scheduling context. It is a special context
// which cannot run work. When a UMS thread blocks, the scheduling context is what actively gets switched back to.
//
if (m_pExecutingContext == NULL)
{
m_pStartingGroup = pGroup;
VMTRACE(MTRACE_EVT_ACTIVATE, m_pSchedulingContext, this, SchedulerBase::FastCurrentContext());
#if _UMSTRACE
ContextBase *pCurrentContext = SchedulerBase::FastCurrentContext();
CMTRACE(MTRACE_EVT_ACTIVATE, (pCurrentContext && !pCurrentContext->IsExternal()) ? static_cast<InternalContextBase *>(pCurrentContext) : NULL, this, m_pSchedulingContext);
#endif // _UMSTRACE
m_pOwningRoot->Activate(m_pSchedulingContext);
}
else
{
Activate(m_pExecutingContext);
}
}
/// <summary>
/// Notification that a critically blocked context has come off the completion list.
/// </summary>
void UMSThreadVirtualProcessor::CriticalNotify()
{
InterlockedExchange(&m_fCriticalIsReady, TRUE);
AttemptWake();
}
/// <summary>
/// Affinitizes an internal context to the virtual processor.
/// </summary>
/// <param name="pContext">
/// The internal context to affinitize.
/// </param>
void UMSThreadVirtualProcessor::Affinitize(InternalContextBase *pContext)
{
if (pContext != NULL)
{
VirtualProcessor::Affinitize(pContext);
}
else
{
//
// We want to switch to the scheduling Context. Setting
// executingContext to NULL will accomplish that.
//
m_pExecutingContext = NULL;
}
}
/// <summary>
/// Attempts to wake the virtual processor due to a notification coming in that is critical to progress on
/// the virtual processor (e.g.: a critically blocked context coming back on the completion list from
/// another virtual processor).
/// </summary>
void UMSThreadVirtualProcessor::AttemptWake()
{
if (ClaimExclusiveOwnership())
{
CORE_ASSERT(m_pExecutingContext != NULL);
Activate(m_pExecutingContext);
}
}
/// <summary>
/// Makes a virtual processor available for scheduling work. This can only be called from the scheduling
/// context.
/// </summary>
void UMSThreadVirtualProcessor::MakeAvailableFromSchedulingContext()
{
//
// This makes the virtual processor available for wake/sleep *FROM* the scheduling context.
//
m_pExecutingContext = m_pSchedulingContext;
MakeAvailable();
}
/// <summary>
/// Indicates if a virtual processor is deactivated waiting for a SFW context
/// </summary>
bool UMSThreadVirtualProcessor::IsWaitingForReservedContext()
{
// If the deactivate call came from scheduling context, then we are
// waiting for an SFW context.
return (m_pExecutingContext == m_pSchedulingContext);
}
/// <summary>
/// Returns a type-cast of pContext to an InternalContextBase or NULL if it is not.
/// </summary>
InternalContextBase *UMSThreadVirtualProcessor::ToInternalContext(IExecutionContext *pContext)
{
if (pContext == m_pSchedulingContext)
return NULL;
else
return static_cast<InternalContextBase *>(pContext);
}
/// <summary>
/// Stub called in SFW before we search for runnable contexts.
/// </summary>
/// <returns>
/// A context which should be run.
/// </returns>
InternalContextBase *UMSThreadVirtualProcessor::PreRunnableSearch()
{
UMSThreadScheduler *pScheduler = static_cast<UMSThreadScheduler *>(m_pOwningNode->GetScheduler());
pScheduler->MoveCompletionListToRunnables(this);
return NULL;
}
} // namespace details
} // namespace Concurrency
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -