// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== // =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ // // Transmogrificator.h // // A background thread which has the purpose of transmogrifying UTs to make them appear as NT threads to the layer // above them. This is done via queued creation of a TransmogrifiedPrimary. The reason there is a background thread // that does this is that we can only make a determination of when to transmogrify at a SwitchTo(..., Nesting) or subsequent // SwitchOut in the RM. At this point, we **CANNOT** perform a heap allocation without hopelessly confusing the scheduler // or deadlocking it. But we **MUST** not allow the running thread to continue without performing a heap allocation. The // catch-22 is solved here by returning the virtual processor (allowing the SwitchTo to happen) and letting it run things // which may hold the heap lock. The original UT (which certainly isn't holding any blasted locks at this stage) isn't run again // until this thread can perform the allocation and get it set up. // // Note that this thread may **VERY WELL** cache transmogrified primaries in order to avoid having to do the thread creation and // heap allocations on each nesting. // // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- namespace Concurrency { namespace details { // // The maximum number of threads we will cache on the side to perform transmogrifications for nesting within a UMS scheduler. These // are *NOT* pre-created, but they are cached up to this depth once they are created and done with. // #define TRANSMOGRIFICATOR_CACHE_DEPTH 8 class Transmogrificator { public: /// /// Constructs a new Transmogrificator. /// Transmogrificator(); /// /// Destructs the Transmogrificator. /// ~Transmogrificator(); /// /// Performs a transmogrification of pProxy. The Transmogrified primary which is created will not start until /// UnblockTransmogrification is called. /// /// /// The thread proxy which is being transmogrified. /// void PerformTransmogrification(UMSThreadProxy *pProxy); /// /// Unblocks the transmogrification which was created in PerformTransmogrification. Note that PerformTransmogrification /// must be called first! /// /// /// The thread proxy whose transmogrification is being unblocked. /// void UnblockTransmogrification(UMSThreadProxy *pProxy); /// /// Called in order to return a cached transmogrified primary to the transmogrificator. /// void ReturnToCache(CachedTransmogrifiedPrimary *pTransmogrifiedPrimary); private: /// /// The thread function which awakens when necessary to bind proxies which wish to be transmogrified with new /// TransmogrifiedPrimary objects. /// void BeginTransmogrifying(); /// /// Callback handler for m_hUnblock /// static void CALLBACK TransmogrificationHandler(PVOID parameter, BOOLEAN is_timeout); // Handle to the transmogrificator thread. HANDLE m_hThread; // Handle to the wait in RegisterWaitForSingleObject HANDLE m_hWaitHandle; // Notification that there are pollers to poll. The background poller stays asleep otherwise. HANDLE m_hUnblock; // The count of proxies queued for transmogrification. volatile LONG m_queuedProxyCount; // The list of proxies that haven't yet gotten a transmogrified primary. SafeRWList m_queuedProxies; // The number of cached proxies and the lock-free list. volatile LONG m_cacheCount; SLIST_HEADER m_cachedProxies; // must be 16-byte aligned in x64 }; } // namespace details } // namespace Concurrency