// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== // =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ // // SchedulingRing.h // // Source file containing the SchedulingRing 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 SchedulingRing { public: SchedulingRing(SchedulerBase *pScheduler, int id); ~SchedulingRing(); int Id() const { return m_id; } // Create a new Schedule Group ScheduleGroupBase *AllocateScheduleGroup(); // Delete a Schedule Group void FreeScheduleGroup(ScheduleGroupBase *pGroup); // Create a schedule group, add it to the list of groups ScheduleGroupBase *CreateScheduleGroup(); ScheduleGroupSegmentBase *GetAnonymousScheduleGroupSegment() const { return m_pAnonymousSegment; } /// /// Returns a shared index to pseudo-round robin through affine schedule group segments within the ring. /// ScheduleGroupSegmentBase *GetPseudoRRAffineScheduleGroupSegment(int *pIdx) { int min = m_nextAffineSegment; ScheduleGroupSegmentBase *pSegment = FindScheduleGroupSegment(min, m_affineSegments.MaxIndex(), pIdx, &m_affineSegments); if (pSegment == NULL && min != 0) pSegment = FindScheduleGroupSegment(0, min, pIdx, &m_affineSegments); return pSegment; } /// /// Returns a shared index to pseudo-round robin through non-affine schedule group segments within the ring. /// ScheduleGroupSegmentBase *GetPseudoRRNonAffineScheduleGroupSegment(int *pIdx) { int min = m_nextNonAffineSegment; ScheduleGroupSegmentBase *pSegment = FindScheduleGroupSegment(min, m_nonAffineSegments.MaxIndex(), pIdx, &m_nonAffineSegments); if (pSegment == NULL && min != 0) pSegment = FindScheduleGroupSegment(0, min, pIdx, &m_nonAffineSegments); return pSegment; } /// /// Sets a shared index to pseudo-round robin through affine schedule group segments within the ring. This sets the index /// to the schedule group segment *AFTER* idx in the iterator position. /// void SetPseudoRRAffineScheduleGroupSegmentNext(int idx) { m_nextAffineSegment = (idx + 1) % (m_affineSegments.MaxIndex()); ASSERT(m_nextAffineSegment >= 0); } /// /// Sets a shared index to pseudo-round robin through non-affine schedule group segments within the ring. This sets the index /// to the schedule group segment *AFTER* idx in the iterator position. /// void SetPseudoRRNonAffineScheduleGroupSegmentNext(int idx) { m_nextNonAffineSegment = (idx + 1) % (m_nonAffineSegments.MaxIndex()); ASSERT(m_nextNonAffineSegment >= 0); } /// /// Returns the first affine schedule group segment within the ring. /// /// /// The iterator position of the returned schedule group segment will be placed here. This can only be /// utilized as the pIdx parameter or the idxStart parameter of a GetNextAffineScheduleGroup. /// ScheduleGroupSegmentBase *GetFirstAffineScheduleGroupSegment(int *pIdx) { return GetFirstScheduleGroupSegment(pIdx, &m_affineSegments); } /// /// Returns the next affine schedule group segment in an iteration. /// ScheduleGroupSegmentBase *GetNextAffineScheduleGroupSegment(int *pIdx, int idxStart = 0) { return GetNextScheduleGroupSegment(pIdx, idxStart, &m_affineSegments); } /// /// Returns the first non-affine schedule group segment within the ring. /// /// /// The iterator position of the returned schedule group segment will be placed here. This can only be /// utilized as the pIdx parameter or the idxStart parameter of a GetNextNonAffineScheduleGroup. /// ScheduleGroupSegmentBase *GetFirstNonAffineScheduleGroupSegment(int *pIdx) { return GetFirstScheduleGroupSegment(pIdx, &m_nonAffineSegments); } /// /// Returns the next non-affine schedule group segment in an iteration. /// ScheduleGroupSegmentBase *GetNextNonAffineScheduleGroupSegment(int *pIdx, int idxStart = 0) { return GetNextScheduleGroupSegment(pIdx, idxStart, &m_nonAffineSegments); } /// /// Returns the node which owns this ring. /// SchedulingNode *GetOwningNode() const { return m_pNode; } /// /// Returns whether this is an active ring or not. /// bool IsActive() const { return (m_active != 0); } /// /// Activates the ring. /// void Activate(); private: friend class SchedulerBase; friend class ScheduleGroupBase; friend class ScheduleGroupSegmentBase; friend class FairScheduleGroup; friend class CacheLocalScheduleGroup; friend class SchedulingNode; friend class VirtualProcessor; friend class InternalContextBase; friend class ThreadInternalContext; // Owning scheduler SchedulerBase *m_pScheduler; // Owning Node SchedulingNode *m_pNode; // The anonymous schedule group - for external contexts and tasks without an explicitly specified schedule group. // There is one anonymous group segment per scheduling node. ScheduleGroupSegmentBase * m_pAnonymousSegment; // Scheduler group segments owned by this ring which have explicitly specified affinity. ListArray m_affineSegments; // Scheduler groups segments owned by this ring which do not have explicitly specified affinity. ListArray m_nonAffineSegments; // Pseudo Round robin indicies. int m_nextAffineSegment; int m_nextNonAffineSegment; int m_id; // An indication as to whether the ring is active. volatile LONG m_active; // Removes the schedule group segment from the appropriate list. void RemoveScheduleGroupSegment(ScheduleGroupSegmentBase* pGroup); void SetOwningNode(SchedulingNode *pNode) { m_pNode = pNode; } /// /// Returns the first schedule group segment in the non-cyclic range [min, max). If such is found /// the schedule group segment is returned and pIdx contains its index within the list array. /// If not found, NULL is returned and the value in pIdx is unspecified. /// ScheduleGroupSegmentBase *FindScheduleGroupSegment(int min, int max, int *pIdx, ListArray *pSegmentList) { ScheduleGroupSegmentBase *pSegment = NULL; int i = min; for (; i < max && pSegment == NULL; ++i) { pSegment = (*pSegmentList)[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 pSegment; } /// /// Returns the first schedule group. /// /// /// The iterator position of the returned schedule group will be placed here. This can only be /// utilized as the pIdx parameter or the idxStart parameter of a GetNextScheduleGroup. /// ScheduleGroupSegmentBase *GetFirstScheduleGroupSegment(int *pIdx, ListArray* pSegmentList) { return FindScheduleGroupSegment(0, pSegmentList->MaxIndex(), pIdx, pSegmentList); } /// /// Returns the next schedule group in an iteration. /// ScheduleGroupSegmentBase *GetNextScheduleGroupSegment(int *pIdx, int idxStart, ListArray* pSegmentList) { ScheduleGroupSegmentBase *pSegment = NULL; int min = *pIdx + 1; if (min > idxStart) { pSegment = FindScheduleGroupSegment(min, pSegmentList->MaxIndex(), pIdx, pSegmentList); min = 0; } if (pSegment == NULL) pSegment = FindScheduleGroupSegment(min, idxStart, pIdx, pSegmentList); return pSegment; } }; } // namespace details } // namespace Concurrency