📄 umsthreadproxy.cpp
字号:
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
//
// UMSThreadProxy.h
//
// Proxy for a UMS thread.
//
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
#include "concrtinternal.h"
namespace Concurrency
{
namespace details
{
/// <summary>
/// Constructs a thread proxy.
/// </summary>
UMSThreadProxy::UMSThreadProxy(IThreadProxyFactory * pFactory, PUMS_COMPLETION_LIST pStartupList, unsigned int stackSize) :
m_pFactory(pFactory),
m_stackSize(stackSize),
m_yieldAction(ActionNone),
m_activationCause(ActivationCauseNone),
m_pTransmogrification(NULL),
m_hPhysicalContext(NULL),
m_hBlock(NULL),
m_pUMSContext(NULL),
m_pRoot(NULL),
m_pLastRoot(NULL),
m_criticalRegionCount(0),
m_hyperCriticalRegionCount(0),
m_fCanceled(FALSE),
m_fIdlePooled(false),
m_blockingType(BlockingNone)
#if defined(_DEBUG)
,m_UMSDebugBits(0)
,m_fShutdownValidations(false)
,m_lastRunPrepareTimeStamp(0)
#endif // _DEBUG
{
m_hBlock = CreateEventW(NULL, FALSE, FALSE, NULL);
if (m_hBlock == NULL)
throw scheduler_resource_allocation_error(HRESULT_FROM_WIN32(GetLastError()));
m_id = ResourceManager::GetThreadProxyId();
UMS_CREATE_THREAD_ATTRIBUTES umsAttributes;
PPROC_THREAD_ATTRIBUTE_LIST pAttributeList;
SIZE_T sizeAttributeList;
if (!UMS::CreateUmsThreadContext(&m_pUMSContext))
throw scheduler_resource_allocation_error(HRESULT_FROM_WIN32(GetLastError()));
UMSBaseObject *pThis = this;
if (!UMS::SetUmsThreadInformation(m_pUMSContext, UmsThreadUserContext, &pThis, sizeof(pThis)))
throw scheduler_resource_allocation_error(HRESULT_FROM_WIN32(GetLastError()));
umsAttributes.UmsVersion = UMS_VERSION;
umsAttributes.UmsContext = m_pUMSContext;
umsAttributes.UmsCompletionList = pStartupList;
UMS::InitializeProcThreadAttributeList(NULL, 1, 0, &sizeAttributeList);
ASSERT(GetLastError() == ERROR_INSUFFICIENT_BUFFER);
pAttributeList = reinterpret_cast<PPROC_THREAD_ATTRIBUTE_LIST>(new char[sizeAttributeList]);
if (!UMS::InitializeProcThreadAttributeList(pAttributeList, 1, 0, &sizeAttributeList))
{
delete[] (reinterpret_cast<char*>(pAttributeList));
throw scheduler_resource_allocation_error(HRESULT_FROM_WIN32(GetLastError()));
}
if (!UMS::UpdateProcThreadAttribute(pAttributeList, 0, PROC_THREAD_ATTRIBUTE_UMS_THREAD, &umsAttributes, sizeof(UMS_CREATE_THREAD_ATTRIBUTES), NULL, NULL))
{
delete[] (reinterpret_cast<char *>(pAttributeList));
throw scheduler_resource_allocation_error(HRESULT_FROM_WIN32(GetLastError()));
}
m_hPhysicalContext = UMS::CreateRemoteThreadEx(GetCurrentProcess(),
NULL,
stackSize*KB,
UMSThreadProxyMain,
this,
STACK_SIZE_PARAM_IS_A_RESERVATION,
pAttributeList,
&m_threadId);
UMS::DeleteProcThreadAttributeList(pAttributeList);
delete[] (reinterpret_cast<char *>(pAttributeList));
if (m_hPhysicalContext == NULL)
throw scheduler_resource_allocation_error(HRESULT_FROM_WIN32(GetLastError()));
}
/// <summary>
/// Destroys a thread proxy.
/// </summary>
UMSThreadProxy::~UMSThreadProxy()
{
if (m_hBlock != NULL)
CloseHandle(m_hBlock);
if (m_hPhysicalContext != NULL)
CloseHandle(m_hPhysicalContext);
if (m_pUMSContext != NULL)
UMS::DeleteUmsThreadContext(m_pUMSContext);
}
/// <summary>
/// Returns a process unique identifier for the thread proxy.
/// </summary>
unsigned int UMSThreadProxy::GetId() const
{
return m_id;
}
/// <summary>
/// Thread start routine for proxies.
/// </summary>
/// <param name="lpParameter">
/// Pointer to the thread proxy
/// </param>
DWORD CALLBACK UMSThreadProxy::UMSThreadProxyMain(LPVOID lpParameter)
{
UMSThreadProxy* pThreadProxy = reinterpret_cast<UMSThreadProxy*> (lpParameter);
pThreadProxy->ReadyForDispatch();
CORE_ASSERT(pThreadProxy->GetCriticalRegionType() == OutsideCriticalRegion || pThreadProxy->m_pRoot->IsDeleting());
pThreadProxy->Dispatch();
ASSERT(pThreadProxy->m_fCanceled);
//
// The data structure needs to remain until we jump back to the primary executing it for the last time and the primary detects that
// the thread has terminated. Otherwise, the primary will read an invalid data structure to determine what just terminated!
//
return 0;
}
/// <summary>
/// Indicate that the thread proxy is ready for dispatch.
/// </summary>
void UMSThreadProxy::ReadyForDispatch()
{
// If the UT is started up on a dedicated primary then we need not be in a hypercritical
// region. We enter a hypercritical region here to ensure that this would work if we decide
// to move UT startup to vprocs.
EnterHyperCriticalRegion();
m_yieldAction = ActionStartup;
UMS::UmsThreadYield(this);
// Critical region count will be cleared on dispatch.
}
/// <summary>
/// Returns our understanding of a UMS context (a UMS thread proxy) from the UMS system's understanding (a UMS_CONTEXT)
/// </summary>
/// <param name="pUMSContext">
/// UMS context
/// </param>
/// <returns>
/// UMS thread proxy
/// </returns>
UMSThreadProxy *UMSThreadProxy::FromUMSContext(PUMS_CONTEXT pUMSContext)
{
if (pUMSContext == NULL)
return NULL;
UMSBaseObject *pObj = NULL;
UMSThreadProxy *pProxy = NULL;
ULONG returnLength;
if (!UMS::QueryUmsThreadInformation(pUMSContext, UmsThreadUserContext, reinterpret_cast <PVOID> (&pObj), sizeof(pObj), &returnLength))
throw scheduler_resource_allocation_error(HRESULT_FROM_WIN32(GetLastError()));
ASSERT(returnLength == sizeof(pObj));
if (pObj != NULL && !pObj->IsPrimary())
pProxy = static_cast<UMSThreadProxy *>(pObj);
return pProxy;
}
/// <summary>
/// Returns our understanding of a UMS context (a UMS thread proxy) from the SLIST_ENTRY used to
/// place it on an SLIST (e.g.: the transfer list).
/// </summary>
/// <param name="pListEntry">
/// Pointer to the SList entry in the thread proxy
/// </param>
/// <returns>
/// UMS thread proxy
/// </returns>
UMSThreadProxy *UMSThreadProxy::FromListEntry(PSLIST_ENTRY pListEntry)
{
if (pListEntry == NULL) return NULL;
return CONTAINING_RECORD(pListEntry, UMSThreadProxy, m_listEntry);
}
/// <summary>
/// Switch from the current thread proxy to pProxy.
/// </summary>
/// <param name="pProxy">
/// The thread proxy to switch to.
/// </param>
/// <param name="switchState">
/// The reason for the switch.
/// </param>
void UMSThreadProxy::InternalSwitchTo(UMSThreadProxy *pProxy, SwitchingProxyState switchState)
{
const YieldAction stateActions[] = {
ActionSwitchToAndRetire /* Idle */,
ActionSwitchTo /* Blocking */,
ActionTransmogrify /* Nesting */
};
//
// Manipulations of m_yieldAction need to be guarded under a hyper-critical region. We cannot tolerate a page fault happening
// which corrupts our state.
//
EnterHyperCriticalRegion();
//
// On nesting, we have to transmogrify the currently running UMS thread to a "virtual"-thread so that it can continue
// to run as an external context of a nested scheduler without having to be scheduled atop a virtual processor (something
// outside our model).
//
if (switchState == Nesting)
{
CORE_ASSERT(m_pTransmogrification == NULL);
//
// We cannot perform an allocation or thread creation here, so we ask the transmogrificator to do this for us. Oh fun.
//
Transmogrificator *pTransmogrificator = m_pRoot->GetResourceManager()->GetTransmogrificator();
pTransmogrificator->PerformTransmogrification(this);
}
RVPMTRACE(switchState == Idle ? MTRACE_EVT_SWITCHTO_IDLE : (switchState == Blocking ? MTRACE_EVT_SWITCHTO_BLOCKING : MTRACE_EVT_SWITCHTO_NESTING), this, m_pRoot, pProxy);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -