📄 virtualprocessor.h
字号:
// Owning ring -- may change
SchedulingRing *m_pOwningRing;
// Owning virtual processor root
IVirtualProcessorRoot *m_pOwningRoot;
// Sub allocator
SubAllocator *m_pSubAllocator;
// Flag that specifies if the virtual processor is working on a ring that is different from it's owning
// ring.
volatile LONG m_fRambling;
// The index that this Virtual Processor is at in its list array
int m_listArrayIndex;
// Statistics data counters
unsigned int m_enqueuedTaskCounter;
unsigned int m_dequeuedTaskCounter;
// Statistics data checkpoints
unsigned int m_enqueuedTaskCheckpoint;
unsigned int m_dequeuedTaskCheckpoint;
// Internal context that is affinitized to and executing on this virtual processor
// This is always an InternalContextBase except on UMS in very special circumstances.
IExecutionContext * m_pExecutingContext;
_HyperNonReentrantLock m_lock;
// Unique identifier for vprocs within a scheduler.
unsigned int m_id;
// Flag specifying whether this is a virtual processor created as a result of a call to Oversubscribe.
bool m_fOversubscribed;
// Flag that is set when the virtual processor should remove itself from the scheduler at a yield point,
// i.e, either when the context executing on it calls Block or Yield, or when it is in the dispatch loop
// looking for work.
bool m_fMarkedForRetirement;
// Whether this virtual processor has reached a safe point in the code
// Used to demark when all virtual processors have reached safe points and a list array deletion
// can occur
bool m_fReachedSafePoint;
// A hidden virtual processor is one that was created for Oversubscribe but whose activation is throttled.
bool m_fHidden;
/// <summary>
/// Causes the virtual processor to remove itself from the scheduler. This is used either when oversubscription
/// ends or when the resource manager asks the vproc to retire.
/// </summary>
virtual void Retire();
// The internal context that caused this virtual processor to be created, if this is an oversubscribed vproc.
InternalContextBase * m_pOversubscribingContext;
/// <summary>
/// Affinitizes an internal context to the virtual processor.
/// </summary>
/// <param name="pContext">
/// The internal context to affinitize.
/// </param>
virtual void Affinitize(InternalContextBase *pContext);
/// <summary>
/// Returns a type-cast of pContext to an InternalContextBase or NULL if it is not.
/// </summary>
virtual InternalContextBase *ToInternalContext(IExecutionContext *pContext);
/// <summary>
/// Initializes the virtual processor. This API is called by the constructor, and when a virtual processor is to
/// be re-initialized, when it is pulled of the free pool in the list array.
/// </summary>
/// <param name="pOwningNode">
/// The owning schedule node for this virtual processor
/// </param>
/// <param name="pOwningRoot">
/// The owning IVirtualProcessorRoot
/// </param>
virtual void Initialize(SchedulingNode *pOwningNode, IVirtualProcessorRoot *pOwningRoot);
private:
friend class SchedulerBase;
friend class ContextBase;
friend class InternalContextBase;
friend class ThreadInternalContext;
friend class UMSThreadInternalContext;
friend class UMSSchedulingContext;
friend class ScheduleGroup;
friend class FairScheduleGroup;
friend class CacheLocalScheduleGroup;
friend class SchedulingNode;
friend class WorkSearchContext;
template <class T> friend class ListArray;
template<class T, class Counter> friend class List;
// Indication of throttling.
bool m_fThrottled;
// Links for throttling
VirtualProcessor *m_pNext;
VirtualProcessor *m_pPrev;
// Intrusive links for list array.
SLIST_ENTRY m_listArrayFreeLink;
// The safe point marker.
SafePointMarker m_safePointMarker;
#if _UMSTRACE
_TraceBuffer m_traceBuffer;
#endif // _UMSTRACE
/// <summary>
/// Start a worker context executing on this.virtual processor.
/// </summary>
virtual void StartupWorkerContext(ScheduleGroupBase* pGroup);
/// <summary>
/// Oversubscribes the virtual processor by creating a new virtual processor root affinitized to the same
/// execution resource as that of the current root
/// </summary>
/// <returns>
/// A virtual processor that oversubscribes this one.
/// </returns>
virtual VirtualProcessor * Oversubscribe();
/// <summary>
/// Marks the the virtual processor such that it removes itself from the scheduler, once the context it is executing
/// reaches a safe yield point. Alternatively, if the context has not started executing yet, it can be retired immediately.
/// </summary>
void MarkForRetirement();
#if _UMSTRACE
void TraceSearchedLocalRunnables();
#endif // _UMSTRACE
/// <summary>
/// Steals a context from the local runnables queue of this virtual processor.
/// </summary>
InternalContextBase *StealLocalRunnableContext()
{
#if _UMSTRACE
TraceSearchedLocalRunnables();
#endif // _UMSTRACE
InternalContextBase *pContext = m_localRunnableContexts.Steal();
if (pContext != NULL)
{
#if defined(_DEBUG)
Concurrency::details::SetContextDebugBits(pContext, CTX_DEBUGBIT_STOLENFROMLOCALRUNNABLECONTEXTS);
#endif // _DEBUG
}
return pContext;
}
/// <summary>
/// Pops a runnable context from the local runnables queue of the vproc, if it can find one.
/// </summary>
InternalContextBase *GetLocalRunnableContext()
{
#if _UMSTRACE
TraceSearchedLocalRunnables();
#endif // _UMSTRACE
if (m_localRunnableContexts.Count() > 0) // Is this check worthwhile? Yes, I believe. We'd take a fence to check otherwise.
{
InternalContextBase *pContext = m_localRunnableContexts.Pop();
#if defined(_DEBUG)
Concurrency::details::SetContextDebugBits(pContext, CTX_DEBUGBIT_POPPEDFROMLOCALRUNNABLECONTEXTS);
#endif // _DEBUG
return pContext;
}
return NULL;
}
/// <summary>
/// Resets the count of work coming in.
/// </summary>
/// <remarks>
/// This function is using modulo 2 behavior of unsigned ints to avoid overflow and
/// reset problems. For more detail look at ExternalStatistics class in externalcontextbase.h.
/// </remarks>
/// <returns>
/// Previous value of the counter.
/// </returns>
unsigned int GetEnqueuedTaskCount()
{
unsigned int currentValue = m_enqueuedTaskCounter;
unsigned int retVal = currentValue - m_enqueuedTaskCheckpoint;
// Update the checkpoint value with the current value
m_enqueuedTaskCheckpoint = currentValue;
ASSERT(retVal < INT_MAX);
return retVal;
}
/// <summary>
/// Resets the count of work being done.
/// </summary>
/// <remarks>
/// This function is using modulo 2 behavior of unsigned ints to avoid overflow and
/// reset problems. For more detail look at the ExternalStatistics class in externalcontextbase.h.
/// </remarks>
/// <returns>
/// Previous value of the counter.
/// </returns>
unsigned int GetDequeuedTaskCount()
{
unsigned int currentValue = m_dequeuedTaskCounter;
unsigned int retVal = currentValue - m_dequeuedTaskCheckpoint;
// Update the checkpoint value with the current value
m_dequeuedTaskCheckpoint = currentValue;
ASSERT(retVal < INT_MAX);
return retVal;
}
/// <summary>
/// Send a virtual processor ETW event
/// </summary>
void TraceVirtualProcessorEvent(ConcRT_EventType eventType, UCHAR level, DWORD schedulerId, DWORD vprocId)
{
if (g_TraceOn && level <= g_EnableLevel)
ThrowVirtualProcessorEvent(eventType, level, schedulerId, vprocId);
}
/// <summary>
/// Send a virtual processor ETW event
/// </summary>
static void ThrowVirtualProcessorEvent(ConcRT_EventType eventType, UCHAR level, DWORD schedulerId, DWORD vprocId);
};
} // namespace details
} // namespace Concurrency
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -