// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== // =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ // // UMSThreadInternalContext.h // // Header file containing the metaphor for a UMS thread based internal execution context/stack. // // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #pragma once namespace Concurrency { namespace details { #pragma warning(push) #pragma warning(disable: 4324) // structure was padded due to alignment specifier class UMSThreadInternalContext : public InternalContextBase { public: // // Public Methods // /// /// Construct an internal thread based context. /// UMSThreadInternalContext(SchedulerBase *pScheduler); /// /// Destroys an internal thread based context. /// virtual ~UMSThreadInternalContext(); /// /// Causes the internal context to block yielding the virtual processor to a different internal context. /// virtual void Block(); /// /// Returns the type of context /// virtual ContextKind GetContextKind() const { return UMSThreadContext; } /// /// Depending on the argument, causes the scheduler to add an extra virtual processor for the /// duration of a block of code or remove a previously added one. /// /// Oversubscribe(true); /// // some slow kernel or I/O code, etc. /// Oversubscribe(false); /// /// UMS provides automatic oversubscription. This API is largely ignored in UMS except for enforcing /// the matching Oversubscribe(false) API as per the spec. /// /// /// A boolean value specifying whether oversubscription is to be turned on or off. /// virtual void Oversubscribe(bool beginOversubscription); /// /// The method that is called when a thread proxy starts executing a particular context. The thread proxy which executes /// the context is passed into this method and must be saved and returned on a call to the get_Proxy method. /// /// /// The state under which this IExecutionContext is being dispatched. /// virtual void Dispatch(DispatchState * pDispatchState); /// /// Enters a critical region of the scheduler. Calling this guarantees that the virtual processor on which this context lives /// is guaranteed to be stable throughout the critical region. For some context types, this is virtually a NOP. For others /// (UMS), this makes it appear that blocking on the context actually blocks the UMS thread instead of triggering return to /// primary. Note that critical regions suppress asynchronous blocking but not synchronous blocking. /// virtual int EnterCriticalRegionHelper(); /// /// Exits a critical region of the scheduler. /// virtual int ExitCriticalRegionHelper(); /// /// Checks if a context is in a critical region. This is only safe from either the current context or from a UMS primary which /// has woken due to a given context blocking. /// virtual CriticalRegionType GetCriticalRegionType() const { CONCRT_COREASSERT(m_pThreadProxy != NULL); return (static_cast(m_pThreadProxy))->GetCriticalRegionType(); } /// /// Enters a hyper-critical region of the scheduler. Calling this guarantees not only the conditions of a critical region but it /// guarantees that synchronous blocking is suppressed as well. This allows for lock sharing between the primary and hyper-critical /// regions running on UTs. No lock sharing can occur between the inside of this region type and the outside of this region type /// on a UT. /// virtual int EnterHyperCriticalRegionHelper(); /// /// Exits a hyper-critical region of the scheduler. /// virtual int ExitHyperCriticalRegionHelper(); /// /// Determines whether or not the context is synchronously blocked at this given time. /// /// /// Whether context is in synchronous block state. /// virtual bool IsSynchronouslyBlocked() const { return InternalContextBase::IsSynchronouslyBlocked() || ((m_blockedState & CONTEXT_UMS_SYNC_BLOCKED) != 0); } private: friend class UMSThreadScheduler; friend class UMSSchedulingContext; friend class UMSThreadVirtualProcessor; enum BlockingType { // No blocking registered. BlockingNone, // Normal blocking BlockingNormal, // Critical blocking (e.g.: Win32 blocking call inside a normal critical region) BlockingCritical }; // The previous virtual processor we were running on. UMSThreadVirtualProcessor *m_pLastVirtualProcessor; // How we last blocked. volatile BlockingType m_blockingType; /// /// Sets the blocking type. /// void SetBlockingType(BlockingType blockingType) { m_blockingType = blockingType; } /// /// Notifies the context that it's blocked. /// /// /// Is previously running context asynchronously blocked. /// void NotifyBlocked(bool fAsynchronous); /// /// Spins until we've registered what blocking type the last block operation was and returns the type. /// BlockingType SpinOnAndReturnBlockingType(); /// /// Called before this executes on a given virtual processor. /// virtual void PrepareToRun(VirtualProcessor *pVProc); private: friend class UMSThreadScheduler; friend class UMSSchedulingContext; friend class UMSThreadVirtualProcessor; /// /// Called when the RM wakes up the thread for some reason. /// virtual void RMAwaken() { CMTRACE(MTRACE_EVT_RMAWAKEN, this, m_pVirtualProcessor, NULL); // // *NOTE*: It is absolutely imperative that this bias awakening of virtual processors to the scheduling node of // m_pVirtualProcessor. RMAwaken is called from an internal context when something comes back on the completion // list of a deactivated virtual processor. Because things are added to runnables on an internal context, a cache // local schedule group may put items in the LRC. The LRC is *NOT* checked when rambling from virtual processors // belonging to other scheduling nodes. If we unblock a context and add it to the LRC on node A and then awake // a virtual processor on node B, the work will never be found and the scheduler will deadlock. This is an artifact // of the way in which UMS completion list events come back on deactivated virtual processors. // (static_cast(m_pScheduler))->MoveCompletionListToRunnables(m_pVirtualProcessor->GetLocation()); } }; #pragma warning(pop) } // namespace details } // namespace Concurrency