Windows2003-3790/windows/advcore/duser/engine/services/context.h
2020-09-30 16:53:55 +02:00

292 lines
9.8 KiB
C++

/***************************************************************************\
*
* File: Context.h
*
* Description:
* This file declares the main Context used by the ResourceManager to manage
* independent "work contexts".
*
*
* History:
* 4/18/2000: JStall: Created
*
* Copyright (C) 2000 by Microsoft Corporation. All rights reserved.
*
\***************************************************************************/
#if !defined(SERVICES__Context_h__INCLUDED)
#define SERVICES__Context_h__INCLUDED
#pragma once
class Context;
class SubContext;
class ContextPackBuilder;
#if DBG
class Thread;
#endif // DBG
/***************************************************************************\
*****************************************************************************
*
* Context defines a pool of threads that can shared objects between the
* threads. Inside DirectUser, only one thread is allowed to execute within
* the context at a time UNLESS IT IS AN "NL" function. By dividing the
* process into independent Context's, threads that are mostly unrelated can
* operate without colliding over shared locks.
*
* Context objects are not created until the application explicitly calls
* InitGadgets(). They can also be destroyed if the application calls
* ::DeleteHandle() on the HDCONTEXT. This means that a thread may or may not
* have a Context, though usually it will.
*
*****************************************************************************
\***************************************************************************/
class Context : public BaseObject
{
public:
Context();
~Context();
static HRESULT Build(INITGADGET * pInit, DUserHeap * pHeap, Context ** ppctxNew);
virtual BOOL xwDeleteHandle();
protected:
virtual void xwDestroy();
public:
void xwPreDestroyNL();
// BaseObject Interface
public:
virtual HandleType GetHandleType() const { return htContext; }
virtual UINT GetHandleMask() const { return 0; }
// Operations
public:
enum ESlot {
slCore = 0, // Core
slMotion, // Motions
slCOUNT, // Number of sub-contexts
};
inline void MarkOrphaned();
inline BOOL IsOrphanedNL() const;
inline void Enter(); // Take shared Context lock
inline void Leave(); // Release shared Context lock
inline void Leave(BOOL fOldEnableDefer, BOOL * pfPending);
#if DBG_CHECK_CALLBACKS
inline void BeginCallback();
inline void EndCallback();
#endif
inline void BeginReadOnly();
inline void EndReadOnly();
inline BOOL IsReadOnly() const;
inline UINT GetThreadMode() const;
inline UINT GetPerfMode() const;
inline DUserHeap * GetHeap() const;
inline SubContext* GetSC(ESlot slot) const;
void AddCurrentThread();
inline BOOL IsEnableDefer() const;
inline void EnableDefer(BOOL fEnable, BOOL * pfOld);
inline void MarkPending();
DWORD xwOnIdleNL(); // Idle time processing
#if DBG_CHECK_CALLBACKS
int m_cLiveObjects; // Live objects outstanding
int m_cTotalObjects; // Total objects allocated
#endif
// Implementation
#if DBG
public:
virtual void DEBUG_AssertValid() const;
#endif
// Data
protected:
#if DBG
Thread * m_DEBUG_pthrLock; // DEBUG: Thread that locked Context
DWORD m_DEBUG_tidLock;// Thread ID of thread that locks
#endif // DBG
long m_cEnterLock; // Count of outstanding Enter()'s
#if DBG_CHECK_CALLBACKS
int m_cLiveCallbacks; // Outstanding callbacks
#endif
CritLock m_lock; // Shared access lock
DUserHeap * m_pHeap; // Initialized heap
UINT m_cReadOnly; // Count of pending "read-only" operations
BOOL m_fPending; // Deferred callbacks are pending (GIVE THIS A FULL BOOL)
BOOL m_fEnableDefer:1; // Enabled deferred messages
BOOL m_fPreDestroy:1;// Have pre-destroyed the Context
BOOL m_fOrphaned:1; // Context has been orphaned
UINT m_nThreadMode; // Threading model for Context
UINT m_nPerfMode; // Performance model
SubContext* m_rgSCs[slCOUNT]; // Sub-context information
};
/***************************************************************************\
*****************************************************************************
*
* SubContext defines a "extensibility" mechanism that allows individual
* projects in DirectUser to provide additional data to store on the context.
* To use this, the project must add a new slot in Context, derive a class
* from SubContext that is created per Context instance, and derive a class
* from ContextPackBuilder to register the extension.
*
*****************************************************************************
\***************************************************************************/
class SubContext
{
// Construction
public:
virtual ~SubContext() { }
virtual HRESULT Create(INITGADGET * pInit) { UNREFERENCED_PARAMETER(pInit); return S_OK; }
virtual void xwPreDestroyNL() PURE;
// Operations
public:
inline void SetParent(Context * pParent);
virtual DWORD xwOnIdleNL() { return INFINITE; }
// Implementation
#if DBG
public:
virtual void DEBUG_AssertValid() const;
#endif
// Data
protected:
Context * m_pParent;
};
/***************************************************************************\
*****************************************************************************
*
* ContextPackBuilder registers an SubContext "extension" to be created
* whenever a new Context is created. The constructor is expected to set the
* slot corresponding to the ESlot value.
*
*****************************************************************************
\***************************************************************************/
class ContextPackBuilder
{
// Construction
public:
// Operations
public:
virtual SubContext* New(Context * pContext) PURE;
static inline ContextPackBuilder *
GetBuilder(Context::ESlot slot);
// Data
protected:
static ContextPackBuilder *
s_rgBuilders[Context::slCOUNT];
};
#define IMPLEMENT_SUBCONTEXT(id, obj) \
class obj##Builder : public ContextPackBuilder \
{ \
public: \
virtual SubContext * New(Context * pParent) \
{ \
SubContext * psc = ProcessNew(obj); \
if (psc != NULL) { \
psc->SetParent(pParent); \
} \
return psc; \
} \
} g_##obj##B \
#define PREINIT_SUBCONTEXT(obj) \
class obj##Builder; \
extern obj##Builder g_##obj##B \
#define INIT_SUBCONTEXT(obj) \
(ContextPackBuilder *) &g_##obj##B \
inline Context * GetContext();
inline BOOL IsInitContext();
/***************************************************************************\
*****************************************************************************
*
* ContextLock provides a convenient mechanism of locking the Context and
* automatically unlocking when finished. Because ContextLock perform
* additional Context-specific actions, it is important to use a ContextLock
* to lock a Context instead of using an ObjectLock.
*
*****************************************************************************
\***************************************************************************/
class ContextLock
{
public:
enum EnableDefer
{
edNone = FALSE, // Enabled deferred messages
edDefer = TRUE, // Don't enable deferred messages
};
inline ContextLock();
inline ~ContextLock();
BOOL LockNL(ContextLock::EnableDefer ed, Context * pctxThread = GetContext());
// Data (public access)
Context * pctx;
BOOL fOldDeferred;
};
class ReadOnlyLock
{
public:
inline ReadOnlyLock(Context * pctxThread = GetContext());
inline ~ReadOnlyLock();
Context * pctx;
};
#if DBG_CHECK_CALLBACKS
#define BEGIN_CALLBACK() \
__try { \
if (!IsInitThread()) { \
AlwaysPromptInvalid("DirectUser has been uninitialized before processing a callback (1)"); \
} \
GetContext()->BeginCallback(); \
#define END_CALLBACK() \
} __finally { \
GetContext()->EndCallback(); \
if (!IsInitThread()) { \
AlwaysPromptInvalid("DirectUser has been uninitialized while processing a Message (2)"); \
} \
}
#endif // DBG_CHECK_CALLBACKS
#include "Context.inl"
#endif // SERVICES__Context_h__INCLUDED