// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
//
// FairScheduleGroup.cpp
//
// Implementation file for FairScheduleGroup.
//
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
#include "concrtinternal.h"
namespace Concurrency
{
namespace details
{
///
/// Puts a runnable context into the runnables collection in the schedule group.
///
void FairScheduleGroupSegment::AddToRunnablesCollection(InternalContextBase* pContext)
{
m_runnableContexts.Enqueue(pContext);
}
///
/// Locates a segment that is appropriate for scheduling a task within the schedule group given information about the task's placement
/// and the origin of the thread making the call.
///
///
/// A segment with affinity to this particular location will be located.
///
///
/// An indication as to whether the schedule group can create a new segment if an appropriate segment cannot be found. If this parameter is
/// specified as true, NULL will never be returned from this method; otherwise, it can be if no matching segment can be found.
///
///
/// A segment appropriate for scheduling work with affinity to segmentAffinity from code executing at origin. Note that NULL may be returned
/// if fCreateNew is specified as false and no appropriate segment yet exists for the group.
///
ScheduleGroupSegmentBase *FairScheduleGroup::LocateSegment(location*, bool fCreateNew)
{
// Ignore the passed in affinity for fair schedule groups.
location unbiased;
if (m_kind & AnonymousScheduleGroup)
{
//
// In order to provide a "like" functionality to Dev10 for anonymous fair groups, we still let the group be split by rings. Non-anonymous
// groups are also treated identically to Dev10 -- they live in one ring which is more for separation than any biasing.
//
return ScheduleGroupBase::LocateSegment(&unbiased, fCreateNew);
}
else
{
ScheduleGroupSegmentBase *pSegment = m_pDefaultSegment;
if (fCreateNew && !pSegment)
{
m_segmentLock._Acquire();
if (m_pDefaultSegment)
{
pSegment = m_pDefaultSegment;
}
else
{
pSegment = CreateSegment(&unbiased, m_pScheduler->GetNextSchedulingRing());
// CreateSegment adds the segment to the list array as its last step, which generates a fence ensuring that the segment
// is fully initialized before it is published on weaker memory models.
m_pDefaultSegment = static_cast(pSegment);
}
m_segmentLock._Release();
}
return pSegment;
}
}
///
/// Internal routine which finds an appropriate segment for a task placement.
///
///
/// A segment with this affinity will be located.
///
///
/// A segment with segmentAffinity within this ring will be found. A given location may be split into multiple segments by node in order
/// to keep work local.
///
///
/// A segment with the specified affinity close to the specified location.
///
ScheduleGroupSegmentBase *FairScheduleGroup::FindSegment(location*, SchedulingRing *pRing)
{
// Ignore the passed in affinity for fair schedule groups
location unbiased;
if (m_kind & AnonymousScheduleGroup)
{
return ScheduleGroupBase::FindSegment(&unbiased, pRing);
}
else
{
return m_pDefaultSegment;
}
}
} // namespace details
} // namespace Concurrency