// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== // =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ // // SchedulingNode.h // // Source file containing the SchedulingNode declaration. // // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- namespace Concurrency { namespace details { /// /// A scheduling node corresponds to a NUMA node or a processor package; containing one or more virtual processor groups. /// class SchedulingNode { public: /// /// Constructs a scheduling node. /// SchedulingNode(const QuickBitSet& resourceSet, DWORD numaNodeNumber, SchedulingRing *pRing); /// /// Destroys a scheduling node. /// ~SchedulingNode(); /// /// Creates and adds a new virtual processor in the node to associated with the root provided. /// NOTE: For non-oversubscribed vprocs this API is currently will only work for initial allocation. /// /// /// The virtual processor root to create the virtual processor with. /// /// /// True if this is an oversubscribed virtual processor. /// /// /// The newly created virtual processor. /// VirtualProcessor* AddVirtualProcessor(IVirtualProcessorRoot *pOwningRoot, bool fOversubscribed = false); /// /// Returns the scheduler associated with the node. /// SchedulerBase * GetScheduler() { return m_pScheduler; } /// /// Returns the scheduling ring associated with the node. /// SchedulingRing * GetSchedulingRing() { return m_pRing; } /// /// Find the virtual processor in this node that matches the root provided. /// /// /// The virtual processor root to match. /// VirtualProcessor* FindMatchingVirtualProcessor(IVirtualProcessorRoot* pRoot); /// /// Returns the ID of the scheduling node. /// int Id() const { return m_id; } /// /// Returns the first virtual processor in the non-cyclic range [min, max). If such is found /// the virtual processor is returned and pIdx contains its index within the list array. /// If not found, NULL is returned and the value in pIdx is unspecified. /// VirtualProcessor *FindVirtualProcessor(int min, int max, int *pIdx) { VirtualProcessor *pVProc = NULL; int i = min; for (; i < max && pVProc == NULL; ++i) { pVProc = m_virtualProcessors[i]; } // // The loop incremented "i" prior to the check. If found, the index is i - 1. If not, we care // not what pIdx contains. // *pIdx = i - 1; return pVProc; } /// /// Returns the first virtual processor. /// /// /// The iterator position of the returned virtual processor will be placed here. This can only be /// utilized as the pIdx parameter or the idxStart parameter of a GetNextVirtualProcessor. /// VirtualProcessor *GetFirstVirtualProcessor(int *pIdx) { return FindVirtualProcessor(0, m_virtualProcessors.MaxIndex(), pIdx); } /// /// Returns the next virtual processor in an iteration. /// VirtualProcessor *GetNextVirtualProcessor(int *pIdx, int idxStart = 0) { VirtualProcessor *pVProc = NULL; int min = *pIdx + 1; if (min > idxStart) { pVProc = FindVirtualProcessor(min, m_virtualProcessors.MaxIndex(), pIdx); min = 0; } if (pVProc == NULL) pVProc = FindVirtualProcessor(min, idxStart, pIdx); return pVProc; } /// /// Returns whether a virtual processor is available. /// bool HasVirtualProcessorAvailable() const { return m_virtualProcessorAvailableCount > 0; } /// /// Returns whether a virtual processor is waiting for throttling. /// bool HasVirtualProcessorPendingThread() const { return m_virtualProcessorsPendingThreadCreate > 0; } /// /// Returns whether a virtual processor is available to execute new work. /// bool HasVirtualProcessorAvailableForNewWork() const { // // The observational race (lack of atomicity between the two reads) should not matter. If it does in some obscure // case, a new atomic counter can be added. // return (m_virtualProcessorAvailableCount - m_virtualProcessorsPendingThreadCreate) > 0; } /// /// Gets a location object which represents the scheduling node. /// location GetLocation(); /// /// Returns a virtual processor from the given location. The virtual processor must be within this node. /// VirtualProcessor* FindVirtualProcessorByLocation(const location* pLoc); /// /// Determines whether the scheduling node contains an execution resource with ID as specified. Note that this does NOT return /// whether the said resource is available in the scheduler -- only whether the given resource ID is logically contained in the /// node. The scheduler may have no virtual processor with that execution resource ID at the moment. /// bool ContainsResourceId(unsigned int resourceId) /*const*/ { return m_resourceBitMap.Exists(resourceId); } /// /// Notifies the node of a resource that is contained within it and its assigned position in all bitmasks used by all ConcRT /// schedulers. /// void NotifyResource(unsigned int resourceId, unsigned int maskId) { m_resourceBitMap.Insert(resourceId, maskId); } /// /// Returns the bitset for all resources in the node. /// const QuickBitSet& GetResourceSet() { return m_resourceSet; } /// /// Gets the NUMA node to which this scheduling node belongs. /// DWORD GetNumaNodeNumber() const { return m_numaNodeNumber; } private: friend class SchedulerBase; friend class VirtualProcessor; friend class InternalContextBase; friend class FairScheduleGroup; template friend class ListArray; // Owning scheduler SchedulerBase *m_pScheduler; // Owning ring SchedulingRing * const m_pRing; // The bit-set identifying execution resources within this node for quick affinity masking. QuickBitSet m_resourceSet; // Maps resource IDs contained within the node to a mask identifier Hash m_resourceBitMap; volatile LONG m_virtualProcessorAvailableCount; volatile LONG m_virtualProcessorsPendingThreadCreate; volatile LONG m_virtualProcessorCount; volatile LONG m_ramblingCount; // rambling -- searching foreign nodes for work DWORD m_numaNodeNumber; int m_id; // Virtual processors owned by this node. ListArray m_virtualProcessors; InternalContextBase *StealLocalRunnableContext(VirtualProcessor* pSkipVirtualProcessor = NULL); /// /// Find an available virtual processor in the scheduling node. /// bool FoundAvailableVirtualProcessor(VirtualProcessor::ClaimTicket& ticket, location bias = location(), ULONG type = VirtualProcessor::AvailabilityAny); void Cleanup(); // Prevent warning about generated assignment operator & copy constructors. SchedulingNode(const SchedulingNode&); void operator=(const SchedulingNode&); }; } // namespace details } // namespace Concurrency