📄 resourcemanager.cpp
字号:
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
//
// ResourceManager.cpp
//
// Implementation of IResourceManager.
//
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
#include "concrtinternal.h"
#include <float.h>
#include <algorithm>
namespace Concurrency
{
/// <summary>
/// Returns the OS version.
/// </summary>
_CRTIMP IResourceManager::OSVersion GetOSVersion()
{
return ::Concurrency::details::ResourceManager::Version();
}
/// <summary>
/// Returns an interface that represents the singleton resource manager instance. The API references the
/// resource manager, and must be matched by a call to IResourceManager::Release(), when the caller is done.
/// </summary>
_CRTIMP IResourceManager* CreateResourceManager()
{
return ::Concurrency::details::ResourceManager::CreateSingleton();
}
/// <summary>
/// The number of hardware threads on the underlying machine is returned here.
/// </summary>
_CRTIMP unsigned int GetProcessorCount()
{
return ::Concurrency::details::ResourceManager::GetCoreCount();
}
/// <summary>
/// The number of NUMA nodes or processor packages on the underlying machine is returned here.
/// If the processor contains more NUMA nodes than processor packages, the number of NUMA nodes
/// is returned, otherwise the number of packages is returned.
/// </summary>
_CRTIMP unsigned int GetProcessorNodeCount()
{
return ::Concurrency::details::ResourceManager::GetNodeCount();
}
/// <summary>
/// Returns an identifier for a scheduler. Before calling an API with an IScheduler interface as a parameter,
/// an identifier must be obtained for the scheduler using this API.
/// </summary>
_CRTIMP unsigned int GetSchedulerId()
{
return ::Concurrency::details::ResourceManager::GetSchedulerId();
}
/// <summary>
/// Returns an identifier for an execution context. Before calling an API with an IExecutionContext interface as a parameter,
/// an identifier must be obtained for the execution context using this API.
/// </summary>
_CRTIMP unsigned int GetExecutionContextId()
{
return ::Concurrency::details::ResourceManager::GetExecutionContextId();
}
}
namespace Concurrency
{
namespace details
{
// Static counters to generate unique identifiers.
volatile LONG ResourceManager::s_schedulerIdCount = -1L;
volatile LONG ResourceManager::s_executionContextIdCount = -1L;
volatile LONG ResourceManager::s_threadProxyIdCount = -1L;
// Operating system characteristics.
unsigned int ResourceManager::s_physicalProcessorCount = 0;
unsigned int ResourceManager::s_packageCount = 0;
unsigned int ResourceManager::s_nodeCount = 0;
IResourceManager::OSVersion ResourceManager::s_version = IResourceManager::UnsupportedOS;
bool ResourceManager::s_fNativeX64 = false;
bool ResourceManager::s_fRequireUMSWorkaround = false;
volatile LONG ResourceManager::s_terminating = 0;
ResourceManager *ResourceManager::s_pResourceManager = NULL;
// Variables used to obtain information about the topology of the system.
DWORD ResourceManager::s_logicalProcessorInformationLength = 0;
PSYSTEM_LOGICAL_PROCESSOR_INFORMATION ResourceManager::s_pSysInfo = NULL;
// The encoded pointer to the SetThreadGroupAffinity function used for Win7 and higher
HardwareAffinity::PFnSetThreadGroupAffinity HardwareAffinity::s_pfnSetThreadGroupAffinity = NULL;
// The encoded pointer to the GetThreadGroupAffinity function used for Win7 and higher
HardwareAffinity::PFnGetThreadGroupAffinity HardwareAffinity::s_pfnGetThreadGroupAffinity = NULL;
// The encoded pointer to the GetCurrentProcessorNumberEx function used for Win7 and higher
ResourceManager::PFnGetCurrentProcessorNumberEx ResourceManager::s_pfnGetCurrentProcessorNumberEx = NULL;
/// <summary>
/// Constructs a hardware affinity from a given thread.
/// </summary>
HardwareAffinity::HardwareAffinity(HANDLE hThread)
{
memset(&m_affinity, 0, sizeof(m_affinity));
if (::Concurrency::GetOSVersion() == ::Concurrency::IResourceManager::Win7OrLater ||
::Concurrency::GetOSVersion() == ::Concurrency::IResourceManager::UmsThreadAwareOS)
{
PFnGetThreadGroupAffinity fnDecodedFunction = (PFnGetThreadGroupAffinity) Security::DecodePointer(s_pfnGetThreadGroupAffinity);
VERIFY(fnDecodedFunction(hThread, &m_affinity));
}
else
{
// On operating systems older than Win7, we don't have access to the correct information about thread's affinity,
// so we will assume that the affinity is that of the process.
DWORD_PTR pProcessAffinityMask;
DWORD_PTR pSystemAffinityMask;
GetProcessAffinityMask(GetCurrentProcess(), &pProcessAffinityMask, &pSystemAffinityMask);
m_affinity.Group = 0;
m_affinity.Mask = pProcessAffinityMask;
}
}
/// <summary>
/// Applies this hardware affinity to a thread.
/// </summary>
/// <param name="hThread">
/// The thread handle to which to apply this affinity.
/// </param>
void HardwareAffinity::ApplyTo(HANDLE hThread)
{
if (::Concurrency::GetOSVersion() == ::Concurrency::IResourceManager::Win7OrLater ||
::Concurrency::GetOSVersion() == ::Concurrency::IResourceManager::UmsThreadAwareOS)
{
PFnSetThreadGroupAffinity fnDecodedFunction = (PFnSetThreadGroupAffinity) Security::DecodePointer(s_pfnSetThreadGroupAffinity);
VERIFY(fnDecodedFunction(hThread, &m_affinity, NULL));
}
else
{
VERIFY(SetThreadAffinityMask(hThread, m_affinity.Mask));
}
}
/// <summary>
/// Called to initialize the SetThreadGroupAffinity function
/// </summary>
void HardwareAffinity::InitializeSetThreadGroupAffinityFn()
{
// Get the SetThreadGroupAffinity function for Win7
PFnSetThreadGroupAffinity pfnSetFunction = (PFnSetThreadGroupAffinity) GetProcAddress(GetModuleHandleW(L"kernel32.dll"),
"SetThreadGroupAffinity");
PFnGetThreadGroupAffinity pfnGetFunction = (PFnGetThreadGroupAffinity) GetProcAddress(GetModuleHandleW(L"kernel32.dll"),
"GetThreadGroupAffinity");
if (pfnSetFunction == NULL || pfnGetFunction == NULL)
{
throw scheduler_resource_allocation_error(HRESULT_FROM_WIN32(GetLastError()));
}
s_pfnSetThreadGroupAffinity = (PFnSetThreadGroupAffinity) Security::EncodePointer(pfnSetFunction);
s_pfnGetThreadGroupAffinity = (PFnGetThreadGroupAffinity) Security::EncodePointer(pfnGetFunction);
}
/// <summary>
/// Returns the OS version.
/// </summary>
IResourceManager::OSVersion ResourceManager::Version()
{
if (s_version == ::Concurrency::IResourceManager::UnsupportedOS)
{
{ // begin locked region
_StaticLock::_Scoped_lock lock(s_lock);
if (s_version == ::Concurrency::IResourceManager::UnsupportedOS)
{
InitializeSystemInformation();
}
} // end locked region
}
return s_version;
}
/// <summary>
/// Returns the number of nodes (processor packages or NUMA nodes, whichever is greater)
/// </summary>
unsigned int ResourceManager::GetNodeCount()
{
if (s_nodeCount == 0)
{
{ // begin locked region
_StaticLock::_Scoped_lock lock(s_lock);
if (s_nodeCount == 0)
{
InitializeSystemInformation();
}
} // end locked region
}
return (s_nodeCount >= s_packageCount) ? s_nodeCount : s_packageCount;
}
/// <summary>
/// Returns the number of cores.
/// </summary>
unsigned int ResourceManager::GetCoreCount()
{
if (s_physicalProcessorCount == 0)
{
{ // begin locked region
_StaticLock::_Scoped_lock lock(s_lock);
if (s_physicalProcessorCount == 0)
{
InitializeSystemInformation();
}
} // end locked region
}
return s_physicalProcessorCount;
}
/// <summary>
/// Returns the current thread's node id and core id (relative to that node).
/// </summary>
unsigned int ResourceManager::GetCurrentNodeAndCore(unsigned int * pCore)
{
if (::Concurrency::GetOSVersion() == ::Concurrency::IResourceManager::Win7OrLater ||
::Concurrency::GetOSVersion() == ::Concurrency::IResourceManager::UmsThreadAwareOS)
{
// For Win7 or later, we can use a simple function
PROCESSOR_NUMBER procNum;
PFnGetCurrentProcessorNumberEx fnDecodedFunction = (PFnGetCurrentProcessorNumberEx) Security::DecodePointer(s_pfnGetCurrentProcessorNumberEx);
fnDecodedFunction(&procNum);
DWORD processorNumber = procNum.Number;
ULONG_PTR processorAffinity = 1 << processorNumber;
for (unsigned int nodeIndex = 0; nodeIndex < m_nodeCount; nodeIndex++)
{
GlobalNode * pNode = &m_pGlobalNodes[nodeIndex];
if ((pNode->m_processorGroup == procNum.Group) && ((pNode->m_nodeAffinity & processorAffinity) != 0))
{
for (unsigned int coreIndex = 0; coreIndex < pNode->m_coreCount; coreIndex++)
{
if (pNode->m_pCores[coreIndex].m_processorNumber == processorNumber)
{
if (pCore != NULL)
{
*pCore = coreIndex;
}
return nodeIndex;
}
}
}
}
ASSERT(UNREACHED);
return 0;
}
else if (::Concurrency::GetOSVersion() == ::Concurrency::IResourceManager::Win2k3 ||
::Concurrency::GetOSVersion() == ::Concurrency::IResourceManager::Vista)
{
// For Win2k3 or Vista, we need to compute the node id and core id from the absolute processor id
typedef DWORD (WINAPI *PFnGetCurrentProcessorNumber)(VOID);
PFnGetCurrentProcessorNumber pFnGetCurrentProcessorNumber
= (PFnGetCurrentProcessorNumber) GetProcAddress(GetModuleHandleW(L"kernel32.dll"),
"GetCurrentProcessorNumber");
if (pFnGetCurrentProcessorNumber == NULL)
{
throw scheduler_resource_allocation_error(HRESULT_FROM_WIN32(GetLastError()));
}
DWORD processorNumber = pFnGetCurrentProcessorNumber();
ULONG_PTR processorAffinity = 1 << processorNumber;
for (unsigned int nodeIndex = 0; nodeIndex < m_nodeCount; nodeIndex++)
{
GlobalNode * pNode = &m_pGlobalNodes[nodeIndex];
if ((pNode->m_nodeAffinity & processorAffinity) != 0)
{
for (unsigned int coreIndex = 0; coreIndex < pNode->m_coreCount; coreIndex++)
{
if (pNode->m_pCores[coreIndex].m_processorNumber == processorNumber)
{
if (pCore != NULL)
{
*pCore = coreIndex;
}
return nodeIndex;
}
}
}
}
ASSERT(UNREACHED);
return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -