|
|
/*++
Copyright (c) 1998-1999 Microsoft Corporation
Module Name:
utils.h
Abstract:
Author:
mquinton 06-30-98 Notes:
Revision History:
--*/
#ifndef __UTILS_H__
#define __UTILS_H__
#ifdef TRACELOG
#include <rtutils.h>
//#include <windef.h>
//#include <winnt.h>
extern BOOL g_bLoggingEnabled; #define MAXDEBUGSTRINGLENGTH 1024
#define TL_ERROR ((DWORD)0x00010000 | TRACE_USE_MASK)
#define TL_WARN ((DWORD)0x00020000 | TRACE_USE_MASK)
#define TL_INFO ((DWORD)0x00040000 | TRACE_USE_MASK)
#define TL_TRACE ((DWORD)0x00080000 | TRACE_USE_MASK)
#define TL_EVENT ((DWORD)0x00100000 | TRACE_USE_MASK)
BOOL TRACELogRegister(LPCTSTR szName); void TRACELogDeRegister(); void TRACELogPrint(IN DWORD dwDbgLevel, IN LPCSTR DbgMessage, IN ...); void TRACELogPrint(IN DWORD dwDbgLevel, HRESULT hr, IN LPCSTR lpszFormat, IN ...);
extern char *TraceLevel(DWORD dwDbgLevel); extern void TAPIFormatMessage(HRESULT hr, LPVOID lpMsgBuf);
#define TRACELOGREGISTER(arg) TRACELogRegister(arg)
#define TRACELOGDEREGISTER() g_bLoggingEnabled?TRACELogDeRegister():0
#define LOG(arg) g_bLoggingEnabled?TRACELogPrint arg:0
#define STATICLOG(arg) g_bLoggingEnabled?StaticTRACELogPrint arg:0
extern char sg_szTraceName[100]; extern DWORD sg_dwTracingToDebugger; extern DWORD sg_dwDebuggerMask; extern DWORD sg_dwTraceID;
#define DECLARE_DEBUG_ADDREF_RELEASE(x) \
void LogDebugAddRef(DWORD dw) \ { TRACELogPrint(TL_INFO, "%s::AddRef() = %d - this %lx", _T(#x), dw, this); } \ void LogDebugRelease(DWORD dw) \ { TRACELogPrint(TL_INFO, "%s::Release() = %d - this %lx", _T(#x), dw, this); }
#define DECLARE_TRACELOG_CLASS(x) \
void TRACELogPrint(IN DWORD dwDbgLevel, IN LPCSTR lpszFormat, IN ...) \ { \ char szTraceBuf[MAXDEBUGSTRINGLENGTH + 1]; \ va_list arglist; \ \ if ( ( sg_dwTracingToDebugger > 0 ) && \ ( 0 != ( dwDbgLevel & sg_dwDebuggerMask ) ) ) \ { \ SYSTEMTIME SystemTime; \ GetLocalTime(&SystemTime); \ \ wsprintfA(szTraceBuf, \ "%s:[%02u:%02u:%02u.%03u,tid=%x:] [%s] (%p) %s::", \ sg_szTraceName, \ SystemTime.wHour, \ SystemTime.wMinute, \ SystemTime.wSecond, \ SystemTime.wMilliseconds, \ GetCurrentThreadId(), \ TraceLevel(dwDbgLevel), \ this, \ _T(#x)); \ \ va_list ap; \ va_start(ap, lpszFormat); \ \ _vsnprintf(&szTraceBuf[lstrlenA(szTraceBuf)], \ MAXDEBUGSTRINGLENGTH - lstrlenA(szTraceBuf), \ lpszFormat, \ ap \ ); \ \ lstrcatA (szTraceBuf, "\n"); \ \ OutputDebugStringA (szTraceBuf); \ \ va_end(ap); \ } \ \ if (sg_dwTraceID != INVALID_TRACEID) \ { \ wsprintfA(szTraceBuf, "[%s] (%p) %s::%s", TraceLevel(dwDbgLevel), this, _T(#x), lpszFormat); \ \ va_start(arglist, lpszFormat); \ TraceVprintfExA(sg_dwTraceID, dwDbgLevel | TRACE_USE_MSEC, szTraceBuf, arglist); \ va_end(arglist); \ } \ } \ \ void TRACELogPrint(IN DWORD dwDbgLevel,IN HRESULT hr, IN LPCSTR lpszFormat, IN ...) \ { \ char szTraceBuf[MAXDEBUGSTRINGLENGTH + 1]; \ LPVOID lpMsgBuf = NULL; \ va_list arglist; \ \ TAPIFormatMessage(hr, &lpMsgBuf); \ \ if ( ( sg_dwTracingToDebugger > 0 ) && \ ( 0 != ( dwDbgLevel & sg_dwDebuggerMask ) ) ) \ { \ SYSTEMTIME SystemTime; \ GetLocalTime(&SystemTime); \ \ wsprintfA(szTraceBuf, \ "%s:[%02u:%02u:%02u.%03u,tid=%x:] [%s] (%p) %s::", \ sg_szTraceName, \ SystemTime.wHour, \ SystemTime.wMinute, \ SystemTime.wSecond, \ SystemTime.wMilliseconds, \ GetCurrentThreadId(), \ TraceLevel(dwDbgLevel), \ this, \ _T(#x) \ ); \ \ va_list ap; \ va_start(ap, lpszFormat); \ \ _vsnprintf(&szTraceBuf[lstrlenA(szTraceBuf)], \ MAXDEBUGSTRINGLENGTH - lstrlenA(szTraceBuf), \ lpszFormat, \ ap \ ); \ \ wsprintfA(&szTraceBuf[lstrlenA(szTraceBuf)], \ " Returned[%lx] %s\n", \ hr, \ lpMsgBuf); \ \ OutputDebugStringA (szTraceBuf); \ \ va_end(ap); \ } \ \ if (sg_dwTraceID != INVALID_TRACEID) \ { \ wsprintfA(szTraceBuf, "[%s] (%p) %s::%s Returned[%lx] %s", TraceLevel(dwDbgLevel), this, _T(#x), lpszFormat,hr, lpMsgBuf ); \ \ va_start(arglist, lpszFormat); \ TraceVprintfExA(sg_dwTraceID, dwDbgLevel | TRACE_USE_MSEC, szTraceBuf, arglist); \ va_end(arglist); \ } \ \ if(lpMsgBuf != NULL) \ { \ LocalFree( lpMsgBuf ); \ } \ } \ \ static void StaticTRACELogPrint(IN DWORD dwDbgLevel, IN LPCSTR lpszFormat, IN ...) \ { \ char szTraceBuf[MAXDEBUGSTRINGLENGTH + 1]; \ va_list arglist; \ \ if ( ( sg_dwTracingToDebugger > 0 ) && \ ( 0 != ( dwDbgLevel & sg_dwDebuggerMask ) ) ) \ { \ SYSTEMTIME SystemTime; \ GetLocalTime(&SystemTime); \ \ wsprintfA(szTraceBuf, \ "%s:[%02u:%02u:%02u.%03u,tid=%x:] [%s] %s::", \ sg_szTraceName, \ SystemTime.wHour, \ SystemTime.wMinute, \ SystemTime.wSecond, \ SystemTime.wMilliseconds, \ GetCurrentThreadId(), \ TraceLevel(dwDbgLevel), \ _T(#x)); \ \ va_list ap; \ va_start(ap, lpszFormat); \ \ _vsnprintf(&szTraceBuf[lstrlenA(szTraceBuf)], \ MAXDEBUGSTRINGLENGTH - lstrlenA(szTraceBuf), \ lpszFormat, \ ap \ ); \ \ lstrcatA (szTraceBuf, "\n"); \ \ OutputDebugStringA (szTraceBuf); \ \ va_end(ap); \ } \ \ if (sg_dwTraceID != INVALID_TRACEID) \ { \ wsprintfA(szTraceBuf, "[%s] %s::%s", TraceLevel(dwDbgLevel), _T(#x), lpszFormat); \ \ va_start(arglist, lpszFormat); \ TraceVprintfExA(sg_dwTraceID, dwDbgLevel | TRACE_USE_MSEC, szTraceBuf, arglist); \ va_end(arglist); \ } \ } \ \ static void StaticTRACELogPrint(IN DWORD dwDbgLevel,IN HRESULT hr, IN LPCSTR lpszFormat, IN ...) \ { \ char szTraceBuf[MAXDEBUGSTRINGLENGTH + 1]; \ LPVOID lpMsgBuf = NULL; \ va_list arglist; \ \ TAPIFormatMessage(hr, &lpMsgBuf); \ \ if ( ( sg_dwTracingToDebugger > 0 ) && \ ( 0 != ( dwDbgLevel & sg_dwDebuggerMask ) ) ) \ { \ SYSTEMTIME SystemTime; \ GetLocalTime(&SystemTime); \ \ wsprintfA(szTraceBuf, \ "%s:[%02u:%02u:%02u.%03u,tid=%x:] [%s] %s::", \ sg_szTraceName, \ SystemTime.wHour, \ SystemTime.wMinute, \ SystemTime.wSecond, \ SystemTime.wMilliseconds, \ GetCurrentThreadId(), \ TraceLevel(dwDbgLevel), \ _T(#x) \ ); \ \ va_list ap; \ va_start(ap, lpszFormat); \ \ _vsnprintf(&szTraceBuf[lstrlenA(szTraceBuf)], \ MAXDEBUGSTRINGLENGTH - lstrlenA(szTraceBuf), \ lpszFormat, \ ap \ ); \ \ wsprintfA(&szTraceBuf[lstrlenA(szTraceBuf)], \ " Returned[%lx] %s\n", \ hr, \ lpMsgBuf); \ \ OutputDebugStringA (szTraceBuf); \ \ va_end(ap); \ } \ \ if (sg_dwTraceID != INVALID_TRACEID) \ { \ wsprintfA(szTraceBuf, "[%s] %s::%s Returned[%lx] %s", TraceLevel(dwDbgLevel), _T(#x), lpszFormat,hr, lpMsgBuf ); \ \ va_start(arglist, lpszFormat); \ TraceVprintfExA(sg_dwTraceID, dwDbgLevel | TRACE_USE_MSEC, szTraceBuf, arglist); \ va_end(arglist); \ } \ \ if(lpMsgBuf != NULL) \ { \ LocalFree( lpMsgBuf ); \ } \ }
#else // TRACELOG not defined
#define TRACELOGREGISTER(arg)
#define TRACELOGDEREGISTER()
#define LOG(arg)
#define STATICLOG(arg)
#define DECLARE_DEBUG_ADDREF_RELEASE(x)
#define DECLARE_TRACELOG_CLASS(x)
#endif // TRACELOG
class CAsyncRequestReply { private: HANDLE hRepliedSemaphore; DWORD dwID; BOOL bReply; HRESULT hResult;
public: DECLARE_TRACELOG_CLASS(CAsyncRequestReply) CAsyncRequestReply(DWORD id, BOOL b, HRESULT hr) { if( (hRepliedSemaphore = CreateSemaphore(NULL,0,1,NULL)) == NULL ) { LOG((TL_INFO, "create CAsyncRequest - CreateSemaphore failed")); hResult = E_OUTOFMEMORY; } else { dwID = id; bReply = b; hResult = hr; LOG((TL_INFO, "create CAsyncRequest %d ",dwID)); } }
~CAsyncRequestReply() { LOG((TL_INFO, "delete CAsyncRequest %d ",dwID));
if( NULL != hRepliedSemaphore ) { CloseHandle(hRepliedSemaphore); } }
inline DWORD getID() {return dwID;}; inline BOOL IsReply() {return bReply;}; inline HRESULT getResult() {return hResult;}; inline void setResult(HRESULT hr) {hResult = hr;};
HRESULT wait() { LOG((TL_INFO, "wait CAsyncRequest %d ",dwID));
extern DWORD gdwTapi2AsynchronousCallTimeout;
DWORD rc = WaitForSingleObject(hRepliedSemaphore, gdwTapi2AsynchronousCallTimeout); switch (rc) { case WAIT_ABANDONED: LOG((TL_ERROR, "wait CAsyncRequest %d WaitForSingle object returned WAIT_ABANDONED",dwID)); hResult = TAPIERR_REQUESTFAILED; break;
case WAIT_OBJECT_0: break; case WAIT_TIMEOUT: LOG((TL_WARN, "wait CAsyncRequest %d WaitForSingle object returned WAIT_TIMEOUT",dwID)); // -1 won't overlap with any value that may be returned from tapi2 calls.
hResult = -1; break; case WAIT_FAILED: { DWORD nLastError = GetLastError(); LOG((TL_ERROR, "wait CAsyncRequest %d WaitForSingle object returned WAIT_FAILED, LastError = %d", dwID, nLastError)); hResult = TAPIERR_REQUESTFAILED; break; } default: break;
}
return hResult; }
void signal() { LOG((TL_INFO, "signal CAsyncRequest %d ",dwID)); ReleaseSemaphore(hRepliedSemaphore, 1, NULL); }
};
typedef list<CAsyncRequestReply *> RequestReplyList;
class CAsyncReplyList { public: DECLARE_TRACELOG_CLASS(CAsyncReplyList) private: RequestReplyList replyList; CRITICAL_SECTION csReply;
CAsyncRequestReply *find(DWORD dwID) { RequestReplyList::iterator i; CAsyncRequestReply *pResult = NULL;
// walk list searching for match
i = replyList.begin(); // iterate over current replies
while ( i != replyList.end() ) { // found it
if ((*i)->getID() == dwID ) { pResult = *i; break; }
i++; }
//returning pointer to matching entry or NULL
return pResult; }
public: CAsyncReplyList() {InitializeCriticalSection( &csReply );};
~CAsyncReplyList() { FreeList(); DeleteCriticalSection( &csReply ); }
void FreeList() { RequestReplyList::iterator i;
EnterCriticalSection( &csReply ); // walk list deleting entries
i = replyList.begin(); while ( i != replyList.end() ) delete *i++;
replyList.clear(); LeaveCriticalSection( &csReply ); };
void remove(CAsyncRequestReply *a) { EnterCriticalSection( &csReply ); replyList.remove(a); LeaveCriticalSection( &csReply ); }
CAsyncRequestReply *addRequest(DWORD id) { CAsyncRequestReply *pReply;
EnterCriticalSection( &csReply );
// Check list to see if we're already on the list ( i.e. the response LINE_REPLY got here before us)
pReply = find(id); if (pReply == NULL || !pReply->IsReply()) { // No so we got here before the reply, create a new request entry on the list
pReply = new CAsyncRequestReply(id, FALSE, 0); if (NULL == pReply) { LOG((TL_ERROR, "Could not alloc for CAsyncRequestReply")); } else if( pReply->getResult() == E_OUTOFMEMORY ) { delete pReply; pReply = NULL; LOG((TL_ERROR, "addRequest - Create Semaphore failed")); } else { try { replyList.push_back(pReply); } catch(...) { delete pReply; pReply = NULL; LOG((TL_ERROR, "addRequest- failed - because of alloc failure"));
} } } // Else, the reply comes before me, remove it from the list
else { replyList.remove (pReply); }
LeaveCriticalSection( &csReply ); return pReply; }
CAsyncRequestReply *addReply(DWORD id, HRESULT hr) { CAsyncRequestReply *pReply;
EnterCriticalSection( &csReply );
// Check list to see if we have a matching entry
pReply = find(id); if (pReply == NULL || pReply->IsReply()) { // No so we got here before the request returned, create a new entry on the list
pReply = new CAsyncRequestReply(id, TRUE, hr); if (NULL == pReply) { LOG((TL_ERROR, "Could not alloc for CAsyncRequestReply")); } else if( pReply->getResult() == E_OUTOFMEMORY ) { delete pReply; pReply = NULL; LOG((TL_ERROR, "addReply - Create Semaphore failed")); } else { try { replyList.push_back(pReply); } catch(...) { delete pReply; pReply = NULL; LOG((TL_ERROR, "addReply- failed - because of alloc failure")); } } } else { // Use the existing entry, set its return code & signal to the waiting request code
pReply->setResult(hr); replyList.remove (pReply); }
LeaveCriticalSection( &csReply ); return pReply; }
};
////////////////////////////////////////////////////////////////////
//
// Class CRetryQueue
// Maintains queue of Async messages for retry.
// Typically these relate to calls not yet entered in the call hash-
// table, such that findCallObject failed. These are reprocessed
// once the call is entered & the ghAsyncRetryQueueEvent event is
// signalled.
//
// Added criticalsection - thread safe now
//
////////////////////////////////////////////////////////////////////
class CRetryQueue { typedef struct _tagRetryQueueEntry { DWORD dwRetryCount; PASYNCEVENTMSG pMessage; } RETRY_QUEUE_ENTRY, *PRETRY_QUEUE_ENTRY; typedef list<RETRY_QUEUE_ENTRY *> RetryQueueListType; #define MAX_REQUEUE_TRIES 3
private:
RetryQueueListType m_RetryQueueList; CRITICAL_SECTION m_cs;
//
// is the queue open for new entries?
//
BOOL m_bAcceptNewEntries;
private:
//
// requeue the entry that failed processing. don't do this if the queue is
// closed.
//
void RequeueEvent(PRETRY_QUEUE_ENTRY pQueueEntry);
public: DECLARE_TRACELOG_CLASS(CRetryQueue)
CRetryQueue() :m_bAcceptNewEntries(FALSE) { InitializeCriticalSection( &m_cs ); }
~CRetryQueue();
void Lock(){ EnterCriticalSection( &m_cs ); } void Unlock(){ LeaveCriticalSection( &m_cs ); } BOOL QueueEvent(PASYNCEVENTMSG pEvent); BOOL DequeueEvent(PRETRY_QUEUE_ENTRY * ppEvent); void ProcessQueue(); void RemoveNewCallHub(DWORD); inline BOOL ItemsInQueue() { BOOL bReturn;
Lock(); bReturn = !m_RetryQueueList.empty(); Unlock();
return bReturn; }
//
// after this function returns, the queue will accept new entries
//
void OpenForNewEntries();
//
// new entries will be denied after this function returns
//
void CloseForNewEntries();
};
#define MAXCACHEENTRIES 5
#define BUFFERTYPE_ADDRCAP 1
#define BUFFERTYPE_LINEDEVCAP 2
#define BUFFERTYPE_PHONECAP 3
typedef struct { UINT_PTR pObject; LPVOID pBuffer;
} CACHEENTRY;
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// CStructCache
//
// A simple class to cache TAPI structures in tapi3.dll
//
// This implementation has an array of CACHEENTRY structures. Each
// CACHEENTRY structure has 2 member:
// pObject - the object that currently owns the buffer
// pBuffer - the buffer
//
// The array is a fixed size, which is set when the class is initialized
// The memory for the buffers is allocated during initialization as
// well. It is possible that a buffer gets realloced (replaced)
// at some time.
//
// This implementation assumes that the object that owns the buffer
// uses it's critical sections correctly. That is, it is locked when
// SetXxxBuffer is called, and it is locked when getting and using
// a buffer If not, the buffer can disapper from the object at any time.
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
class CStructCache { private: CRITICAL_SECTION m_cs; DWORD m_dwType; DWORD m_dwMaxEntries; DWORD m_dwUsedEntries; CACHEENTRY m_aEntries[MAXCACHEENTRIES];
public: DECLARE_TRACELOG_CLASS(CStructCache)
CStructCache() { int iCount;
InitializeCriticalSection( &m_cs );
for( iCount=0; iCount<MAXCACHEENTRIES; iCount++) { m_aEntries[iCount].pObject = NULL; m_aEntries[iCount].pBuffer = NULL; }
m_dwType = 0; m_dwMaxEntries = 0; m_dwUsedEntries = 0; }
~CStructCache() { DeleteCriticalSection( &m_cs ); }
void Lock() { EnterCriticalSection( &m_cs ); } void Unlock() { LeaveCriticalSection( &m_cs ); }
HRESULT Initialize( DWORD dwMaxEntries, DWORD dwSize, DWORD dwType ); HRESULT Shutdown(); HRESULT GetBuffer( UINT_PTR pNewObject, LPVOID * ppReturnStruct ); HRESULT SetBuffer( UINT_PTR pObject, LPVOID pNewStruct ); HRESULT InvalidateBuffer( UINT_PTR pObject ); };
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// CArray - based on from CSimpleArray from atl
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
template <class T> class CTObjectArray { private: T * m_aT; int m_nSize; int m_nUsed;
public: DECLARE_TRACELOG_CLASS(CTObjectArray) CTObjectArray() : m_aT(NULL), m_nSize(0), m_nUsed(0){}
~CTObjectArray() {}
int GetSize() const { return m_nUsed; } BOOL Add(T& t) { if(m_nSize == m_nUsed) { T * aT; int nNewSize; nNewSize = (m_nSize == 0) ? 1 : (m_nSize * 2); aT = (T*) ClientAlloc (nNewSize * sizeof(T)); if(aT == NULL) { return FALSE; }
CopyMemory( aT, m_aT, m_nUsed * sizeof(T) );
ClientFree( m_aT );
m_aT = aT; m_nSize = nNewSize; }
m_aT[m_nUsed] = t;
t->AddRef();
m_nUsed++; return TRUE; } BOOL Remove(T& t) { int nIndex = Find(t); if(nIndex == -1) return FALSE; return RemoveAt(nIndex); } BOOL RemoveAt(int nIndex) { m_aT[nIndex]->Release();
if(nIndex != (m_nUsed - 1)) { MoveMemory( (void*)&m_aT[nIndex], (void*)&m_aT[nIndex + 1], (m_nUsed - (nIndex + 1)) * sizeof(T) ); }
m_nUsed--; return TRUE; } void Shutdown() { if( NULL != m_aT ) { int index;
for (index = 0; index < m_nUsed; index++) { m_aT[index]->Release(); }
ClientFree(m_aT); m_aT = NULL; m_nUsed = 0; m_nSize = 0; } } T& operator[] (int nIndex) const { _ASSERTE(nIndex >= 0 && nIndex < m_nUsed); return m_aT[nIndex]; } int Find(T& t) const { for(int i = 0; i < m_nUsed; i++) { if(m_aT[i] == t) return i; } return -1; // not found
} };
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// CArray - based on from CSimpleArray from atl
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
template <class T> class CTArray { private: T * m_aT; int m_nSize; int m_nUsed;
public: DECLARE_TRACELOG_CLASS(CTArray)
CTArray() : m_aT(NULL), m_nSize(0), m_nUsed(0){}
~CTArray() {}
int GetSize() const { return m_nUsed; } BOOL Add(T& t) { if(m_nSize == m_nUsed) { T * aT; int nNewSize; nNewSize = (m_nSize == 0) ? 1 : (m_nSize * 2); aT = (T*) ClientAlloc (nNewSize * sizeof(T)); if(aT == NULL) { return FALSE; }
CopyMemory( aT, m_aT, m_nUsed * sizeof(T) );
ClientFree( m_aT );
m_aT = aT; m_nSize = nNewSize; }
m_aT[m_nUsed] = t;
m_nUsed++; return TRUE; } BOOL Remove(T& t) { int nIndex = Find(t); if(nIndex == -1) return FALSE; return RemoveAt(nIndex); } BOOL RemoveAt(int nIndex) { if(nIndex != (m_nUsed - 1)) { MoveMemory( (void*)&m_aT[nIndex], (void*)&m_aT[nIndex + 1], (m_nUsed - (nIndex + 1)) * sizeof(T) ); }
m_nUsed--; return TRUE; } void Shutdown() { if( NULL != m_aT ) { int index;
ClientFree(m_aT); m_aT = NULL; m_nUsed = 0; m_nSize = 0; } } T& operator[] (int nIndex) const { _ASSERTE(nIndex >= 0 && nIndex < m_nUsed); return m_aT[nIndex]; } int Find(T& t) const { for(int i = 0; i < m_nUsed; i++) { if(m_aT[i] == t) return i; } return -1; // not found
} };
#endif // __UTILS_H__
|