// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== // =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ // // VirtualProcessorRoot.h // // Part of the ConcRT Resource Manager -- this header file contains the internal definition for the base virtual // processor root. // // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- namespace Concurrency { namespace details { /// /// An abstraction for a virtual processor -- an entity on top of which a single thread of execution (of whatever /// type) runs. Note that there are specific derived classes for free and bound virtual processor roots -- necessary /// so as to easily hand out different types of thread proxies and message thread proxies upon Activate for bound /// schedulers, etc... /// class VirtualProcessorRoot : public IVirtualProcessorRoot { public: /// /// Constructs a new virtual processor root. /// /// /// The scheduler proxy this root is created for. A scheduler proxy holds RM data associated with an instance of /// a scheduler. /// /// /// The processor node that this root belongs to. The processor node is one among the nodes allocated to the /// scheduler proxy. /// /// /// The index into the array of cores for the processor node specified. /// VirtualProcessorRoot(SchedulerProxy *pSchedulerProxy, SchedulerNode* pNode, unsigned int coreIndex); /// /// Destroys a virtual processor root. /// virtual ~VirtualProcessorRoot() { } /// /// Returns a unique identifier for the virtual processor root. /// virtual unsigned int GetId() const { return m_id; } /// /// Returns a unique identifier for the node that the given virtual processor root belongs to. The identifier returned /// will fall in the range [0, nodeCount] where nodeCount is the value returned from Concurrency::GetProcessorNodeCount. /// virtual unsigned int GetNodeId() const { return m_executionResource.GetNodeId(); } /// /// Returns a unique identifier for the execution resource that this virtual processor root runs atop. /// virtual unsigned int GetExecutionResourceId() const { return m_executionResource.GetExecutionResourceId(); } /// /// Causes the scheduler to start running a thread proxy on the specified virtual processor root which will execute /// the Dispatch method of the context supplied by pContext. /// /// /// The context which will be dispatched on a (potentially) new thread running atop this virtual processor root. /// virtual void Activate(::Concurrency::IExecutionContext *pContext) =0; /// /// Causes the thread proxy running atop this virtual processor root to temporarily stop dispatching pContext. /// /// /// The context which should temporarily stop being dispatched by the thread proxy running atop this virtual processor root. /// virtual bool Deactivate(::Concurrency::IExecutionContext *pContext) =0; /// /// Forces all data in the memory heirarchy of one processor to be visible to all other processors. /// /// /// The context which is currently being dispatched by this root. /// virtual void EnsureAllTasksVisible(::Concurrency::IExecutionContext *pContext) =0; /// /// Called to indicate that a scheduler is done with a virtual processor root and wishes to return it to the resource manager. /// /// /// The scheduler making the request to remove this virtual processor root. /// virtual void Remove(IScheduler *pScheduler); /// /// Returns a number of active virtual processors and external threads running on top of the execution resource /// associated with this virtual processor root. /// /// /// A current subscription level of the underlying execution resource. /// virtual unsigned int CurrentSubscriptionLevel() const { return m_executionResource.CurrentSubscriptionLevel(); } // ************************************************** // Internal // ************************************************** /// /// Returns a pointer to the scheduler proxy this virtual processor root was created by. /// SchedulerProxy * GetSchedulerProxy() { return m_executionResource.GetSchedulerProxy(); } /// /// Returns the core index into the array of cores, for the node that this virtual processor root is part of. /// int GetCoreIndex() { return m_executionResource.GetCoreIndex(); } /// /// Retrieves an underlying execution resource. /// ExecutionResource * GetExecutionResource() { return &m_executionResource; } /// /// Helpers to prevent from removing a virtual processor root twice. We remove the root from the list in the allocated /// nodes when the corresponding vprocroot::Remove call is made. /// bool IsRootRemoved() { return m_fRemovedFromScheduler; } void MarkRootRemoved() { m_fRemovedFromScheduler = true; } /// /// Deletes the virtual processor. /// virtual void DeleteThis() =0; /// /// Notifies the underlying RM that the core is subscribed by this root *if* necessary. /// void Subscribe(); /// /// Notifies the underlying RM that the core is not subscribed by this root *if* necessary. /// void Unsubscribe(); /// /// This API is called when a virtual processor root is being destroyed. It removes the effect of this virtual processor root /// on the subscription level for the underlying core. /// void ResetSubscriptionLevel(); /// /// Sets the activated context to the specified value. /// void SetActivatedContext(::Concurrency::IExecutionContext *pContext) { // // The below need not be atomic but must have at least write release semantics. // InterlockedExchangePointer(reinterpret_cast(&m_pActivatedContext), pContext); } /// /// Gets the activated context and simultaneously sets it to NULL. /// ::Concurrency::IExecutionContext *AcquireActivatedContext() { // // Once this is set, we are the only entity that will ever acquire/reset. We simply need to wait for the set which may // be a few instructions behind. // _SpinWaitBackoffNone spinWait(_Sleep0); while (m_pActivatedContext == NULL) { spinWait._SpinOnce(); } // // The only entity which will subsequently set this won't come until after this has happened and we woke up another thread. This // need not be atomic or have barrier semantics. // ::Concurrency::IExecutionContext *pActivatedContext = m_pActivatedContext; m_pActivatedContext = NULL; return pActivatedContext; } /// /// This API is called by the RM to indicate that this vproc does not contribute towards concurrency limits /// set by the user /// void MarkAsOversubscribed() { m_fOversubscribed = true; } /// /// Returns true if this is an oversubscribed vproc. /// bool IsOversubscribed() { return m_fOversubscribed; } protected: // Internal context that was last activated. This is used to resolve activate/deactivate,idle races. IExecutionContext * volatile m_pActivatedContext; // Execution resource underneath this virtual processor root ExecutionResource m_executionResource; // Set to true when a RemoveVirtualProcessors call has been made on the corresponding scheduler interface for this // virtual processor root. bool m_fRemovedFromScheduler; // Flag to distinguish vprocs that were created through CreateOversubscribe() call. bool m_fOversubscribed; // The process unique identifier assigned to this virtual processor root. unsigned int m_id; // Fence used to avoid kernel transitions with activation/deactivation races. volatile LONG m_activationFence; private: // The current unique identifier being handed out to created virtual processor roots. static long s_currentId; }; } // namespace details } // namespace Concurrency