// CTraceServer.cpp // defines the CTraceServer class #include "stdafx.h" #include #include #include #include #include #include "CTraceServer.h" CTraceServer::CTraceServer() { traceFileName = ""; traceFileNumber = 0; fpTraceFile = NULL; initialized = false; traceThreadStartedEvent = NULL; traceThread = NULL; traceThreadID = 0; traceThreadStartedEvent = CreateEvent(NULL, TRUE, FALSE, "TraceThreadEvent"); InitializeCriticalSection(&m_csTraceMutex); } CTraceServer::~CTraceServer() { if (traceThreadStartedEvent) CloseHandle(traceThreadStartedEvent); traceThreadStartedEvent = NULL; DeleteCriticalSection(&m_csTraceMutex); } int CTraceServer::initialize() { bool l_initialized; int returnCode = 0; EnterCriticalSection(&m_csTraceMutex); l_initialized = initialized; initialized = true; LeaveCriticalSection(&m_csTraceMutex); if (l_initialized) { WaitForSingleObject(traceThreadStartedEvent, INFINITE); } else { bufferMisses = 0; // open trace file if (!openFirstTraceFile()) { returnCode = -10; } else { // initialize trace buffers bufferQ.erase(bufferQ.begin(), bufferQ.end()); for (int i=0; i 0) { char *buffer = bufferQ.front(); bufferQ.pop_front(); if (buffer) { delete [] (buffer); buffersFreed++; } else nullBuffers++; } LeaveCriticalSection(&m_csTraceMutex); fprintf(fpTraceFile, "TRACER : freed %d buffers(%d null buffers) & %d buffer misses\n", buffersFreed, nullBuffers, bufferMisses); // close trace file if (fpTraceFile) { fflush(fpTraceFile); fclose(fpTraceFile); fpTraceFile = NULL; } _chmod(traceFileName.c_str(), _S_IREAD); CloseHandle(traceThread); traceThread = NULL; return 0; } DWORD CTraceServer::getTraceThreadID() { WaitForSingleObject(traceThreadStartedEvent, INFINITE); return traceThreadID; } char * CTraceServer::getTraceBuffer() { char *buffer = NULL; EnterCriticalSection(&m_csTraceMutex); if (bufferQ.size() > 0) { buffer = bufferQ.front(); bufferQ.pop_front(); } LeaveCriticalSection(&m_csTraceMutex); if (buffer) { buffer[TRACE_BUFFER_SIZE - 1] = '\n'; } else { bufferMisses++; } return buffer; } void CTraceServer::freeTraceBuffer(char *traceBuffer) { if (traceBuffer) { EnterCriticalSection(&m_csTraceMutex); bufferQ.push_back(traceBuffer); LeaveCriticalSection(&m_csTraceMutex); } } string CTraceServer::makeTraceFileName(int traceFileNum) { char fileName[100]; sprintf(fileName, "TraceFile_%04d.txt", traceFileNum); std::string newFile(fileName); return newFile; } bool CTraceServer::openFirstTraceFile() { // find out the last trace file that was created. open the one after that int lastTraceFileNumber = -1; struct _stat lastTraceFileStats; lastTraceFileStats.st_mtime = 0; for (int i=0; i= lastTraceFileStats.st_mtime) { lastTraceFileStats = fileStats; lastTraceFileNumber = i; } } } if (lastTraceFileNumber < 0) traceFileNumber = 1; else traceFileNumber = lastTraceFileNumber; traceFileName = makeTraceFileName(traceFileNumber); _chmod(traceFileName.c_str(), _S_IREAD | _S_IWRITE); // in case the file exists and is read-only, change perms fpTraceFile = fopen(traceFileName.c_str(), "ac"); if (fpTraceFile == NULL) return false; return true; } bool CTraceServer::changeTraceFile() { bool result = true; if (fpTraceFile) fclose(fpTraceFile); _chmod(traceFileName.c_str(), _S_IREAD); traceFileNumber = (traceFileNumber + 1) % NUM_TRACE_FILES; traceFileName = makeTraceFileName(traceFileNumber); _chmod(traceFileName.c_str(), _S_IREAD | _S_IWRITE); // in case the file exists and is read-only, change perms fpTraceFile = fopen(traceFileName.c_str(), "wc"); if (!fpTraceFile) result = false; return result; } int CTraceServer::trace(char *traceBuffer) { int returnValue(0); if (PostThreadMessage(traceThreadID, WM_USER, (WPARAM)traceBuffer, 0) == 0) { // that means error happened returnValue = (int)GetLastError(); freeTraceBuffer(traceBuffer); } return returnValue; } DWORD WINAPI CTraceServer::TraceThread(LPVOID pParams) { CTraceServer *traceServer = (CTraceServer *)pParams; return traceServer->doTraceThread(); } void CTraceServer::printTime() { time_t currentTime_t; time(¤tTime_t); struct tm *currentTm = localtime(¤tTime_t); fprintf(fpTraceFile, "\n------------ %s", asctime(currentTm)); } DWORD CTraceServer::doTraceThread() { DWORD resultCode = 0; int cnt = 0; MSG traceMsg; DWORD lastTime = 0; BOOL postResult; HANDLE thisThread = GetCurrentThread(); SetThreadPriority(thisThread, THREAD_PRIORITY_IDLE); PeekMessage(&traceMsg, NULL, WM_USER, WM_USER, PM_NOREMOVE); while(true) { postResult = PostThreadMessage(traceThreadID, WM_USER, 0, 0); if (postResult != 0) break; DWORD lastError = GetLastError(); Sleep(100); } GetMessage(&traceMsg, NULL, 0, WM_USER); printTime(); SetEvent(traceThreadStartedEvent); int flushTimer(0); bool needsFlush(false); while(true) { BOOL result = PeekMessage(&traceMsg, NULL, WM_USER, WM_USER, PM_NOREMOVE); if (result != 0 || !needsFlush) { // there are messages, or we do not need flush. so wait for next message result = GetMessage(&traceMsg, NULL, 0, WM_USER); if (result == 0) { // means WM_QUIT message received if ((int)(traceMsg.wParam) == 1234 && (int)(traceMsg.lParam) == 5678) { fprintf(fpTraceFile, "Got WM_QUIT message : stopping thread\n"); printTime(); fflush(fpTraceFile); SetEvent(traceThreadStartedEvent); resultCode = 0; break; } else fprintf(fpTraceFile, "Got WM_QUIT message\n"); } else if (result == -1) { // error happened in GetMessage printTime(); fprintf(fpTraceFile, "Error in GetMessage in the tracer thread. Return value 0x%x %d\n", result, result); } else { // normal trace message char *buffer = (char *)(traceMsg.wParam); if (abs(traceMsg.time - lastTime) > TIMESTAMP_INTERVAL) { lastTime = traceMsg.time; printTime(); } struct timeb currentTime_b; ftime(¤tTime_b); time_t currentTime_t = currentTime_b.time; struct tm *currentTm = localtime(¤tTime_t); fprintf(fpTraceFile, "%02u:%02u:%02u.%03u : %s", currentTm->tm_hour, currentTm->tm_min, currentTm->tm_sec, currentTime_b.millitm, buffer); needsFlush = true; freeTraceBuffer(buffer); cnt = (cnt + 1)%10; if (!cnt) { if (ftell(fpTraceFile) > MAX_TRACEFILE_SIZE) { printTime(); if (!changeTraceFile()) { resultCode = -20; break; } } } } } else { // no messages in queue and we need flush fflush(fpTraceFile); needsFlush = false; } } return resultCode; }