// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== // =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ // // UmsThreadScheduler.h // // Header file containing the metaphor for a UMS thread based concrt scheduler // // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #pragma once #pragma warning (push) #pragma warning (disable: 4100) // unreferenced formal parameter, for comments namespace Concurrency { namespace details { class UMSThreadScheduler : public IUMSScheduler, public SchedulerBase { public: /// /// Creates a UMS thread based scheduler /// UMSThreadScheduler(_In_ const ::Concurrency::SchedulerPolicy& policy); /// /// Creates a UMS thread based scheduler /// static UMSThreadScheduler* Create(_In_ const ::Concurrency::SchedulerPolicy& policy); /// /// Create the correct flavor of virtual processor /// virtual VirtualProcessor *CreateVirtualProcessor(SchedulingNode *pOwningNode, IVirtualProcessorRoot *pOwningRoot); /// /// Destroys a UMS thread based scheduler /// virtual ~UMSThreadScheduler(); /// /// Returns a scheduler unique identifier for the context. /// /// /// The Id for the IScheduler. /// virtual unsigned int GetId() const { return Id(); } /// /// Get the scheduler policy. /// /// /// The policy of the scheduler. /// virtual SchedulerPolicy GetPolicy() const { return SchedulerBase::GetPolicy(); } /// /// Called by the resource manager in order to gather statistics for a given scheduler. The statistics gathered here /// will be used to drive dynamic feedback with the scheduler to determine when it is appropriate to assign more resources /// or take resources away. Note that these counts can be optimistic and do not necessarily have to reflect the current /// count with 100% synchronized accuracy. /// /// /// The number of tasks which have been completed by the scheduler since the last call to the Statistics method. /// /// /// The number of tasks that have arrived in the scheduler since the last call to the Statistics method. /// /// /// The total number of tasks in all scheduler queues. /// virtual void Statistics(unsigned int *pTaskCompletionRate, unsigned int *pTaskArrivalRate, unsigned int *pNumberOfTasksEnqueued) { SchedulerBase::Statistics(pTaskCompletionRate, pTaskArrivalRate, pNumberOfTasksEnqueued); } /// /// Called when the resource manager is giving virtual processors to a particular scheduler. The virtual processors are /// identified by an array of IVirtualProcessorRoot interfaces. This call is made to grant virtual processor roots /// at initial allocation during the course of ISchedulerProxy::RequestInitialVirtualProcessors, and during dynamic /// core migration. /// /// /// An array of IVirtualProcessorRoot interfaces representing the virtual processors being added to the scheduler. /// /// /// Number of IVirtualProcessorRoot interfaces in the array. /// virtual void AddVirtualProcessors(IVirtualProcessorRoot **ppVirtualProcessorRoots, unsigned int count) { SchedulerBase::AddVirtualProcessors(ppVirtualProcessorRoots, count); } /// /// Called when the resource manager is taking away virtual processors from a particular scheduler. The scheduler should /// mark the supplied virtual processors such that they are removed asynchronously and return immediately. Note that /// the scheduler should make every attempt to remove the virtual processors as quickly as possible as the resource manager /// will reaffinitize threads executing upon them to other resources. Delaying stopping the virtual processors may result /// in unintentional oversubscription within the scheduler. /// /// /// An array of IVirtualProcessorRoot interfaces representing the virtual processors which are to be removed. /// /// /// Number of IVirtualProcessorRoot interfaces in the array. /// virtual void RemoveVirtualProcessors(IVirtualProcessorRoot **ppVirtualProcessorRoots, unsigned int count) { SchedulerBase::RemoveVirtualProcessors(ppVirtualProcessorRoots, count); } /// /// Called when the resource manager is made aware that the hardware threads underneath the virtual processors assigned to /// this particular scheduler are 'externally idle' once again i.e. any other schedulers that may have been using them have /// stopped using them. This API is called only when a scheduler proxy was created with MinConcurrency = MaxConcurrency. /// /// /// An array of IVirtualProcessorRoot interfaces representing the virtual processors on which other schedulers have become idle. /// /// /// Number of IVirtualProcessorRoot interfaces in the array. /// virtual void NotifyResourcesExternallyIdle(IVirtualProcessorRoot ** ppVirtualProcessorRoots, unsigned int count) {} /// /// Called when the resource manager is made aware that the execution resources underneath the virtual processors assigned to /// this particular scheduler are busy (active) on other schedulers. The reason these execution resources were lent to /// other schedulers is usually a lack of activation on the part of this scheduler, or a system-wide oversubscription. /// This API is called only when a scheduler proxy was created with MinConcurrency = MaxConcurrency. /// /// /// An array of IVirtualProcessorRoot interfaces representing the virtual processors on which other schedulers have become busy. /// /// /// Number of IVirtualProcessorRoot interfaces in the array. /// virtual void NotifyResourcesExternallyBusy(IVirtualProcessorRoot ** ppVirtualProcessorRoots, unsigned int count) {} /// /// Returns an IScheduler interface. /// /// /// An IScheduler interface. /// virtual IScheduler * GetIScheduler() { return this; } /// /// Called in order to notify the scheduler of the particular completion list created in the RM for it. /// /// /// The completion list created in the RM for this scheduler. /// virtual void SetCompletionList(IUMSCompletionList *pCompletionList) { m_pCompletionList = pCompletionList; } /// /// Called in order to move the completion list to the runnables lists. /// /// /// Bias any awakening of virtual processors to this location. /// /// /// Whether there was anything on the completion list when queried. /// bool MoveCompletionListToRunnables(location bias = location()); /// /// Static initialization common to UMS schedulers. /// static void OneShotStaticConstruction(); /// /// Static destruction common to UMS schedulers. /// static void OneShotStaticDestruction(); /// /// Returns the current scheduling context. /// static UMSSchedulingContext* FastCurrentSchedulingContext() { return reinterpret_cast(TlsGetValue(UMSThreadScheduler::t_dwSchedulingContextIndex)); } protected: /// /// Creates a new thread internal context and returns it to the base scheduler. /// virtual InternalContextBase *CreateInternalContext(); /// /// Notification after a virtual processor goes from INACTIVE to ACTIVE or ACTIVE to INACTIVE /// For UMS we need to ensure that there is at least 1 active vproc. /// /// /// True if a virtual processor is going from INACTIVE to ACTIVE, and false if it is going from ACTIVE to INACTIVE. /// /// /// Active virtual processor count after the transition /// virtual void VirtualProcessorActiveNotification(bool fActive, LONG activeCount); /// /// Returns whether the reserved context pool can be utilized to fetch contexts to bypass throttling. /// virtual bool AllowGeneralFetchOfReservedContexts() { return false; } private: friend class UMSSchedulingContext; // Keeps track of the current scheduling context. static DWORD t_dwSchedulingContextIndex; // The completion list. IUMSCompletionList *m_pCompletionList; // flag to cancel the background thread that creates UTs bool m_fCancelContextCreationHandler; // Event to signal the creation of UTs HANDLE m_hCreateContext; // Private methods // Hide the assignment operator and copy constructor. UMSThreadScheduler const &operator =(UMSThreadScheduler const &); // no assign op UMSThreadScheduler(UMSThreadScheduler const &); // no copy ctor }; } // namespace details } // namespace Concurrency #pragma warning (pop)