// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== // =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ // // TransmogrifiedPrimary.h // // A very special primary thread whose sole purpose is to "virtually" transmogrify a UMS thread into an NT thread // for the purposes of scheduler nesting. Note that this class is also reused in any circumstance where similar behavior // is required. // // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #pragma once namespace Concurrency { namespace details { /// /// A base interface for all UMS thread abstractions so that we could determine if the /// current thread is a primary or a UT. /// class UMSBaseObject { public: virtual bool IsPrimary() = 0; virtual ~UMSBaseObject(); }; class TransmogrifiedPrimary : public UMSBaseObject { public: /// /// Creates a new primary which transmogrifies a series of proxies (via ExecuteToCompletion/QueueToCompletion) into "virtual threads" until /// they exit -- one at a time. /// TransmogrifiedPrimary(); /// /// Destroys the transmogrified primary. /// ~TransmogrifiedPrimary(); /// /// Queues a thread to execute to completion and asynchronously returns. It is not safe to utilize this method and ExecuteToCompletion /// simultaneously. /// /// /// The proxy to queue to completion. /// void QueueToCompletion(UMSThreadProxy *pProxy); /// /// Shuts down a multiple binding transmogrified primary. /// void Shutdown() { SetEvent(m_hRetire); } /// /// Indicates whether this is a primary or not. /// virtual bool IsPrimary() { return true; } UMSBackgroundPoller *GetUMSBackgroundPoller() { return &m_poller; } protected: /// /// Called when a transmogrification is complete. /// virtual void CompletedTransmogrification() { } private: // The UMS thread that this primary transmogrifies to a "virtual"-thread. UMSThreadProxy *m_pBoundProxy; // The primary thread. HANDLE m_hPrimary; // UMS Completion list event HANDLE m_hCompletionListEvent; // The block handle (we are signaled when the old primary indicates that transmogrification is complete) HANDLE m_hBlock; // The retirement handle HANDLE m_hRetire; // The TID of the primary thread. DWORD m_primaryId; // The UMS completion list for this transmogrified primary. PUMS_COMPLETION_LIST m_pCompletionList; // // For multiple bindings. // SafeSQueue m_queuedExecutions; volatile LONG m_queueCount; // // For poller // UMSBackgroundPoller m_poller; /// /// Initializes the class. /// void Initialize(); /// /// Unblocks the transmogrified primary so that it can execute the UT it is transmogrifying. /// void Unblock() { SetEvent(m_hBlock); } /// /// Search for new work /// UMSThreadProxy * SearchForWork(); /// /// Waits for new work /// UMSThreadProxy * WaitForWork(); /// /// Handle blocking of a UT /// UMSThreadProxy * HandleBlocking(); /// /// Handle yielding of a UT /// UMSThreadProxy * HandleYielding(); /// /// Execute the given proxy on this primary /// /// /// The proxy to run /// void Execute(UMSThreadProxy *pProxy); /// /// Waits for the blocked proxy to be ready /// /// /// The proxy that is blocked /// UMSThreadProxy * WaitForBlockedThread(UMSThreadProxy * pProxy); /// /// The UMS primary function. This is invoked when the primary 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 primary pointer) /// static void NTAPI PrimaryInvocation(UMS_SCHEDULER_REASON reason, ULONG_PTR activationPayload, PVOID pData); /// /// The primary thread. /// /// /// The TransmogrifiedPrimary that the primary manages. /// static DWORD CALLBACK PrimaryMain(LPVOID pContext); }; /// /// A transmogrified primary which places itself upon the transmogrificator's cache at the end of each transmogrification. /// class CachedTransmogrifiedPrimary : public TransmogrifiedPrimary { public: /// /// Construct a new cached transmogrified primary. The primary will be placed back upon the cache of the specified transmogrificator /// at the end of each transmogrification. /// CachedTransmogrifiedPrimary(Transmogrificator *pTransmogrificator); protected: /// /// Called when a transmogrification is complete. /// virtual void CompletedTransmogrification(); private: friend class Transmogrificator; // An entry for this primary on the transmogrificator's cache. SLIST_ENTRY m_cacheEntry; Transmogrificator *m_pTransmogrificator; }; } // namespace details } // namespace Concurrency