// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== // =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ // // UMSFreeVirtualProcessorRoot.h // // Part of the ConcRT Resource Manager -- this header file contains the internal definition for the UMS free virtual // processor root (represents a virtual processor as handed to a scheduler). // // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- namespace Concurrency { namespace details { class UMSFreeVirtualProcessorRoot : public IThreadProxy, public UMSBaseObject, public VirtualProcessorRoot { public: // Private helper class class InitialThreadParam { public: InitialThreadParam(UMSFreeVirtualProcessorRoot * pRoot) { m_pRoot = pRoot; m_hEvent = CreateEventW(NULL, FALSE, FALSE, NULL); if (m_hEvent == NULL) { throw scheduler_resource_allocation_error(HRESULT_FROM_WIN32(GetLastError())); } } ~InitialThreadParam() { if (m_hEvent != NULL) { CloseHandle(m_hEvent); } } HANDLE m_hEvent; UMSFreeVirtualProcessorRoot * m_pRoot; }; /// /// Constructs a new free 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. /// UMSFreeVirtualProcessorRoot(UMSSchedulerProxy *pSchedulerProxy, SchedulerNode* pNode, unsigned int coreIndex); /// /// Destroys a free virtual processor root. /// virtual ~UMSFreeVirtualProcessorRoot(); /// /// Deletes the virtual processor. /// virtual void DeleteThis(); /// /// Determines whether the virtual processor is marked for deletion. /// bool IsDeleting() const { return m_fDelete; } // ************************************************** // IVirtualProcessorRoot: // ************************************************** /// /// 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); /// /// 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); /// /// 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); /// /// Notify the primary that a thread on which it is critically blocked (due to asynchronous interruption in a critical region) /// is now runnable. /// void CriticalNotify() { SetEvent(m_hCriticalNotificationEvent); } // ************************************************** // IThreadProxy (for the scheduling context): // ************************************************** /// /// Returns a process unique identifier for the thread proxy. /// /// /// The IThreadProxy id. /// virtual unsigned int GetId() const; /// /// Called in order to perform a cooperative context switch between one context and another. After this call, pContext will /// be running atop the virtual processor root and the context which was running will not. What happens to the context that /// was running depends on the value of the reason argument. /// /// /// The context to cooperatively switch to. /// /// /// Indicates the state of the thread proxy that is executing the switch. This can determine ownership of the underlying thread /// proxy and context. /// virtual void SwitchTo(IExecutionContext *pContext, SwitchingProxyState switchState); /// /// Called in order to disassociate the currently executing context from its virtual processor root, and reinitialize the root /// for future use. /// /// /// Indicates the state of the thread proxy that is executing the switch. This can determine ownership of the underlying thread /// proxy and context. /// virtual void SwitchOut(SwitchingProxyState switchState = Blocking); /// /// Called in order to yield to the underlying operating system. This allows the operating system to schedule /// other work in that time quantum. /// virtual void YieldToSystem(); /// /// Returns whether or not this object is the primary. /// virtual bool IsPrimary() { return true; } #if _UMSTRACE void Trace(int traceEvt, void *pCtx, void *pVproc, ULONG_PTR data) { m_traceBuffer.Trace(traceEvt, pCtx, pVproc, data); } #endif // _UMSTRACE /// /// Returns whether or not the given context is the scheduling context. /// bool IsSchedulingContext(IExecutionContext *pContext) const { return (pContext == m_pSchedulingContext); } /// /// Returns our RM. /// ResourceManager *GetResourceManager(); /// /// Returns the currently executing proxy on this virtual processor root. /// UMSThreadProxy *GetExecutingProxy() { return m_pExecutingProxy; } /// /// Called in order to reset this virtual processor root to a completely quiescent state (not running anything). /// void ResetOnIdle(); protected: /// /// Returns our scheduler proxy (cast appropriately to a UMSSchedulerProxy). /// UMSSchedulerProxy *SchedulerProxy() { return static_cast(GetSchedulerProxy()); } private: #if _UMSTRACE _TraceBuffer m_traceBuffer; #endif // _UMSTRACE // A handle to the primary thread. HANDLE m_hPrimary; // Blocking handle if the thread should block. HANDLE m_hBlock; // The critical notification event. This event is waited upon in conjunction with the completion list event // when the primary gets stuck in a critical region (or other piece of critical code such as startup). When signaled, // it informs the primary that there it can do something. HANDLE m_hCriticalNotificationEvent; // The unique scheduling context. This is hard bound to this virtual processor and is actually invoked on the primary thread. IExecutionContext *m_pSchedulingContext; // The UT which is running atop this primary. UMSThreadProxy *m_pExecutingProxy; // The TID of the primary thread. DWORD m_primaryId; // Process wide unique identifier. unsigned int m_id; // Variable used to manage subscription level for UMS, in addition to the activation fence which is used for both threads and UMS. // Additional comments in UMSFreeVirtualProcessorRoot::Deactivate. bool m_fWokenByScheduler; // Set to true when the root is activated for the first time. bool m_fActivated; // Indicates deletion needs to take place. bool m_fDelete; // Indicates the primary is started. bool m_fStarted; /// /// Called in order to invoke the scheduler's scheduling context. /// /// /// If invocation of this context is due to previous context blocking, then was it due to an asynchronous event (e.g.: page fault). /// Otherwise, false is passed in. /// void InvokeSchedulingContext(bool fAsynchronous); /// /// Executes the specified proxy. This can only be called from the primary thread! /// /// /// The thread proxy to execute. /// /// /// Whether the switch is happening as a result of a SwitchTo from the scheduling context. On failure, we do not recursively reinvoke /// the scheduling context, we simply return -- indicating failure. /// /// /// An indication as to whether the execution was due to the result of a critical block and subsequent execute. /// /// /// This does *NOT* return if execution is successful. Any return indicates failure. /// void Execute(UMSFreeThreadProxy *pProxy, bool fromSchedulingContext, bool fCriticalBlockAndExecute); /// /// Creates the primary thread. /// void CreatePrimary(); /// /// Starts up the primary thread. /// void StartupPrimary() { CONCRT_COREASSERT(m_fStarted == false); m_fStarted = true; SetEvent(m_hBlock); } /// /// Marks a particular UMS thread proxy as running atop this UMS virtual processor root. /// /// /// The proxy which is to run atop this virtual processor root. /// /// /// Is the affinitization due to a critical execution happening on the same vproc. /// void Affinitize(UMSFreeThreadProxy *pProxy, bool fCriticalReexecute = false); /// /// Called in order to handle a UMS thread blocking. /// /// /// The thread that is blocking. /// /// /// An indication of whether the blocking was due to an asynchronous event (e.g.: page fault) or a synchronous one (e.g.: calling an API /// which explicitly blocked. /// void HandleBlocking(UMSFreeThreadProxy *pBlockedProxy, bool fAsynchronous); /// /// Called in order to handle a UMS thread cooperative yielding. /// /// /// The thread that is yielding. /// void HandleYielding(UMSFreeThreadProxy *pProxy); /// /// Performs a critical blocking of the primary until a specific UT appears on the completion list. The specified UT must /// be in a critical region! /// void CriticalBlockAndExecute(UMSFreeThreadProxy *pProxy); /// /// Returns whether or not we are executing on the primary thread for this virtual processor. /// bool OnPrimary() { return (GetCurrentThreadId() == m_primaryId); } /// /// Performs a deactivation of the virtual processor. This is always called on the primary. A user thread which deactivates must defer the /// call to the primary to perform the blocking action. /// bool InternalDeactivate(); /// /// The UMS primary function. This is invoked when the virtual processor switches into UMS scheduling mode or whenever a given /// context blocks or yields. /// /// /// The reason for the UMS invocation. /// /// /// The activation payload (depends on reason) /// /// /// The context (the virtual processor pointer) /// static void NTAPI PrimaryInvocation(UMS_SCHEDULER_REASON reason, ULONG_PTR activationPayload, PVOID pData); /// /// The primary thread for this UMS virtual processor. /// /// /// The UMSFreeVirtualProcessorRoot that the primary manages. /// static DWORD CALLBACK PrimaryMain(LPVOID pContext); }; } // namespace details } // namespace Concurrency