Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

202 lines
6.5 KiB

//-----------------------------------------------------------------------------
// Microsoft OLE DB Implementation For ODBC Providers
// (C) Copyright 1994 - 1996 By Microsoft Corporation.
//
// @doc
//
// @module AUTOBLOC.H | CAutoBlock object implementation.
//
// @rev 1 | 02-27-95 | EricJ | Created
// @rev 2 | 06-30-95 | EricJ | Added autoduck comments (maybe too many?)
// @rev 3 | 07-02-96 | EricJ | Removed debug code; doesn't work on WIN95 or RISC.
//-----------------------------------------------------------------------------
#ifndef __AUTOBLOC_H_
#define __AUTOBLOC_H_
//-----------------------------------------------------------------------------
// @class CAutoBlock | Auto blocking / synchronization.
//
// This C++ object allows blocking of critical sections.
// The constructor/destructor automatically Enter and Leave
// correctly, to ensure that each call is correctly paired.
// This ensures correct operation for exception handling
// and for multiple returns.
//
// @ex Here's example usage. |
//
// void test2()
// {
// CAutoBlock ab( &g_Crit1 );
//
// // Do some work here...
// // Destructor cleans up
// }
//
// void test3()
// {
// CAutoBlock ab( &g_Crit2 );
//
// //...do some work -- we are blocked here...
//
// ab.UnBlock();
//
// //...do some work -- we are not blocked here...
// //...destructor does nothing...
// }
//
// @devnote
// If you want to enter the same critical section again,
// just use another CAutoBlock.
//
// Note that since the storage is auto (not static or dynamic
// via `new`), this goes onto the stack. Thus the overhead of
// this class is almost exactly the same as explictly calling
// EnterCriticalSection / LeaveCriticalSection.
//-----------------------------------------------------------------------------
class DBEXPORT CAutoBlock {
public: //@access public functions
CAutoBlock( CRITICAL_SECTION *pCrit ); //@cmember CTOR. Begins blocking.
~CAutoBlock(); //@cmember DTOR. Ends blocking.
void UnBlock(); //@cmember Ends blocking.
private: //@access private data
CRITICAL_SECTION *m_pCrit; //@cmember The critical section.
};
//-----------------------------------------------------------------------------
// Inline functions
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// @mfunc Constructor.
// Begins blocking. Does EnterCriticalSection, so you can put at
// beginning of function, or in the middle of the function,
// or inside some scoped {}.
//-----------------------------------------------------------------------------------
inline CAutoBlock::CAutoBlock(
CRITICAL_SECTION *pCrit ) //@parm IN | The critical section.
{
// It is OK to pass a NULL ptr to this routine. It is a NOOP.
// Note that passing NULL to EnterCriticalSection blows up.
if (0 != pCrit )
::EnterCriticalSection( pCrit );
m_pCrit = pCrit;
}
//-----------------------------------------------------------------------------
// @mfunc Destructor.
// Ends blocking. Does LeaveCriticalSection, unless you called UnBlock(),
// in which case it's a NOOP.
//-----------------------------------------------------------------------------------
inline CAutoBlock::~CAutoBlock()
{
if ( 0 != m_pCrit )
::LeaveCriticalSection( m_pCrit );
}
//-----------------------------------------------------------------------------
// @mfunc
// Ends blocking explicitly. Thereafter, the destructor does nothing.
//-----------------------------------------------------------------------------------
inline void CAutoBlock::UnBlock()
{
// Clear the critical-section member,
// so that the destructor doesn't do anything.
if ( 0 != m_pCrit )
::LeaveCriticalSection( m_pCrit );
m_pCrit = 0;
}
//-----------------------------------------------------------------------------
// @class CAutoBlock2 | Auto blocking / synchronization.
// This class requires each critical section to be assigned a level.
// Critical Sections can be called only in a low-to-high order, within a thread.
// Otherwise the chance for deadlock exists.
//-----------------------------------------------------------------------------
// ifdef this out for now, so it doesn't introduce another global var.
#ifdef NOTREADY
class DBEXPORT CAutoBlock2 {
public: //@access public functions
CAutoBlock2( CRITICAL_SECTION *pCrit, DWORD dwLevel ); //@cmember CTOR. Begins blocking.
~CAutoBlock2(); //@cmember DTOR. Ends blocking.
void UnBlock(); //@cmember Ends blocking.
private: //@access private data
CRITICAL_SECTION *m_pCriticalSection; //@cmember The critical section.
DEBUGCODE( DWORD m_dwLevel; ) //@cmember Level of this critical section.
};
// There can be 32 levels, 0...31.
// They can only be used in low --> high order.
enum CritLevels {
CRITLEV_DATASOURCE,
CRITLEV_SESSION,
CRITLEV_COMMAND,
CRITLEV_ROWSET,
};
// We need a global var for the TLS index.
// @todo EJ 2-jun-96: Fake it for now; until this is integrated.
static DWORD g_dwTlsIndexCS = TLS_OUT_OF_INDEXES;
inline CAutoBlock2::CAutoBlock2( CRITICAL_SECTION *pCriticalSection, DWORD dwLevel )
{
#ifdef DEBUG
DWORD dwExistLevel;
assert( 0 <= dwLevel && dwLevel <= 31);
assert(g_dwTlsIndexCS != TLS_OUT_OF_INDEXES);
dwExistLevel = (DWORD) TlsGetValue(g_dwTlsIndexCS);
// Disallow calls to lower levels than we currently have.
// Allow calls to same level.
assert(dwExistLevel > (DWORD) (1<<(dwLevel+1)) - 1);
dwExistLevel |= 1<<dwLevel;
TlsSetValue(g_dwTlsIndexCS, (LPVOID) dwExistLevel);
m_dwLevel = dwLevel;
#endif
m_pCriticalSection = pCriticalSection;
if ( 0 != pCriticalSection )
::EnterCriticalSection( pCriticalSection );
}
inline CAutoBlock2::~CAutoBlock2()
{
#ifdef DEBUG
DWORD dwExistLevel;
dwExistLevel = (DWORD) TlsGetValue(g_dwTlsIndexCS);
dwExistLevel &= ~ (1<<m_dwLevel);
TlsSetValue(g_dwTlsIndexCS, (LPVOID) dwExistLevel);
#endif
if ( 0 != m_pCriticalSection )
::LeaveCriticalSection( m_pCriticalSection );
}
inline void CAutoBlock2::UnBlock()
{
// Clear the critical-section member,
// so that the destructor doesn't do anything.
if ( 0 != m_pCriticalSection )
::LeaveCriticalSection( m_pCriticalSection );
m_pCriticalSection = 0;
}
#endif // NOTREADY
#endif // __AUTOBLOC_H_