📄 executionresource.cpp
字号:
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
//
// ExecutionResource.cpp
//
// Part of the ConcRT Resource Manager -- this file contains the internal implementation for the execution
// resource.
//
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
#include "concrtinternal.h"
namespace Concurrency
{
namespace details
{
/// <summary>
/// Constructs a new execution resource.
/// </summary>
/// <param name="pSchedulerProxy">
/// The scheduler proxy this resource is created for. A scheduler proxy holds RM data associated with an instance of
/// a scheduler.
/// <param name="pNode">
/// The processor node that this resource belongs to. The processor node is one among the nodes allocated to the
/// scheduler proxy.
/// </param>
/// <param name="coreIndex">
/// The index into the array of cores for the processor node specified.
/// </param>
ExecutionResource::ExecutionResource(SchedulerProxy * pSchedulerProxy, SchedulerNode* pNode, unsigned int coreIndex) :
m_pVirtualProcessorRoot(NULL),
m_tlsResetValue(0),
m_numThreadSubscriptions(0),
m_pSchedulerProxy(pSchedulerProxy),
m_nodeId(pNode->m_id),
m_coreIndex(coreIndex),
m_pParentExecutionResource(NULL)
{
// Derive the execution resource id from the node and the core.
m_executionResourceId = ((int)(pNode->m_processorGroup) << 8) + pNode->m_pCores[coreIndex].m_processorNumber;
}
/// <summary>
/// Constructs a new execution resource.
/// </summary>
/// <param name="pSchedulerProxy">
/// The scheduler proxy this resource is created for. A scheduler proxy holds RM data associated with an instance of
/// a scheduler.
/// <param name="pParentExecutionResource">
/// The parent execution resource representing this thread. If there was already an execution resource on the
/// calling thread that was created in a different scheduler, it becomes the parent of this execution resource.
/// </param>
ExecutionResource::ExecutionResource(SchedulerProxy * pSchedulerProxy, ExecutionResource * pParentExecutionResource) :
m_pVirtualProcessorRoot(NULL),
m_tlsResetValue(0),
m_numThreadSubscriptions(0),
m_pSchedulerProxy(pSchedulerProxy),
m_nodeId(pParentExecutionResource->GetNodeId()),
m_coreIndex(pParentExecutionResource->GetCoreIndex()),
m_pParentExecutionResource(pParentExecutionResource)
{
m_executionResourceId = pParentExecutionResource->GetExecutionResourceId();
}
/// <summary>
/// Called to indicate that a scheduler is done with an execution resource and wishes to return it to the resource manager.
/// </summary>
/// <param name="pScheduler">
/// The scheduler making the request to remove this execution resource.
/// </param>
void ExecutionResource::Remove(IScheduler *pScheduler)
{
if (pScheduler == NULL)
{
throw std::invalid_argument("pScheduler");
}
// Remove must be called on the same thread that called SubscribeCurrentThread.
ExecutionResource * pExecutionResource = m_pSchedulerProxy->GetCurrentThreadExecutionResource();
if (pExecutionResource != this)
{
throw invalid_operation();
}
// The scheduler proxy should match the scheduler calling remove.
if (m_pSchedulerProxy->Scheduler() != pScheduler)
{
throw invalid_operation();
}
m_pSchedulerProxy->GetResourceManager()->RemoveExecutionResource(this);
}
/// <summary>
/// Set this execution resource as current on this thread
/// </summary>
void ExecutionResource::SetAsCurrent()
{
// Save the information about this execution resource in the TLS for nested SubscribeCurrentThread calls.
DWORD tlsSlot = m_pSchedulerProxy->GetResourceManager()->GetExecutionResourceTls();
m_tlsResetValue = (size_t) TlsGetValue(tlsSlot);
ASSERT((void *) m_tlsResetValue != (void *)this);
TlsSetValue(tlsSlot, this);
}
/// <summary>
/// Clear the current execution resource on this thread.
/// </summary>
void ExecutionResource::ResetCurrent()
{
DWORD tlsSlot = m_pSchedulerProxy->GetResourceManager()->GetExecutionResourceTls();
TlsSetValue(tlsSlot, (void *) m_tlsResetValue);
m_tlsResetValue = 0;
}
/// <summary>
/// Increments the number of external threads that run on this execution resource as well as
/// the number of fixed threads that are running on the underlying core.
/// </summary>
/// <remarks>
/// This information is used to validate matching SubscribeCurrentThread/Release calls, as well as
/// to mark a core on which this resource runs as fixed (not-movable).
/// </remarks>
void ExecutionResource::IncrementUseCounts()
{
// The RM LOCK needs to be held before calling this routine
if (m_numThreadSubscriptions++ == 0)
{
// For an execution resources associated with a vproc, the threadsubscription count is expected to
// go from 0 to 1 when a context running on that vproc subscribes a thread to the scheduler it is running
// on or a different scheduler.
// For an execution resource *not* associated with a vproc, the threadsubscription count is expected to
// go from 0 to 1 when it is created.
bool isVPRoot = (m_pVirtualProcessorRoot != NULL);
if (m_pParentExecutionResource == NULL)
{
// Mark on the core that this execution resource has added a new reference
m_pSchedulerProxy->IncrementFixedCoreCount(m_nodeId, m_coreIndex, !isVPRoot);
if (!isVPRoot)
{
// Save old affinity
HANDLE hThread = GetCurrentThread();
m_oldAffinity = HardwareAffinity(hThread);
// Affinitize this thread to a given node
HardwareAffinity newAffinity = m_pSchedulerProxy->GetNodeAffinity(m_nodeId);
newAffinity.ApplyTo(hThread);
m_pSchedulerProxy->IncrementCoreSubscription(this);
m_pSchedulerProxy->AddExecutionResource(this);
}
}
else
{
ASSERT(!isVPRoot);
m_pSchedulerProxy->AddThreadSubscription(this);
}
SetAsCurrent();
}
}
/// <summary>
/// Called to update the proxy counts, which must be done under the RM lock.
/// </summary>
void ExecutionResource::DecrementUseCounts()
{
// The RM LOCK needs to be held before calling this routine
ASSERT(m_numThreadSubscriptions > 0);
// This particular call does not have to worry about the RM receiving a SchedulerShutdown for the scheduler proxy in question.
if (--m_numThreadSubscriptions == 0)
{
bool isVPRoot = (m_pVirtualProcessorRoot != NULL);
// Reset the TLS to the previous state.
// The previous state could be either NULL (if this was not an external threads first subscription),
// a pointer to a thread proxy (it if was originally a vproc), or a parent execution resource (if this
// was a nested execution resource).
ResetCurrent();
if (m_pParentExecutionResource == NULL)
{
// Mark on the core that this execution resource has removed one of its references
m_pSchedulerProxy->DecrementFixedCoreCount(m_nodeId, m_coreIndex, !isVPRoot);
if (!isVPRoot)
{
m_oldAffinity.ApplyTo(GetCurrentThread());
m_pSchedulerProxy->DecrementCoreSubscription(this);
m_pSchedulerProxy->DestroyExecutionResource(this);
}
}
else
{
ASSERT(!isVPRoot);
m_pParentExecutionResource->DecrementUseCounts();
m_pSchedulerProxy->RemoveThreadSubscription(this);
}
}
}
/// <summary>
/// Returns the subscription level on the core that this execution resource represents
/// </summary>
/// <returns>
/// A current subscription level of the underlying execution resource.
/// </returns>
unsigned int ExecutionResource::CurrentSubscriptionLevel() const
{
return m_pSchedulerProxy->GetResourceManager()->CurrentSubscriptionLevel(m_nodeId, m_coreIndex);
}
} // namespace details
} // namespace Concurrency
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -