// CTraceServer.cpp
|
|
// defines the CTraceServer class
|
|
#include "stdafx.h"
|
#include <time.h>
|
#include <io.h>
|
#include <sys/types.h>
|
#include <sys/timeb.h>
|
#include <sys/stat.h>
|
#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<NUM_TRACE_BUFFERS; i++) {
|
char *buffer = new char[TRACE_BUFFER_SIZE];
|
if (buffer != NULL) {
|
bufferQ.push_back(buffer);
|
}
|
}
|
traceThread = CreateThread(NULL, 0, TraceThread, this, 0, &traceThreadID);
|
WaitForSingleObject(traceThreadStartedEvent, INFINITE);
|
}
|
}
|
return returnCode;
|
}
|
|
int
|
CTraceServer::uninitialize() {
|
bool l_initialized;
|
int returnCode = 0;
|
EnterCriticalSection(&m_csTraceMutex);
|
l_initialized = initialized;
|
initialized = false;
|
LeaveCriticalSection(&m_csTraceMutex);
|
|
if (!l_initialized) {
|
return 0;
|
}
|
|
// wait for the file print thread to stop. this way it will return all trace buffers to the free list
|
ResetEvent(traceThreadStartedEvent);
|
PostThreadMessage(traceThreadID, WM_QUIT, 1234, 5678);
|
WaitForSingleObject(traceThreadStartedEvent, INFINITE);
|
traceThreadID = 0;
|
// free trace buffers
|
int buffersFreed = 0;
|
int nullBuffers = 0;
|
EnterCriticalSection(&m_csTraceMutex);
|
while (bufferQ.size() > 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<NUM_TRACE_FILES; i++) {
|
string fileName = makeTraceFileName(i);
|
struct _stat fileStats;
|
if (_stat(fileName.c_str(), &fileStats) == 0) {
|
if (fileStats.st_mtime >= 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;
|
}
|