//+-------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1992. // // File: context.hxx // // Contents: Per-context things header // // Classes: CPerContext // // History: 14-Aug-92 DrewB Created // //--------------------------------------------------------------- #ifndef __CONTEXT_HXX__ #define __CONTEXT_HXX__ #include #include #if WIN32 >= 100 #include #include #endif #ifdef MULTIHEAP #include extern SCODE DfSyncSharedMemory(ULONG ulHeapName); #else extern SCODE DfSyncSharedMemory(void); #endif interface ILockBytes; // Maximum length of a mutex name for contexts #define CONTEXT_MUTEX_NAME_LENGTH 32 //+-------------------------------------------------------------- // // Class: CPerContext (pc) // // Purpose: Holds per-context information // // Interface: See below // // History: 14-Aug-92 DrewB Created // //--------------------------------------------------------------- class CGlobalContext; SAFE_DFBASED_PTR(CBasedGlobalContextPtr, CGlobalContext); class CPerContext : public CContext { public: inline CPerContext( IMalloc *pMalloc, ILockBytes *plkbBase, CFileStream *pfstDirty, ILockBytes *plkbOriginal, ULONG ulOpenLock); inline CPerContext(IMalloc *pMalloc); inline void SetILBInfo(ILockBytes *plkbBase, CFileStream *pfstDirty, ILockBytes *plkbOriginal, ULONG ulOpenLock); inline void SetLockInfo(BOOL fTakeLock, DFLAGS dfOpenLock); inline SCODE InitNewContext(void); inline SCODE InitFromGlobal(CGlobalContext *pgc); ~CPerContext(void); inline LONG AddRef(void); inline LONG Release(void); #ifdef ASYNC inline LONG AddRefSharedMem(void); inline LONG ReleaseSharedMem(void); inline LONG DecRef(void); #endif inline ILockBytes *GetBase(void) const; inline CFileStream *GetDirty(void) const; inline ILockBytes *GetOriginal(void) const; inline ULONG GetOpenLock(void) const; inline ContextId GetContextId(void) const; inline CGlobalContext *GetGlobal(void) const; inline IMalloc * GetMalloc(void) const; inline void SetOpenLock(ULONG ulOpenLock); inline SCODE TakeSem(DWORD dwTimeout); inline void ReleaseSem(void); #ifdef MULTIHEAP inline SCODE SetAllocatorState(CPerContext **pppcPrev, CSmAllocator *psma); inline SCODE GetThreadAllocatorState(); inline CSmAllocator *SetThreadAllocatorState(CPerContext **pppcPrev); inline void UntakeSem() { ReleaseSem(); }; // workaround macro in docfilep #endif #ifdef ASYNC inline IFillInfo * GetFillInfo(void) const; inline HANDLE GetNotificationEvent(void) const; SCODE InitNotificationEvent(ILockBytes *plkbBase); #if DBG == 1 inline BOOL HaveMutex(void); #endif #endif void Close(void); #ifdef DIRECTWRITERLOCK ULONG * GetRecursionCount () {return &_cRecursion; }; #endif #ifdef MULTIHEAP BYTE * GetHeapBase () { return _pbBase; }; #endif inline BOOL IsHandleValid (); private: ILockBytes *_plkbBase; CFileStream *_pfstDirty; ILockBytes *_plkbOriginal; ULONG _ulOpenLock; CBasedGlobalContextPtr _pgc; LONG _cReferences; #ifdef ASYNC LONG _cRefSharedMem; #endif IMalloc * const _pMalloc; #ifdef ASYNC IFillInfo *_pfi; HANDLE _hNotificationEvent; #endif #ifdef MULTIHEAP CSharedMemoryBlock *_psmb; // heap object BYTE * _pbBase; // base address of heap ULONG _ulHeapName; // name of shared mem region #endif #if WIN32 >= 100 CDfMutex _dmtx; #endif #ifdef DIRECTWRITERLOCK ULONG _cRecursion; // recursion count of writers #endif }; SAFE_DFBASED_PTR(CBasedPerContextPtr, CPerContext); //+--------------------------------------------------------------------------- // // Class: CGlobalContext // // Purpose: Holds context-insensitive information // // Interface: See below // // History: 26-Oct-92 DrewB Created // //---------------------------------------------------------------------------- class CGlobalContext : public CContextList { public: inline CGlobalContext(IMalloc *pMalloc); inline void SetLockInfo(BOOL fTakeLock, DFLAGS dfOpenLock); DECLARE_CONTEXT_LIST(CPerContext); inline BOOL TakeLock(void) const; inline DFLAGS GetOpenLockFlags(void) const; inline IMalloc *GetMalloc(void) const; #if WIN32 >= 100 inline void GetMutexName(TCHAR *ptcsName); #ifdef ASYNC inline void GetEventName(TCHAR *ptcsName); #endif #endif private: BOOL _fTakeLock; DFLAGS _dfOpenLock; IMalloc * const _pMalloc; #if WIN32 >= 100 LARGE_INTEGER _luidMutexName; #endif }; inline CGlobalContext::CGlobalContext(IMalloc *pMalloc) : _pMalloc(pMalloc) { #if WIN32 >= 100 // Use a luid as the name for the mutex because the 64-bit // luid generator is guaranteed to produce machine-wide unique // values each time it is called, so if we use one for our mutex // name we know it won't collide with any others #if !defined(MULTIHEAP) _luidMutexName.QuadPart = PBasicEntry::GetNewLuid(pMalloc); #else if (DFBASEPTR == NULL) // task memory support { LUID luid; AllocateLocallyUniqueId (&luid); _luidMutexName.LowPart = luid.LowPart; _luidMutexName.HighPart = luid.HighPart; } else { _luidMutexName.QuadPart = g_smAllocator.GetHeapName(); } #endif #endif } inline void CGlobalContext::SetLockInfo(BOOL fTakeLock, DFLAGS dfOpenLock) { _fTakeLock = fTakeLock; _dfOpenLock = dfOpenLock; } //+-------------------------------------------------------------- // // Member: CGlobalContext::TakeLock, public // // Synopsis: Returns whether locks should be taken or not // // History: 04-Sep-92 DrewB Created // //--------------------------------------------------------------- inline BOOL CGlobalContext::TakeLock(void) const { return _fTakeLock; } //+-------------------------------------------------------------- // // Member: CGlobalContext::GetOpenLockFlags, public // // Synopsis: Returns the open lock flags // // History: 04-Sep-92 DrewB Created // //--------------------------------------------------------------- inline DFLAGS CGlobalContext::GetOpenLockFlags(void) const { return _dfOpenLock; } //+-------------------------------------------------------------- // // Member: CGlobalContext::GetMalloc, public // // Synopsis: Returns the allocator associated with this global context // // History: 05-May-93 AlexT Created // //--------------------------------------------------------------- inline IMalloc *CGlobalContext::GetMalloc(void) const { return (IMalloc *)_pMalloc; } //+--------------------------------------------------------------------------- // // Member: CGlobalContext::GetMutexName, public // // Synopsis: Returns the name to use for the mutex for this tree // // Arguments: [ptcsName] - Name return // // Modifies: [ptcsName] // // History: 09-Oct-93 DrewB Created // // Notes: [ptcsName] should have space for at least // CONTEXT_MUTEX_NAME_LENGTH characters // //---------------------------------------------------------------------------- #if WIN32 >= 100 inline void CGlobalContext::GetMutexName(TCHAR *ptcsName) { StringCchPrintf (ptcsName, CONTEXT_MUTEX_NAME_LENGTH, TSTR("OleDfRoot%X%08lX"), _luidMutexName.HighPart, _luidMutexName.LowPart); } #ifdef ASYNC inline void CGlobalContext::GetEventName(TCHAR *ptcsName) { StringCchPrintf (ptcsName, CONTEXT_MUTEX_NAME_LENGTH, TSTR("OleAsyncE%X%08lX"), _luidMutexName.HighPart, _luidMutexName.LowPart); } #endif // ASYNC #endif inline void CPerContext::SetILBInfo(ILockBytes *plkbBase, CFileStream *pfstDirty, ILockBytes *plkbOriginal, ULONG ulOpenLock) { _plkbBase = plkbBase; _pfstDirty = pfstDirty; _plkbOriginal = plkbOriginal; _ulOpenLock = ulOpenLock; #ifdef ASYNC _pfi = NULL; if (_plkbBase) { IFillInfo *pfi; HRESULT hr = _plkbBase->QueryInterface(IID_IFillInfo, (void **)&pfi); if (SUCCEEDED(hr)) { if (SUCCEEDED(InitNotificationEvent(_plkbBase))) { _pfi = pfi; } else { pfi->Release(); } } } #endif } //+-------------------------------------------------------------- // // Member: CPerContext::CPerContext, public // // Synopsis: Constructor // // Arguments: [plkbBase] - Base lstream // [pfstDirty] - Dirty lstream // [plkbOriginal] - Original base lstream for // independent copies // [ulOpenLock] - Open lock for base lstream // // History: 14-Aug-92 DrewB Created // 18-May-93 AlexT Added pMalloc // //--------------------------------------------------------------- inline CPerContext::CPerContext( IMalloc *pMalloc, ILockBytes *plkbBase, CFileStream *pfstDirty, ILockBytes *plkbOriginal, ULONG ulOpenLock) : _pMalloc(pMalloc) { _plkbBase = plkbBase; _pfstDirty = pfstDirty; _plkbOriginal = plkbOriginal; _ulOpenLock = ulOpenLock; _cReferences = 1; #ifdef ASYNC _cRefSharedMem = 1; #endif _pgc = NULL; #ifdef MULTIHEAP g_smAllocator.GetState(&_psmb, &_pbBase, &_ulHeapName); #endif #ifdef DIRECTWRITERLOCK _cRecursion = 0; // recursion count of writers #endif } //+-------------------------------------------------------------- // // Member: CPerContext::CPerContext, public // // Synopsis: Constructor for a temporary stack-based object // This is only used for unmarshaling, since we // need a percontext to own the heap before the // actual percontext is unmarshaled // // Arguments: [pMalloc] - Base IMalloc // // History: 29-Nov-95 HenryLee Created // //--------------------------------------------------------------- inline CPerContext::CPerContext(IMalloc *pMalloc) : _pMalloc(pMalloc) { #ifdef MULTIHEAP g_smAllocator.GetState(&_psmb, &_pbBase, &_ulHeapName); #endif _plkbBase = _plkbOriginal = NULL; _pfstDirty = NULL; _ulOpenLock = 0; _cReferences = 1; #ifdef ASYNC _cRefSharedMem = 1; #endif _pgc = NULL; #ifdef ASYNC _pfi = NULL; _hNotificationEvent = INVALID_HANDLE_VALUE; #endif #ifdef DIRECTWRITERLOCK _cRecursion = 0; // recursion count of writers #endif } #ifdef ASYNC inline LONG CPerContext::AddRefSharedMem(void) { olAssert(_cRefSharedMem >= _cReferences); AtomicInc(&_cRefSharedMem); olAssert(_cRefSharedMem >= _cReferences); return _cRefSharedMem; } inline LONG CPerContext::ReleaseSharedMem(void) { LONG lRet; olAssert(_cRefSharedMem > 0); olAssert(_cRefSharedMem >= _cReferences); lRet = AtomicDec(&_cRefSharedMem); if ((_cReferences == 0) && (_cRefSharedMem == 0)) delete this; return lRet; } inline LONG CPerContext::DecRef(void) { olAssert(_cRefSharedMem >= _cReferences); AtomicDec(&_cReferences); olAssert(_cRefSharedMem >= _cReferences); return _cReferences; } #endif //+--------------------------------------------------------------------------- // // Member: CPerContext::AddRef, public // // Synopsis: Increments the ref count // // History: 27-Oct-92 DrewB Created // //---------------------------------------------------------------------------- inline LONG CPerContext::AddRef(void) { #ifdef ASYNC olAssert(_cRefSharedMem >= _cReferences); AddRefSharedMem(); #endif AtomicInc(&_cReferences); #ifdef ASYNC olAssert(_cRefSharedMem >= _cReferences); #endif return _cReferences; } //+--------------------------------------------------------------------------- // // Member: CPerContext::Release, public // // Synopsis: Decrements the ref count // // History: 27-Oct-92 DrewB Created // //---------------------------------------------------------------------------- inline LONG CPerContext::Release(void) { LONG lRet; olAssert(_cReferences > 0); #ifdef ASYNC olAssert(_cRefSharedMem >= _cReferences); #endif lRet = AtomicDec(&_cReferences); if (lRet == 0) { #ifdef ASYNC if (_plkbBase != NULL) { Close(); } #else delete this; #endif } #ifdef ASYNC olAssert(_cRefSharedMem >= _cReferences); //Note: If the object is going to get deleted, it will happen // in the ReleaseSharedMem call. lRet = ReleaseSharedMem(); #endif return lRet; } //+-------------------------------------------------------------- // // Member: CPerContext::GetBase, public // // Synopsis: Returns the base // // History: 14-Aug-92 DrewB Created // //--------------------------------------------------------------- inline ILockBytes *CPerContext::GetBase(void) const { return _plkbBase; } //+-------------------------------------------------------------- // // Member: CPerContext::GetDirty, public // // Synopsis: Returns the dirty // // History: 14-Aug-92 DrewB Created // //--------------------------------------------------------------- inline CFileStream *CPerContext::GetDirty(void) const { return _pfstDirty; } //+-------------------------------------------------------------- // // Member: CPerContext::GetOriginal, public // // Synopsis: Returns the Original // // History: 14-Aug-92 DrewB Created // //--------------------------------------------------------------- inline ILockBytes *CPerContext::GetOriginal(void) const { return _plkbOriginal; } //+-------------------------------------------------------------- // // Member: CPerContext::GetOpenLock, public // // Synopsis: Returns the open lock index // // History: 04-Sep-92 DrewB Created // //--------------------------------------------------------------- inline ULONG CPerContext::GetOpenLock(void) const { return _ulOpenLock; } //+-------------------------------------------------------------- // // Member: CPerContext::GetContextId, public // // Synopsis: Returns the context id // // History: 04-Sep-92 DrewB Created // //--------------------------------------------------------------- inline ContextId CPerContext::GetContextId(void) const { return ctxid; } //+-------------------------------------------------------------- // // Member: CPerContext::GetMalloc, public // // Synopsis: Returns the IMalloc pointer // // History: 04-Apr-96 PhilipLa Created // //--------------------------------------------------------------- inline IMalloc * CPerContext::GetMalloc(void) const { return _pMalloc; } //+-------------------------------------------------------------- // // Member: CPerContext::GetGlobal, public // // Synopsis: Returns the global context // // History: 04-Sep-92 DrewB Created // //--------------------------------------------------------------- inline CGlobalContext *CPerContext::GetGlobal(void) const { return BP_TO_P(CGlobalContext *, _pgc); } inline void CPerContext::SetLockInfo(BOOL fTakeLock, DFLAGS dfOpenLock) { _pgc->SetLockInfo(fTakeLock, dfOpenLock); } //+--------------------------------------------------------------------------- // // Member: CPerContext::InitNewContext, public // // Synopsis: Creates a new context and context list // // Returns: Appropriate status code // // History: 27-Oct-92 DrewB Created // //---------------------------------------------------------------------------- inline SCODE CPerContext::InitNewContext(void) { SCODE sc; CGlobalContext *pgcTemp; sc = (pgcTemp = new (_pMalloc) CGlobalContext(_pMalloc)) == NULL ? STG_E_INSUFFICIENTMEMORY : S_OK; if (SUCCEEDED(sc)) { _pgc = P_TO_BP(CBasedGlobalContextPtr, pgcTemp); #if WIN32 >= 100 TCHAR atcMutexName[CONTEXT_MUTEX_NAME_LENGTH]; _pgc->GetMutexName(atcMutexName); sc = _dmtx.Init(atcMutexName); if (FAILED(sc)) { _pgc->Release(); _pgc = NULL; } else #endif _pgc->Add(this); } return sc; } //+--------------------------------------------------------------------------- // // Member: CPerContext::InitFromGlobal, public // // Synopsis: Adds a context to the context list // // Returns: Appropriate status code // // History: 27-Oct-92 DrewB Created // //---------------------------------------------------------------------------- inline SCODE CPerContext::InitFromGlobal(CGlobalContext *pgc) { SCODE sc; sc = S_OK; #if WIN32 >= 100 TCHAR atcMutexName[CONTEXT_MUTEX_NAME_LENGTH]; pgc->GetMutexName(atcMutexName); sc = _dmtx.Init(atcMutexName); #endif if (SUCCEEDED(sc)) { _pgc = P_TO_BP(CBasedGlobalContextPtr, pgc); _pgc->AddRef(); _pgc->Add(this); } return sc; } //+--------------------------------------------------------------------------- // // Member: CPerContext::SetOpenLock, public // // Synopsis: Sets the open lock // // History: 13-Jan-93 DrewB Created // //---------------------------------------------------------------------------- inline void CPerContext::SetOpenLock(ULONG ulOpenLock) { _ulOpenLock = ulOpenLock; } //+--------------------------------------------------------------------------- // // Member: CPerContext::TakeSem, public // // Synopsis: Takes the mutex // // Arguments: [dwTimeout] - Timeout // // Returns: Appropriate status code // // History: 09-Oct-93 DrewB Created // //---------------------------------------------------------------------------- inline SCODE CPerContext::TakeSem(DWORD dwTimeout) { #if WIN32 >= 100 SCODE sc; olChk(_dmtx.Take(dwTimeout)); #ifdef ONETHREAD olChkTo(EH_Tree, s_dmtxProcess.Take(dwTimeout)); #endif #ifdef MULTIHEAP if (_psmb && !_psmb->IsSynced()) { olChkTo(EH_Process, _psmb->Sync()); } #else olChkTo(EH_Process, DfSyncSharedMemory()); #endif EH_Err: return sc; EH_Process: #ifdef ONETHREAD s_dmtxProcess.Release(); EH_Tree: #endif _dmtx.Release(); return sc; #else return S_OK; #endif } //+--------------------------------------------------------------------------- // // Member: CPerContext::ReleaseSem, public // // Synopsis: Releases the mutex // // History: 09-Oct-93 DrewB Created // //---------------------------------------------------------------------------- inline void CPerContext::ReleaseSem(void) { #if WIN32 >= 100 #ifdef ONETHREAD s_dmtxProcess.Release(); #endif _dmtx.Release(); #endif } #ifdef MULTIHEAP //+------------------------------------------------------------------------- // // Member: CPerContext::SetThreadAllocatorState, public // // Synopsis: set current thread's allocator to be this percontext // // History: 29-Nov-95 HenryLee Created // //-------------------------------------------------------------------------- inline CSmAllocator *CPerContext::SetThreadAllocatorState(CPerContext**pppcPrev) { CSmAllocator *pSmAllocator = &g_smAllocator; pSmAllocator->SetState(_psmb, _pbBase, _ulHeapName, pppcPrev, this); return pSmAllocator; } //+--------------------------------------------------------------------------- // // Member: CPerContext::SetAllocatorState, public // // Synopsis: sets owner of shared memory heap to this percontext // remembers the previous context owner // // History: 29-Nov-95 HenryLee Created // //---------------------------------------------------------------------------- inline SCODE CPerContext::SetAllocatorState (CPerContext **pppcPrev, CSmAllocator *pSmAllocator) { pSmAllocator->SetState(_psmb, _pbBase, _ulHeapName, pppcPrev, this); return S_OK; } //+-------------------------------------------------------------- // // Member: CPerContext::GetThreadAllocatorState, public // // Synopsis: retrives the current thread's allocator state // // Arguments: none // // History: 29-Nov-95 HenryLee Created // //--------------------------------------------------------------- inline SCODE CPerContext::GetThreadAllocatorState() { g_smAllocator.GetState(&_psmb, &_pbBase, &_ulHeapName); return S_OK; } //+-------------------------------------------------------------- // // Class: CSafeMultiHeap // // Purpose: 1) sets and restores allocator state for those // methods that do not take the tree mutex // 2) for self-destructive methods like IStorage::Release, // IStream::Release, IEnumSTATSTG::Release, the // previous percontext may get deleted along with // whole heap, and it checks for that // // Interface: See below // // History: 29-Nov-95 HenryLee Created // //--------------------------------------------------------------- class CSafeMultiHeap { public: CSafeMultiHeap(CPerContext *ppc); ~CSafeMultiHeap(); private: CSmAllocator *_pSmAllocator; CPerContext *_ppcPrev; }; #endif // MULTIHEAP #ifdef ASYNC inline IFillInfo * CPerContext::GetFillInfo(void) const { return _pfi; } inline HANDLE CPerContext::GetNotificationEvent(void) const { return _hNotificationEvent; } #if DBG == 1 inline BOOL CPerContext::HaveMutex(void) { return _dmtx.HaveMutex(); } #endif // #if DBG == 1 #endif // #ifdef ASYNC inline BOOL CPerContext::IsHandleValid () { TCHAR tcsName[CONTEXT_MUTEX_NAME_LENGTH * 2]; StringCchCopy (tcsName, CONTEXT_MUTEX_NAME_LENGTH, TEXT("\\BaseNamedObjects\\")); _pgc->GetMutexName(&tcsName[lstrlen(tcsName)]); BOOL fValid = _dmtx.IsHandleValid(tcsName); if (!fValid) // if this object is not valid, don't let anyone else { // use it because its per-process handles are bogus ctxid = 0; } return fValid; } #endif // #ifndef __CONTEXT_HXX__