// // 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 #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::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::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::iterator i = m_arrHandle.begin(); i != m_arrHandle.end(); i++ ) ::ReleaseMutex(*i); }