WindowsXP-SP1/enduser/troubleshoot/tshoot/sync.cpp

215 lines
5.8 KiB
C++

//
// MODULE: SYNC.CPP
//
// PURPOSE: syncronization classes
//
// COMPANY: Saltmine Creative, Inc. (206)-284-7511 support@saltmine.com
//
// AUTHOR: Oleg Kalosha
//
// ORIGINAL DATE: 8-04-98
//
// NOTES:
//
// Version Date By Comments
//--------------------------------------------------------------------
// V3.0 08-04-98 OK
//
#include "stdafx.h"
#include <algorithm>
#include "sync.h"
#include "event.h"
#include "baseexception.h"
#include "CharConv.h"
#include "apiwraps.h"
////////////////////////////////////////////////////////////////////////////////////
// CSyncObj
// single sync object abstract class
////////////////////////////////////////////////////////////////////////////////////
CSyncObj::CSyncObj()
{
// we are to initialize handle in specific inherited class
}
CSyncObj::~CSyncObj()
{
::CloseHandle(m_handle);
}
HANDLE CSyncObj::GetHandle() const
{
return m_handle;
}
////////////////////////////////////////////////////////////////////////////////////
// CMutexObj //
// single mutex object class
// Manages a single mutex handle to facilitate waiting for the mutex.
////////////////////////////////////////////////////////////////////////////////////
CMutexObj::CMutexObj()
: CSyncObj()
{
m_handle = ::CreateMutex(NULL, FALSE, NULL);
}
CMutexObj::~CMutexObj()
{
::CloseHandle(m_handle);
}
// Smarter strategy here than an infinite wait. Wait up to 60 seconds, then log to event
// log and wait infinitely. If it's logged to event log & eventually gets the mutex,
// it logs to say it finally got the mutex.
void CMutexObj::Lock()
{
WAIT_INFINITE(m_handle);
}
void CMutexObj::Unlock()
{
::ReleaseMutex(m_handle);
}
////////////////////////////////////////////////////////////////////////////////////
// CMultiSyncObj //
// multiple sync object abstract class
// Manages multiple handles (the exact type of handle will be determined by a class
// inheriting from this) to facilitate waiting for the union of several events.
////////////////////////////////////////////////////////////////////////////////////
CMultiSyncObj::CMultiSyncObj()
{
}
CMultiSyncObj::~CMultiSyncObj()
{
}
void CMultiSyncObj::AddHandle(HANDLE handle)
{
vector<HANDLE>::iterator i =
find(m_arrHandle.begin(), m_arrHandle.end(), handle);
if (i == m_arrHandle.end())
{
try
{
m_arrHandle.push_back(handle);
}
catch (exception& x)
{
CString str;
// Note STL exception in event log.
CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ );
CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
SrcLoc.GetSrcFileLineStr(),
CCharConversion::ConvertACharToString(x.what(), str),
_T(""),
EV_GTS_STL_EXCEPTION );
}
}
}
void CMultiSyncObj::RemoveHandle(HANDLE handle)
{
vector<HANDLE>::iterator i =
find(m_arrHandle.begin(), m_arrHandle.end(), handle);
if (i != m_arrHandle.end())
m_arrHandle.erase(i);
}
void CMultiSyncObj::Clear()
{
m_arrHandle.clear();
}
////////////////////////////////////////////////////////////////////////////////////
// CMultiMutexObj //
// Manages multiple mutex handles to facilitate waiting for the union of several mutexes.
////////////////////////////////////////////////////////////////////////////////////
CMultiMutexObj::CMultiMutexObj()
: CMultiSyncObj()
{
}
CMultiMutexObj::~CMultiMutexObj()
{
}
// Deprecated use, because it provides inferior logging.
void CMultiMutexObj::Lock()
{
Lock(__FILE__, __LINE__);
}
void CMultiMutexObj::Lock(
LPCSTR srcFile, // Calling source file (__FILE__), used for logging.
// LPCSTR, not LPCTSTR, because __FILE__ is a char*, not a TCHAR*
int srcLine, // Calling source line (__LINE__), used for logging.
DWORD TimeOutVal /*=60000*/ // Time-out interval in milliseconds. After
// this we log an error, then wait infinitely
)
{
CBuildSrcFileLinenoStr SrcLoc( srcFile, srcLine );
DWORD nWaitRetVal= ::WaitForMultipleObjects(
m_arrHandle.size(),
m_arrHandle.begin(),
TRUE, // wait for all objects, not just one.
TimeOutVal);
if (nWaitRetVal == WAIT_FAILED)
{
// very bad news, should never happen
DWORD dwErr = ::GetLastError();
CString strErr;
strErr.Format(_T("%d"), dwErr);
CBuildSrcFileLinenoStr SrcLoc3(__FILE__, __LINE__);
CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
SrcLoc3.GetSrcFileLineStr(),
_T("Thread wait failed."),
strErr,
EV_GTS_ERROR_STUCK_THREAD );
}
else if (nWaitRetVal == WAIT_TIMEOUT)
{
// Initial wait timed out, note in log, and wait infinitely.
CBuildSrcFileLinenoStr SrcLoc1(__FILE__, __LINE__);
CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
SrcLoc1.GetSrcFileLineStr(),
_T("Thread wait exceeded initial timeout interval."),
_T(""),
EV_GTS_STUCK_THREAD );
nWaitRetVal= ::WaitForMultipleObjects(
m_arrHandle.size(),
m_arrHandle.begin(),
TRUE, // wait for all objects, not just one.
INFINITE);
// If successfully got what we were waiting for (after logging an apparent
// problem), log the fact that it's ultimately OK.
if (nWaitRetVal == WAIT_OBJECT_0)
{
CBuildSrcFileLinenoStr SrcLoc2(__FILE__, __LINE__);
CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(),
SrcLoc2.GetSrcFileLineStr(),
_T("Thread infinite wait succeeded."),
_T(""),
EV_GTS_STUCK_THREAD );
}
}
// Else we don't really care what else ::WaitForMultipleObjects() returns.
// If we get here we got what we were waiting for
}
void CMultiMutexObj::Unlock()
{
for (vector<HANDLE>::iterator i = m_arrHandle.begin();
i != m_arrHandle.end();
i++
)
::ReleaseMutex(*i);
}