221 lines
5.7 KiB
C++
221 lines
5.7 KiB
C++
#include <unicode.h>
|
|
#include <windows.h>
|
|
#include "SafeCS.h"
|
|
|
|
|
|
//+-----------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (c) Microsoft Corporation 2000
|
|
//
|
|
// File: SafeCS.cpp
|
|
//
|
|
// Contents: CSafeAutoCriticalSection implementation
|
|
// CSafeLock implementation
|
|
//
|
|
//------------------------------------------------------------------------
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Class: CSafeAutoCriticalSection
|
|
//
|
|
// Purpose: Wrapper for initializing critical-sections.
|
|
//
|
|
// Interface: Lock - locks the critical section
|
|
// Unlock - unlocks the critical section
|
|
// Constructor - initializes the critical section
|
|
// Detructor - uninitializes the critical section
|
|
//
|
|
// Notes: This provides a convenient way to ensure that you're
|
|
// you wrap InitializeCriticalSection and
|
|
// UnInitializeCriticalSection in try catches which is useful
|
|
// in low-mem conditions
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// Default constructor - Initializes the critical section and sets the state
|
|
// flag to initialized
|
|
//+--------------------------------------------------------------------------
|
|
|
|
CSafeAutoCriticalSection::CSafeAutoCriticalSection()
|
|
{
|
|
m_lState = STATE_UNINITIALIZED;
|
|
m_dwError = ERROR_SUCCESS;
|
|
|
|
__try
|
|
{
|
|
LONG lPreviousState;
|
|
|
|
// try to set state flag
|
|
lPreviousState = InterlockedCompareExchange(&m_lState,
|
|
STATE_INITIALIZED,
|
|
STATE_UNINITIALIZED);
|
|
|
|
// if this critical section was not initialized
|
|
if(STATE_UNINITIALIZED == lPreviousState)
|
|
{
|
|
//
|
|
// Note we can call InitializeCriticalSectionAndSpinCount here
|
|
// and thereby eliminate the need for a try catch in
|
|
// EnterCriticalSection. But the docs say that
|
|
// InitializeCriticalSectionAndSpinCount is valid on NT4.0 SP3
|
|
// onwards and we need to run on plain NT4.0 - hence we call
|
|
// InitializeCriticalSection
|
|
//
|
|
|
|
InitializeCriticalSection(&m_cs);
|
|
}
|
|
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
m_dwError = _exception_code();
|
|
}
|
|
|
|
// failed to initialize - need to reset
|
|
if(ERROR_SUCCESS != m_dwError)
|
|
{
|
|
m_lState = STATE_UNINITIALIZED;
|
|
}
|
|
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// Destructor
|
|
//+--------------------------------------------------------------------------
|
|
|
|
CSafeAutoCriticalSection::~CSafeAutoCriticalSection()
|
|
{
|
|
LONG lPreviousState;
|
|
|
|
// try to reset the the state to uninitialized
|
|
lPreviousState = InterlockedCompareExchange(&m_lState,
|
|
STATE_UNINITIALIZED,
|
|
STATE_INITIALIZED);
|
|
|
|
// if the object was initialized delete the critical section
|
|
if(STATE_INITIALIZED == lPreviousState)
|
|
{
|
|
DeleteCriticalSection(&m_cs);
|
|
}
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// Enters critical section, if needed initializes critical section
|
|
// before entering
|
|
//
|
|
// Returns
|
|
// DWORD - ERROR_SUCCESS if everything is fine
|
|
// ERROR_OUTOFMEMORY if failed to create or enter critical section
|
|
//+--------------------------------------------------------------------------
|
|
|
|
DWORD CSafeAutoCriticalSection::Lock()
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
|
|
if(!IsInitialized())
|
|
{
|
|
return m_dwError;
|
|
}
|
|
|
|
__try
|
|
{
|
|
EnterCriticalSection(&m_cs);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
dwError = _exception_code();
|
|
}
|
|
|
|
return dwError;
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// Leaves critical section
|
|
//+--------------------------------------------------------------------------
|
|
DWORD CSafeAutoCriticalSection::Unlock()
|
|
{
|
|
if(!IsInitialized())
|
|
{
|
|
return m_dwError;
|
|
}
|
|
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Class: CSafeLock
|
|
//
|
|
// Purpose: Auto-unlocking critical-section services
|
|
//
|
|
// Interface: Lock - locks the critical section
|
|
// Unlock - unlocks the critical section
|
|
// Constructor - locks the critical section (unless told
|
|
// otherwise)
|
|
// Detructor - unlocks the critical section if its locked
|
|
//
|
|
// Notes: This provides a convenient way to ensure that you're
|
|
// unlocking a CSemExclusive, which is useful if your routine
|
|
// can be left via several returns and/or via exceptions....
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
CSafeLock::CSafeLock(CSafeAutoCriticalSection* val) :
|
|
m_pSem(val),
|
|
m_locked(FALSE)
|
|
{
|
|
}
|
|
|
|
CSafeLock::CSafeLock(CSafeAutoCriticalSection& val) :
|
|
m_pSem(&val),
|
|
m_locked(FALSE)
|
|
{
|
|
}
|
|
|
|
CSafeLock::~CSafeLock()
|
|
{
|
|
if (m_locked)
|
|
{
|
|
m_pSem->Unlock();
|
|
}
|
|
}
|
|
|
|
DWORD CSafeLock::Lock()
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
|
|
if(!m_locked)
|
|
{
|
|
dwError = m_pSem->Lock();
|
|
|
|
if(ERROR_SUCCESS == dwError)
|
|
{
|
|
m_locked = TRUE;
|
|
}
|
|
}
|
|
|
|
return dwError;
|
|
}
|
|
|
|
|
|
DWORD CSafeLock::Unlock()
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
|
|
if(m_locked)
|
|
{
|
|
dwError = m_pSem->Unlock();
|
|
m_locked = FALSE;
|
|
}
|
|
|
|
return dwError;
|
|
}
|
|
|
|
|