// ==++==
//
// 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