2025-04-27 07:49:33 -04:00

407 lines
8.6 KiB
C++

#ifndef _SMH_H_
#define _SMH_H_
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// SMH.H
//
// Public interface to shared memory heap implementation in
// \cal\src\_shmem
//
// Copyright 1986-1997 Microsoft Corporation, All Rights Reserved
//
#include <synchro.h>
// ========================================================================
// SHARED MEMORY HANDLES
//
// They are always defined as 32 bit values
//
#ifdef _WIN64
typedef VOID * __ptr32 SHMEMHANDLE;
#else
typedef HANDLE SHMEMHANDLE;
#endif
// ========================================================================
//
// NAMESPACE SMH
//
// Differentiates the shared memory heap allocation functions
// from all of the other various heap allocation functions
// in existence.
//
// Yes, this could have been done with a prefix just as easily....
//
namespace SMH
{
BOOL __fastcall FInitialize( IN LPCWSTR pwszInstanceName );
VOID __fastcall Deinitialize();
PVOID __fastcall PvAlloc( IN DWORD cbData, OUT SHMEMHANDLE * phsmba );
VOID __fastcall Free( IN SHMEMHANDLE hsmba );
PVOID __fastcall PvFromSMBA( IN SHMEMHANDLE hsmba );
};
// ========================================================================
//
// CLASS CSmhInit
//
// Initializer for shared memory heap. Any class containing member objects
// that reside on the shared memory heap should also include an instance
// of this class as a member BEFORE the others to ensure that they are
// properly destroyed before the heap is deinitialized.
//
class CSmhInit
{
// NOT IMPLEMENTED
//
CSmhInit& operator=( const CSmhInit& );
CSmhInit( const CSmhInit& );
public:
CSmhInit()
{
}
BOOL FInitialize( LPCWSTR lpwszSignature )
{
return SMH::FInitialize( lpwszSignature );
}
~CSmhInit()
{
SMH::Deinitialize();
}
};
// ========================================================================
//
// TEMPLATE CLASS SharedHandle
//
// Encapsulates a reference to a SharedObj (a refcounted object in shared
// memory). The SharedHandle itself is designed to exist in shared memory.
// Any process can access the SharedObj through a SharedHandle.
// Because the SharedHandle represents a reference on the SharedObj,
// access to the SharedObj through the handle is always "safe"
// in that the SharedObj cannot "go away" as long as the SharedHandle
// exists. If safe access to the SharedHandle itself is a concern,
// that protection must be provided externally. This can be easily done
// by making the SharedHandle a member of another SharedObj. Entire
// hierarchies of refcounted objects in shared memory can be created
// this way.
//
template<class _X> class SharedObj;
template<class _X>
class SharedHandle
{
//
// The RAW shared memory handle
//
SHMEMHANDLE m_hsmba;
//
// A shared multi-reader/single writer lock to resolve
// simultaneous attempts to modify the handle via
// operator=() while accessing it via PObjBind().
// It should not be possible for consumers of
// SharedHandle to return from PObjBind() without a
// qualified reference to some object.
//
mutable CSharedMRWLock m_lock;
// CREATORS
//
void Init( SharedObj<_X> * pObj,
SHMEMHANDLE hsmba )
{
//
// Stuff the object and its raw handle.
// Note that NULL objects (with corresponding
// NULL handles) are allowed. Get a proper
// ref on the object before returning.
//
if ( pObj )
{
Assert( hsmba );
pObj->AddRef();
}
m_hsmba = hsmba;
}
void Deinit()
{
//
// If the handle is non-NULL, drop the ref
// to its SharedObject, destroying the object
// when the last ref is released.
//
if ( m_hsmba )
{
SharedObj<_X> * pObj = static_cast<SharedObj<_X> *>(SMH::PvFromSMBA( m_hsmba ));
Assert( pObj );
if ( 0 == pObj->Release() )
{
pObj->~SharedObj<_X>();
SMH::Free( m_hsmba );
}
// We should always reset m_hsmba because it's ref is gone already
//
m_hsmba = NULL;
}
}
public:
// CREATORS
//
SharedHandle() :
m_hsmba(NULL)
{
}
~SharedHandle()
{
Deinit();
}
SharedHandle( const SharedHandle<_X>& rhs )
{
(VOID) rhs.PObjBind(this);
}
SharedHandle<_X>& operator=( const SharedHandle<_X>& rhs )
{
//
// Shortcut for assignment to self. Actually doing
// the assignment to self is a recipe for deadlock.
//
if ( this != &rhs )
{
SynchronizedWriteBlock<CSharedMRWLock> blk(m_lock);
//
// Blow away the current value associated with this handle
//
Deinit();
//
// Construct new data for the handle
//
(VOID) rhs.PObjBind(this);
}
return *this;
}
VOID Clear()
{
Deinit();
}
// ACCESSORS
//
SharedObj<_X> * PObjBind( SharedHandle<_X> * pshObj ) const
{
SynchronizedReadBlock<CSharedMRWLock> blk(m_lock);
SharedObj<_X> * pObj;
pObj = m_hsmba ?
static_cast<SharedObj<_X> *>(SMH::PvFromSMBA( m_hsmba )) :
NULL;
pshObj->Init(pObj, m_hsmba);
return pObj;
}
// STATICS
//
static SharedObj<_X> *
Create( UINT cbExtra,
SharedHandle<_X> * pshObj )
{
SHMEMHANDLE hsmba;
SharedObj<_X> * pObj =
new(SMH::PvAlloc( sizeof(SharedObj<_X>) + cbExtra, &hsmba ))
SharedObj<_X>();
pshObj->Init(pObj, hsmba);
return pObj;
}
};
// ========================================================================
//
// TEMPLATE CLASS SharedObj
//
// Implements a refcountable object in shared memory. The object data
// itself is provided by the template paramater (_X). Access to the object
// through this interface is direct. It is up to the consumer of
// SharedObj to provide thread-safe access and control the lifetime
// of the object via its refcount.
//
template<class _X>
class SharedObj
{
//
// Refcount
//
LONG m_lcRef;
//
// The _X instance
//
_X m_x;
// NOT IMPLEMENTED
//
SharedObj& operator=( const SharedObj& );
SharedObj( const SharedObj& );
public:
// STATICS
//
static void * operator new(size_t cb, void * pv)
{
//
// Just return the pointer given to us. Presumably, it points
// to a valid block of shared memory large enough to contain
// the object.
//
return pv;
}
// Fix C4291
void operator delete (void * pv) {}
void operator delete (void * pv, void * pM) {}
//
// For symetry with operator new we also could create operator delete.
// As this object manages just a refcount, but not memory we will
// could just return. But that is not that important at the moment.
//
// CREATORS
//
SharedObj() : m_lcRef(0) {}
// ACCESSORS
//
const _X& X() const { return m_x; }
_X& X() { return m_x; }
UINT AddRef()
{
DebugTrace ("SharedObj AddRef = %d, this = %x\n", m_lcRef+1, this);
return InterlockedIncrement( &m_lcRef );
}
UINT Release()
{
DebugTrace ("SharedObj Release = %d, this = %x\n", m_lcRef-1, this);
return InterlockedDecrement( &m_lcRef );
}
};
// ========================================================================
//
// TEMPLATE CLASS SharedPtr
//
// Encapsulates a reference to a SharedObj (a refcounted object in shared
// memory) as a pointer for use in local (process) memory. A SharedPtr
// is essentially just a SharedHandle (which holds a reference to the
// SharedObj) and an addressable pointer bound to that handle.
//
template<class _X>
class SharedPtr
{
//
// The SharedHandle to which this SharedPtr is bound
//
SharedHandle<_X> m_shObj;
//
// Physical pointer to the shared object
//
SharedObj<_X> * m_pObj;
// NOT IMPLEMENTED
//
SharedPtr& operator=( const SharedPtr& );
SharedPtr( const SharedPtr& );
public:
// CREATORS
//
SharedPtr() :
m_pObj(NULL)
{
}
~SharedPtr() {}
// ACCESSORS
//
SharedHandle<_X>& GetHandle()
{
return m_shObj;
}
BOOL FIsNull() const
{
return !m_pObj;
}
// MANIPULATORS
//
// Create a new object. cbExtra leaves room at the end of
// the allocation for variable-sized objects.
//
BOOL FCreate( UINT cbExtra = 0 )
{
m_pObj = SharedHandle<_X>::Create( cbExtra, &m_shObj );
return !!m_pObj;
}
// Bind to an existing SharedObject by its handle.
//
BOOL FBind( SharedHandle<_X>& shObj )
{
Assert (NULL == m_pObj);
m_pObj = shObj.PObjBind( &m_shObj );
return !!m_pObj;
}
//
// Forward everything else to the controlled object
//
_X* operator->() const
{
Assert( m_pObj );
return &m_pObj->X();
}
VOID Clear()
{
m_pObj = NULL;
m_shObj.Clear();
}
};
#endif // !defined(_SMH_H_)