You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
389 lines
9.7 KiB
389 lines
9.7 KiB
/***************************************************************************\
|
|
*
|
|
* File: Context.inl
|
|
*
|
|
* History:
|
|
* 4/18/2000: JStall: Created
|
|
*
|
|
* Copyright (C) 2000 by Microsoft Corporation. All rights reserved.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
|
|
#if !defined(SERVICES__Context_inl__INCLUDED)
|
|
#define SERVICES__Context_inl__INCLUDED
|
|
#pragma once
|
|
|
|
#include "Thread.h"
|
|
|
|
#if !USE_DYNAMICTLS
|
|
extern __declspec(thread) Context * t_pContext;
|
|
#endif
|
|
|
|
/***************************************************************************\
|
|
*****************************************************************************
|
|
*
|
|
* class Context
|
|
*
|
|
*****************************************************************************
|
|
\***************************************************************************/
|
|
|
|
//------------------------------------------------------------------------------
|
|
inline Context *
|
|
GetContext()
|
|
{
|
|
#if USE_DYNAMICTLS
|
|
Assert(IsInitThread());
|
|
|
|
Context * pContext = GetThread()->GetContext();
|
|
#else
|
|
Context * pContext = t_pContext;
|
|
#endif
|
|
AssertMsg(pContext != NULL, "Using uninitialized Context");
|
|
return pContext;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
__forceinline Context *
|
|
RawGetContext()
|
|
{
|
|
#if USE_DYNAMICTLS
|
|
Thread * pthr = RawGetThread();
|
|
if (pthr != NULL) {
|
|
return pthr->GetContext();
|
|
} else {
|
|
return (Context *) pthr;
|
|
}
|
|
#else
|
|
return t_pContext;
|
|
#endif
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
inline BOOL
|
|
IsInitContext()
|
|
{
|
|
#if USE_DYNAMICTLS
|
|
Thread * pthr = RawGetThread();
|
|
return (pthr != NULL) && (pthr->GetContext() != NULL);
|
|
#else
|
|
return t_pContext != NULL;
|
|
#endif
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
inline Context *
|
|
CastContext(BaseObject * pbase)
|
|
{
|
|
if ((pbase != NULL) && (pbase->GetHandleType() == htContext)) {
|
|
return (Context *) pbase;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
inline const Context *
|
|
CastContext(const BaseObject * pbase)
|
|
{
|
|
if ((pbase != NULL) && (pbase->GetHandleType() == htContext)) {
|
|
return (const Context *) pbase;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
inline void
|
|
Context::MarkOrphaned()
|
|
{
|
|
// NOTE: A Context may be orphaned multiple times from different threads.
|
|
m_fOrphaned = TRUE;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
inline BOOL
|
|
Context::IsOrphanedNL() const
|
|
{
|
|
return m_fOrphaned;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
inline void
|
|
Context::Enter()
|
|
{
|
|
AssertMsg(m_cRef > 0, "Context must be valid to be locked");
|
|
m_lock.Enter();
|
|
Lock();
|
|
if (m_cEnterLock++ == 0) {
|
|
//
|
|
// Just entered, so no deferred callbacks yet.
|
|
//
|
|
m_fPending = FALSE;
|
|
}
|
|
|
|
#if DBG
|
|
if (m_cEnterLock > 30) {
|
|
Trace("WARNING: DUser: m_cEnterLock is getting high (%d) for Context 0x%p.\n", m_cEnterLock, this);
|
|
Trace(" Probably have an Enter() without an matching Leave().\n");
|
|
}
|
|
#endif
|
|
|
|
#if DBG
|
|
m_DEBUG_pthrLock = IsInitThread() ? GetThread() : (Thread *) (void *) 0x12345678;
|
|
m_DEBUG_tidLock = GetCurrentThreadId();
|
|
#endif // DBG
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
inline void
|
|
Context::Leave()
|
|
{
|
|
#if DBG
|
|
m_DEBUG_pthrLock = NULL;
|
|
m_DEBUG_tidLock = 0;
|
|
#endif // DBG
|
|
|
|
AssertMsg(m_cEnterLock > 0, "Must have a matching Enter() for every Leave()");
|
|
--m_cEnterLock;
|
|
|
|
AssertMsg(m_cRef > 0, "Context should still be valid when unlocked");
|
|
if (xwUnlock()) {
|
|
//
|
|
// Only can access the object if it is still valid after being
|
|
// xwUnlock()'d.
|
|
//
|
|
|
|
m_lock.Leave();
|
|
}
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
inline void
|
|
Context::Leave(BOOL fOldEnableDefer, BOOL * pfPending)
|
|
{
|
|
#if DBG
|
|
m_DEBUG_pthrLock = NULL;
|
|
m_DEBUG_tidLock = 0;
|
|
#endif // DBG
|
|
|
|
AssertMsg(m_cEnterLock > 0, "Must have a matching Enter() for every Leave()");
|
|
*pfPending = (--m_cEnterLock == 0) && m_fPending && m_fEnableDefer; // Must --m_cEnterLock first
|
|
m_fEnableDefer = fOldEnableDefer;
|
|
|
|
AssertMsg(m_cRef > 0, "Context should still be valid when unlocked");
|
|
if (xwUnlock()) {
|
|
//
|
|
// Only can access the object if it is still valid after being
|
|
// xwUnlock()'d.
|
|
//
|
|
|
|
m_lock.Leave();
|
|
}
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
inline DUserHeap *
|
|
Context::GetHeap() const
|
|
{
|
|
AssertMsg(m_pHeap != NULL, "Heap should be specified for Context");
|
|
return m_pHeap;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
inline SubContext *
|
|
Context::GetSC(ESlot slot) const
|
|
{
|
|
return m_rgSCs[slot];
|
|
}
|
|
|
|
|
|
#if DBG_CHECK_CALLBACKS
|
|
|
|
//------------------------------------------------------------------------------
|
|
inline void
|
|
Context::BeginCallback()
|
|
{
|
|
m_cLiveCallbacks++;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
inline void
|
|
Context::EndCallback()
|
|
{
|
|
Assert(m_cLiveCallbacks > 0);
|
|
m_cLiveCallbacks--;
|
|
}
|
|
|
|
#endif // DBG_CHECK_CALLBACKS
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
inline void
|
|
Context::BeginReadOnly()
|
|
{
|
|
AssertMsg(m_cEnterLock > 0, "Must have Enter()'d the context before making read-only");
|
|
m_cReadOnly++;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
inline void
|
|
Context::EndReadOnly()
|
|
{
|
|
Assert(m_cEnterLock > 0);
|
|
m_cReadOnly--;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
inline BOOL
|
|
Context::IsReadOnly() const
|
|
{
|
|
return m_cReadOnly;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
inline UINT
|
|
Context::GetThreadMode() const
|
|
{
|
|
return m_nThreadMode;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
inline UINT
|
|
Context::GetPerfMode() const
|
|
{
|
|
return m_nPerfMode;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
inline BOOL
|
|
Context::IsEnableDefer() const
|
|
{
|
|
return m_fEnableDefer;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
__forceinline void
|
|
Context::EnableDefer(BOOL fEnable, BOOL * pfOld)
|
|
{
|
|
if (pfOld != NULL) {
|
|
*pfOld = m_fEnableDefer;
|
|
}
|
|
|
|
m_fEnableDefer = fEnable;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
inline void
|
|
Context::MarkPending()
|
|
{
|
|
AssertMsg(m_fEnableDefer, "Deferred callbacks must be enabled");
|
|
m_fPending = TRUE;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
*****************************************************************************
|
|
*
|
|
* class SubContext
|
|
*
|
|
*****************************************************************************
|
|
\***************************************************************************/
|
|
|
|
//------------------------------------------------------------------------------
|
|
inline void
|
|
SubContext::SetParent(Context * pParent)
|
|
{
|
|
AssertMsg(m_pParent == NULL, "Must set only once");
|
|
m_pParent = pParent;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
*****************************************************************************
|
|
*
|
|
* class ContextPackBuilder
|
|
*
|
|
*****************************************************************************
|
|
\***************************************************************************/
|
|
|
|
//------------------------------------------------------------------------------
|
|
inline ContextPackBuilder *
|
|
ContextPackBuilder::GetBuilder(Context::ESlot slot)
|
|
{
|
|
AssertMsg(s_rgBuilders[slot] != NULL, "Build must be defined");
|
|
return s_rgBuilders[slot];
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
*****************************************************************************
|
|
*
|
|
* Various lock helpers
|
|
*
|
|
*****************************************************************************
|
|
\***************************************************************************/
|
|
|
|
//------------------------------------------------------------------------------
|
|
inline
|
|
ContextLock::ContextLock()
|
|
{
|
|
pctx = NULL;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
inline
|
|
ContextLock::~ContextLock()
|
|
{
|
|
if (pctx != NULL) {
|
|
//
|
|
// Leaving the lock, so notify the Thread and give it a chance to do
|
|
// anything it needed afterwards.
|
|
//
|
|
|
|
BOOL fPending;
|
|
pctx->Leave(fOldDeferred, &fPending);
|
|
|
|
if (fPending) {
|
|
GetThread()->xwLeftContextLockNL();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
inline
|
|
ReadOnlyLock::ReadOnlyLock(Context * pctxThread)
|
|
{
|
|
pctx = pctxThread;
|
|
pctx->BeginReadOnly();
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
inline
|
|
ReadOnlyLock::~ReadOnlyLock()
|
|
{
|
|
pctx->EndReadOnly();
|
|
}
|
|
|
|
|
|
#endif // SERVICES__Context_inl__INCLUDED
|