// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
//
// location.cpp
//
// Implementation file of the metaphor for a location.
//
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
#include "concrtinternal.h"
namespace Concurrency
{
typedef BOOL (WINAPI *PFN_GetNumaNodeNumberFromHandle)(HANDLE, PUSHORT);
///
/// Constructs a specific location.
///
_Use_decl_annotations_
location::location(_Type _LocationType, unsigned int _Id, unsigned int _BindingId, void *_PBinding) :
_M_type(_LocationType),
_M_reserved(0),
_M_bindingId(_BindingId),
_M_pBinding(_PBinding)
{
//
// Guarantee order per union.
//
_M_ptr = NULL;
_M_id = _Id;
}
///
/// Returns a location which represents a given NUMA node.
///
///
/// The NUMA node number to construct a location for.
///
///
/// A location representing the NUMA node specified by the parameter.
///
location location::from_numa_node(unsigned short _NumaNodeNumber)
{
ULONG highestNodeNumber = platform::__GetNumaHighestNodeNumber();
if (_NumaNodeNumber > highestNodeNumber)
{
throw invalid_operation();
}
return location(location::_NumaNode, _NumaNodeNumber, 0, NULL);
}
///
/// Determines whether two locations have an intersection. This is a fast intersection which avoids certain checks by knowing that
/// the *this* pointer is a virtual processor location for a validly bound virtual processor.
///
///
/// The location to intersect with this.
///
///
/// An indication as to whether the two locations intersect.
///
bool location::_FastVPIntersects(const location& _Rhs) const
{
switch(_Rhs._M_type)
{
case _ExecutionResource:
return _M_id == _Rhs._M_id;
case _NumaNode:
return _As()->GetOwningNode()->GetNumaNodeNumber() == (DWORD)_Rhs._M_id;
case _SchedulingNode:
return static_cast(_As()->GetOwningNode()->Id()) == _Rhs._M_id;
case _System:
return true;
}
return false;
}
///
/// Determines whether two locations have an intersection. This is a fast intersection which avoids certain checks by knowing that
/// the *this* pointer is a node for a validly bound node.
///
///
/// The location to intersect with this.
///
///
/// An indication as to whether the two locations intersect.
///
bool location::_FastNodeIntersects(const location& _Rhs) const
{
switch(_Rhs._M_type)
{
case _ExecutionResource:
return _As()->ContainsResourceId(_Rhs._M_id);
case _NumaNode:
return _As()->GetNumaNodeNumber() == (DWORD)_Rhs._M_id;
case _SchedulingNode:
return _M_id == _Rhs._M_id;
case _System:
return true;
}
return false;
}
///
/// Returns a location representing the most specific place the calling thread is executing upon.
///
location location::current()
{
location current;
ContextBase *pCurrentContext = SchedulerBase::FastCurrentContext();
if (pCurrentContext != NULL && !pCurrentContext->IsExternal())
{
InternalContextBase *pCtx = static_cast(pCurrentContext);
pCtx->EnterCriticalRegion();
VirtualProcessor *pVProc = pCtx->m_pVirtualProcessor;
current = location(location::_ExecutionResource, pVProc->GetExecutionResourceId(), pVProc->GetOwningNode()->GetScheduler()->Id(), pVProc);
pCtx->ExitCriticalRegion();
}
return current;
}
location __cdecl location::_Current_node()
{
location current;
ContextBase *pCurrentContext = SchedulerBase::FastCurrentContext();
if (pCurrentContext != NULL && !pCurrentContext->IsExternal())
{
InternalContextBase *pCtx = static_cast(pCurrentContext);
pCtx->EnterCriticalRegion();
VirtualProcessor *pVProc = pCtx->m_pVirtualProcessor;
SchedulingNode *pNode = pVProc->GetOwningNode();
current = location(location::_SchedulingNode, pNode->Id(), pNode->GetScheduler()->Id(), pNode);
pCtx->ExitCriticalRegion();
}
return current;
}
} // namespace Concurrency