// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== // =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ // // VirtualProcessorRoot.cpp // // Part of the ConcRT Resource Manager -- this file contains the internal implementation for the base virtual // processor root. // // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #include "concrtinternal.h" namespace Concurrency { namespace details { // The current unique identifier being handed out to created virtual processor roots. long VirtualProcessorRoot::s_currentId = 0; /// /// Constructs a new virtual processor root. /// /// /// The scheduler proxy this root is created for. A scheduler proxy holds RM data associated with an instance of /// a scheduler. /// /// /// The processor node that this root belongs to. The processor node is one among the nodes allocated to the /// scheduler proxy. /// /// /// The index into the array of cores for the processor node specified. /// VirtualProcessorRoot::VirtualProcessorRoot(SchedulerProxy * pSchedulerProxy, SchedulerNode* pNode, unsigned int coreIndex) : m_pActivatedContext(NULL) , m_executionResource(pSchedulerProxy, pNode, coreIndex) , m_fRemovedFromScheduler(false) , m_fOversubscribed(false) , m_activationFence(0) { m_id = (unsigned int)InterlockedIncrement(&s_currentId); m_executionResource.MarkAsVirtualProcessorRoot(this); } /// /// Called to indicate that a scheduler is done with a virtual processor root and wishes to return it to the resource manager. /// /// /// The scheduler making the request to remove this virtual processor root. /// void VirtualProcessorRoot::Remove(IScheduler *pScheduler) { if (pScheduler == NULL) throw std::invalid_argument("pScheduler"); if (GetSchedulerProxy()->Scheduler() != pScheduler) throw invalid_operation(); ResetSubscriptionLevel(); // This particular call does not have to worry about the RM receiving a SchedulerShutdown for the scheduler proxy in question. GetSchedulerProxy()->DestroyVirtualProcessorRoot(this); } /// /// Notifies the underlying RM that the core is subscribed by this root *if* necessary. /// void VirtualProcessorRoot::Subscribe() { // // Note that there is a possibility in a race between activate/deactivate or activate/idle that we might race between the increment and // decrement and see a subscription count of: // // 1->2->1 instead of 1->0->1 // // This *SHOULD* be fine in the RM layer and might even be a more desirable outcome so RM doesn't try to "give away" the idle core // which is idle for a split second. In any case, it is noted here and can be fixed here if deemed necessary at a later point // in time. // GetSchedulerProxy()->IncrementCoreSubscription(GetExecutionResource()); } /// /// Notifies the underlying RM that the core is not subscribed by this root *if* necessary. /// void VirtualProcessorRoot::Unsubscribe() { GetSchedulerProxy()->DecrementCoreSubscription(GetExecutionResource()); } /// /// This API is called when a virtual processor root is being destroyed. It removes the effect of this virtual processor root /// on the subscription level for the underlying core. /// void VirtualProcessorRoot::ResetSubscriptionLevel() { // // This should **ONLY** be called in the remove path to quickly address the subscription level change. There's now a race between this // happening from two different paths -- one a thread removing itself from a virtual processor via IThreadProxy::SwitchOut and another // via the removal of said virtual processor via IVirtualProcessorRoot::Remove. // // Since the fence can only be 1 or 0 at this point (you can't race remove/activate or there's another bug at a higher level), only the // entity which decrements the fence to 0 plays with the subscription level. // #if defined(_DEBUG) // // Assert that there is no activate/remove race. We must snap the value of the fence as our observation might change between two // reads. // LONG snapFence = m_activationFence; ASSERT(snapFence == 0 || snapFence == 1); #endif // _DEBUG LONG newVal = InterlockedDecrement(&m_activationFence); if (newVal == 0) { // // The virtual processor was in an activated state when it was removed -- we need to reduce the subscription level here. // Unsubscribe(); } else { // // The value could be -1 if we raced with the virtual processor switching out. // ASSERT(newVal == -1); } } } // namespace details } // namespace Concurrency