// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== // =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ // // CurrentScheduler.cpp // // Implementation of static scheduler APIs for CurrentScheduler:: // // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #include "concrtinternal.h" namespace Concurrency { /// /// Returns a unique identifier for the current scheduler. Returns -1 if no current scheduler exists. /// unsigned int CurrentScheduler::Id() { const SchedulerBase *pScheduler = SchedulerBase::SafeFastCurrentScheduler(); return pScheduler != NULL ? pScheduler->Id() : UINT_MAX; } /// /// Returns a current number of virtual processors for the current scheduler. Returns -1 if no current scheduler exists. /// No error state. /// unsigned int CurrentScheduler::GetNumberOfVirtualProcessors() { const SchedulerBase *pScheduler = SchedulerBase::SafeFastCurrentScheduler(); return pScheduler != NULL ? pScheduler->GetNumberOfVirtualProcessors() : UINT_MAX; } /// /// Returns a copy of the policy the current scheduler is using. Returns NULL if no current /// scheduler exists. /// SchedulerPolicy CurrentScheduler::GetPolicy() { const SchedulerBase *pScheduler = SchedulerBase::CurrentScheduler(); return pScheduler->GetPolicy(); } /// /// Returns a reference to the scheduler instance in TLS storage (viz., the current scheduler). /// If one does not exist, the default scheduler for the process is attached to the calling thread and returned -- /// if the default scheduler does not exist it is created /// /// /// The TLS storage for the current scheduler is returned. /// Scheduler* CurrentScheduler::Get() { return SchedulerBase::CurrentScheduler(); } /// /// The normal scheduler factory. (Implicitly calls Scheduler::Attach on the internally represented scheduler instance.) /// The created scheduler will become the current scheduler for the current context (if it is an OS context it will be /// inducted to a ConcRT context). To shutdown such a scheduler, Detach needs to be called. Any extra Reference calls /// must be matched with Release for shutdown to commence. /// /// /// [in] A const pointer to the scheduler policy (See Scheduler Policy API) /// void CurrentScheduler::Create(const SchedulerPolicy& policy) { SchedulerBase *pScheduler = SchedulerBase::Create(policy); pScheduler->Attach(); } /// /// Detaches the current scheduler from the calling thread and restores the previously attached scheduler as the current /// scheduler. Implicitly calls Release. After this function is called, the calling thread is then managed by the scheduler /// that was previously activated via Create() or Attach(). /// void CurrentScheduler::Detach() { SchedulerBase* pScheduler = SchedulerBase::SafeFastCurrentScheduler(); if (pScheduler != NULL) { return pScheduler->Detach(); } else { throw scheduler_not_attached(); } } /// /// Causes the OS event object 'shutdownEvent' to be set when the scheduler shuts down and destroys itself. /// /// /// [in] A valid event object /// void CurrentScheduler::RegisterShutdownEvent(HANDLE shutdownEvent) { SchedulerBase* pScheduler = SchedulerBase::SafeFastCurrentScheduler(); if (pScheduler != NULL) { return pScheduler->RegisterShutdownEvent(shutdownEvent); } else { throw scheduler_not_attached(); } } /// /// Create a schedule group within the current scheduler. /// ScheduleGroup* CurrentScheduler::CreateScheduleGroup() { return SchedulerBase::CurrentScheduler()->CreateScheduleGroup(); } /// /// Creates a new schedule group within the scheduler associated with the calling context. Tasks scheduled within the newly created /// schedule group will be biased towards executing at the specified location. /// /// /// A reference to a location where the tasks within the schedule group will biased towards executing at. /// /// /// A pointer to the newly created schedule group. This ScheduleGroup object has an initial reference count placed on it. /// /// /// This method will result in the process' default scheduler being created and/or attached to the calling context if there is no /// scheduler currently associated with the calling context. /// You must invoke the Release method on a schedule group when you are /// done scheduling work to it. The scheduler will destroy the schedule group when all work queued to it has completed. /// Note that if you explicitly created this scheduler, you must release all references to schedule groups within it, before /// you release your reference on the scheduler, via detaching the current context from it. /// /// /// /// /// ScheduleGroup* CurrentScheduler::CreateScheduleGroup(location& placement) { return SchedulerBase::CurrentScheduler()->CreateScheduleGroup(placement); } /// /// Create a light-weight schedule within the current scheduler in an implementation dependent schedule group. /// /// /// [in] A pointer to the main function of a task. /// /// /// [in] A void pointer to the data that will be passed in to the task. /// _Use_decl_annotations_ void CurrentScheduler::ScheduleTask(TaskProc proc, void *data) { SchedulerBase::CurrentScheduler()->ScheduleTask(proc, data); } /// /// Schedules a light-weight task within the scheduler associated with the calling context. The light-weight task will be placed /// within a schedule group of the runtime's choosing. It will also be biased towards executing at the specified location. /// /// /// A pointer to the function to execute to perform the body of the light-weight task. /// /// /// A void pointer to the data that will be passed as a parameter to the body of the task. /// /// /// A reference to a location where the light-weight task will be biased towards executing at. /// /// /// This method will result in the process' default scheduler being created and/or attached to the calling context if there is no /// scheduler currently associated with the calling context. /// /// /// /// _Use_decl_annotations_ void CurrentScheduler::ScheduleTask(TaskProc proc, void * data, location& placement) { SchedulerBase::CurrentScheduler()->ScheduleTask(proc, data, placement); } /// /// Determines whether a given location is available on the current scheduler. /// /// /// A reference to the location to query the current scheduler about. /// /// /// An indication of whether or not the location specified by the argument is available on the current /// scheduler. /// /// /// This method will not result in scheduler attachment if the calling context is not already associated with a scheduler. /// Note that the return value is an instantaneous sampling of whether the given location is available. In the presence of multiple /// schedulers, dynamic resource management may add or take away resources from schedulers at any point. Should this happen, the given /// location may change availability. /// /**/ bool CurrentScheduler::IsAvailableLocation(const location& _Placement) { const SchedulerBase *pScheduler = SchedulerBase::SafeFastCurrentScheduler(); return pScheduler != NULL ? pScheduler->IsAvailableLocation(_Placement) : false; } namespace details { void _CurrentScheduler::_ScheduleTask(TaskProc _Proc, void * _Data) { SchedulerBase::CurrentScheduler()->ScheduleTask(_Proc, _Data); } unsigned int _CurrentScheduler::_Id() { return CurrentScheduler::Id(); } unsigned int _CurrentScheduler::_GetNumberOfVirtualProcessors() { return SchedulerBase::CurrentScheduler()->GetNumberOfVirtualProcessors(); } _Scheduler _CurrentScheduler::_Get() { return _Scheduler(SchedulerBase::CurrentScheduler()); } } // namespace details } // namespace Concurrency