📄 internalcontextbase.h
字号:
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
//
// InternalContextBase.h
//
// Header file containing the base class definition for an internal execution context.
//
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
#pragma once
namespace Concurrency
{
namespace details
{
/// <summary>
/// Implements the base class for ConcRT internal contexts.
/// </summary>
class InternalContextBase : public IExecutionContext, public ContextBase
{
public:
using ContextBase::GetId;
//
// Public methods
//
/// <summary>
/// Constructs the base class object for an internal context.
/// </summary>
InternalContextBase(SchedulerBase *pScheduler);
/// <summary>
/// Causes the internal context to block yielding the virtual processor to a different internal context.
/// </summary>
virtual void Block();
/// <summary>
/// Unblocks the internal context putting it on a runnables collection in its schedule group.
/// </summary>
virtual void Unblock();
/// <summary>
/// Determines whether or not the context is synchronously blocked at this given time.
/// </summary>
/// <returns>
/// Whether context is in synchronous block state.
/// </returns>
virtual bool IsSynchronouslyBlocked() const
{
return (m_contextSwitchingFence == 2);
}
/// <summary>
/// Yields the virtual processor to a different runnable internal context if one is found.
/// </summary>
virtual void Yield();
/// <summary>
/// Yields the virtual processor to a different runnable internal context if one is found.
///
/// This is intended for spin loops.
/// </summary>
virtual void SpinYield();
/// <summary>
/// See comments for Concurrency::Context::Oversubscribe.
/// </summary>
virtual void Oversubscribe(bool beginOversubscription);
/// <summary>
/// Destroys the base class object for an internal context.
/// </summary>
virtual ~InternalContextBase();
/// <summary>
/// Returns an identifier to the virtual processor the context is currently executing on, if any.
/// </summary>
virtual unsigned int GetVirtualProcessorId() const;
/// <summary>
/// Toggle the flag that ensures that scheduler is not deleted until adding is completely finished.
/// </summary>
/// <param name="value">
/// The value to set the flag to.
/// </param>
void CrossGroupRunnable(LONG value) { m_fCrossGroupRunnable = value; }
/// <summary>
/// Set the value of the oversubscribed virtual processor for a context that invokes Oversubscribe.
/// </summary>
void SetOversubscribedVProc(VirtualProcessor * pVirtualProcessor) { m_pOversubscribedVProc = pVirtualProcessor; }
/// <summary>
/// Called to retreive the oversubscribed vproc and reset it to null.
/// </summary>
VirtualProcessor * GetAndResetOversubscribedVProc(VirtualProcessor * pExpectedVirtualProcessor);
/// <summary>
/// Returns a scheduler unique identifier for the context.
/// </summary>
/// <returns>
/// The Id of the context.
/// </returns>
virtual unsigned int GetId() const;
/// <summary>
/// Returns the scheduler to which this context belongs.
/// </summary>
/// <returns>
/// The owning scheduler.
/// </returns>
virtual IScheduler * GetScheduler();
/// <summary>
/// Returns the thread proxy which is executing this context. Until the Dispatch method has been called on the given
/// context, this will return NULL. Once the Dispatch method has been called, this returns the IThreadProxy which
/// was passed into the Dispatch method.
/// </summary>
/// <returns>
/// The thread proxy which dispatched this particular context, otherwise NULL.
/// </returns>
virtual IThreadProxy * GetProxy();
#if _DEBUG
// _DEBUG helper
DWORD GetThreadId() const;
#endif
/// <summary>
/// Sets the thread proxy which is executing this context. The caller must save this and return it upon a call to the GetProxy method.
/// Note that the resource manager guarantees stability of the thread proxy while inside the Dispatch method.
/// </summary>
/// <param name="pThreadProxy">
/// The thread proxy which dispatched this particular context.
/// </param>
/// <returns>
/// An indication of success.
/// </returns>
virtual void SetProxy(IThreadProxy *pThreadProxy);
/// <summary>
/// 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.
/// </summary>
/// <param name="pDispatchState">
/// The state under which this IExecutionContext is being dispatched.
/// </param>
virtual void Dispatch(DispatchState * pDispatchState);
/// <summary>
/// Allocates a block of memory of the size specified.
/// </summary>
/// <param name="numBytes">
/// Number of bytes to allocate.
/// </param>
/// <returns>
/// A pointer to newly allocated memory.
/// </returns>
virtual void* Alloc(size_t numBytes);
/// <summary>
/// Frees a block of memory previously allocated by the Alloc API.
/// </summary>
/// <param name="pAllocation">
/// A pointer to an allocation previously allocated by Alloc.
/// </param>
virtual void Free(void* pAllocation);
/// <summary>
/// Swaps the existing schedule group with the one supplied. This function should be called when the context already
/// has a schedule group. It decrements the existing group reference count, and references the new one if the caller
/// indicates so.
/// </summary>
/// <param name="pNewGroup">
/// The new group to assign to the context. This may be NULL.
/// </param>
/// <param name="referenceNewGroup">
/// Whether the context should reference the new group. In some cases there may be an existing reference
/// transferred to the context, in which case this parameter is false.
/// </param>
void SwapScheduleGroup(ScheduleGroupBase* pNewGroup, bool referenceNewGroup = false);
/// <summary>
/// Increments the count of work coming in.
/// </summary>
void IncrementEnqueuedTaskCounter()
{
if (m_pScheduler->IsUMSScheduler())
IncrementEnqueuedTaskCounterHelper();
else
m_pVirtualProcessor->m_enqueuedTaskCounter++;
}
void IncrementEnqueuedTaskCounterHelper();
/// <summary>
/// Increments the count of work being done.
/// </summary>
void IncrementDequeuedTaskCounter()
{
if (m_pScheduler->IsUMSScheduler())
IncrementDequeuedTaskCounterHelper(1);
else
m_pVirtualProcessor->m_dequeuedTaskCounter++;
}
/// <summary>
/// Increments the count of work being done.
/// </summary>
void IncrementDequeuedTaskCounter(unsigned int count)
{
if (m_pScheduler->IsUMSScheduler())
IncrementDequeuedTaskCounterHelper(count);
else
m_pVirtualProcessor->m_dequeuedTaskCounter += count;
}
void IncrementDequeuedTaskCounterHelper(unsigned int count);
/// <summary>
/// In some cases internal context has not yet recieved a virtual processor so we have
/// to save the fact that the work was dequeued and we'll update it in Affinitize.
/// </summary>
void SaveDequeuedTask()
{
ASSERT(!m_fHasDequeuedTask);
m_fHasDequeuedTask = true;
}
/// <summary>
/// Notifies that some work was skipped by an iteration of dispatch loop of this context
/// </summary>
void NotifyWorkSkipped()
{
m_fWorkSkipped = true;
}
#if defined(_DEBUG)
/// <summary>
/// Gets the debug bits.
/// </summary>
DWORD GetDebugBits() const
{
return m_ctxDebugBits;
}
/// <summary>
/// Sets a series of internal debugging bits for the context.
/// </summary>
/// <param name="bits">
/// A bitmapped series of CTX_DEBUGBIT_* flags to set within the context.
/// </param>
void SetDebugBits(DWORD bits)
{
m_ctxDebugBits |= bits;
}
/// <summary>
/// Clears a series of internal debugging bits for the context.
/// </summary>
/// <param name="bits">
/// A bitmapped series of CTX_DEBUGBIT_* flags to clear within the context.
/// </param>
void ClearDebugBits(DWORD bits)
{
m_ctxDebugBits &= ~bits;
}
/// <summary>
/// Completelky clears all debug bits.
/// </summary>
void ClearDebugBits()
{
m_ctxDebugBits = 0;
}
void NotifyAcquired()
{
m_lastAcquiredTid = GetCurrentThreadId();
}
#endif // _DEBUG
#if _UMSTRACE
void Trace(int traceEvt, void *pCtx, void *pVproc, ULONG_PTR data)
{
m_traceBuffer.Trace(traceEvt, pCtx, pVproc, data);
}
#endif // _UMSTRACE
/// <summary>
/// Returns whether the context is in the idle pool or not. Finalization will call this during the sweep phase to
// determine all the blocked contexts. A context in the idle pool is considered "not blocked".
/// </summary>
bool IsIdle() const
{
return m_fIdle;
}
/// <summary>
/// Prepare a context for execution by associating a scheduler group/chore with it. Scheduler
// shall call this routine before executing an internal context
/// </summary>
void PrepareForUse(ScheduleGroupBase* pGroup, _Chore *pChore, bool choreStolen);
/// <summary>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -