- Naming style migrated to camel-case - P7lib logger sources added - Vcpkg manifest, CMake presets and build moved to root - SDL2, Vulkan and RmlUi dependencies added - Logger LOG macro added - Logger configuration - SDL2 window configuration - Vulkan configuration - RmlUi configuration - SDL event loop
2084 lines
65 KiB
C++
2084 lines
65 KiB
C++
////////////////////////////////////////////////////////////////////////////////
|
|
// /
|
|
// 2012-2020 (c) Baical /
|
|
// /
|
|
// This library is free software; you can redistribute it and/or /
|
|
// modify it under the terms of the GNU Lesser General Public /
|
|
// License as published by the Free Software Foundation; either /
|
|
// version 3.0 of the License, or (at your option) any later version. /
|
|
// /
|
|
// This library is distributed in the hope that it will be useful, /
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of /
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU /
|
|
// Lesser General Public License for more details. /
|
|
// /
|
|
// You should have received a copy of the GNU Lesser General Public /
|
|
// License along with this library. /
|
|
// /
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// This header file provide functionality to format data into text format /
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "CommonClient.h"
|
|
#include "ClText.h"
|
|
|
|
//allow to see dump of memory leaks at the end of test in VS debug output
|
|
//#define _CRTDBG_MAP_ALLOC
|
|
//#include <crtdbg.h>
|
|
//#ifdef _DEBUG
|
|
//#define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
|
|
//#define new DEBUG_NEW
|
|
//#endif
|
|
|
|
#define THREAD_IDLE_TIMEOUT (100)
|
|
#define FREE_DATA_WAIT_TIMEOUT (100)
|
|
|
|
enum eThreadsEvents
|
|
{
|
|
eThreadEventExit = MEVENT_SIGNAL_0,
|
|
eThreadEventHasData,
|
|
eThreadEventDataFlush,
|
|
eThreadEventsCount = 3
|
|
};
|
|
|
|
#define DATA_FREE_SIGNAL (MEVENT_SIGNAL_0)
|
|
|
|
#define MIN_BUFFER_SIZE (16384)
|
|
#define MAX_BUFFER_SIZE (131072)
|
|
#define MIN_BUFFERS_COUNT (3)
|
|
|
|
#define DEF_POOL_SIZE (MAX_BUFFER_SIZE * 16)
|
|
#define MIN_POOL_SIZE (MIN_BUFFER_SIZE * MIN_BUFFERS_COUNT)
|
|
#define TRACE_TEXT_LENGTH (0x1000)
|
|
|
|
#define TAIL_SIZE(iBuffer) (m_dwBuffer_Size - (tUINT32)iBuffer->szUsed)
|
|
|
|
#define TIME_HRS_100NS 36000000000ull
|
|
#define TIME_MIN_100NS 600000000ull
|
|
#define TIME_SEC_100NS 10000000ull
|
|
#define TIME_MSC_100NS 10000ull
|
|
|
|
#ifndef min
|
|
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
|
#endif
|
|
|
|
#if !defined(MAXUINT64)
|
|
#define MAXUINT64 ((tUINT64)~((tUINT64)0))
|
|
#endif
|
|
|
|
#define REALLOC_MESSAGE(i_szValue, i_pClient)\
|
|
if ((i_szValue + 256) >= (i_pClient->m_szMsg - (i_pClient->m_pMsgCur - i_pClient->m_pMsg)))\
|
|
{\
|
|
size_t l_szNew = i_pClient->m_szMsg + i_szValue + 256;\
|
|
tXCHAR *l_pNew = (tXCHAR *)realloc(i_pClient->m_pMsg, l_szNew * sizeof(tXCHAR));\
|
|
if (l_pNew)\
|
|
{\
|
|
i_pClient->m_pMsgCur = l_pNew + (i_pClient->m_pMsgCur - i_pClient->m_pMsg);\
|
|
i_pClient->m_pMsg = l_pNew;\
|
|
i_pClient->m_szMsg = l_szNew;\
|
|
}\
|
|
}\
|
|
|
|
|
|
struct sField
|
|
{
|
|
const tXCHAR *pField;
|
|
CClText::fnFormat pFormat;
|
|
};
|
|
|
|
static const sField g_pFields[] =
|
|
{
|
|
{ CLIENT_FMT_CHANNEL, CClText::FormatChannel },
|
|
{ CLIENT_FMT_MSG_ID, CClText::FormatMessageId },
|
|
{ CLIENT_FMT_MSG_INDEX, CClText::FormatMessageIndex },
|
|
{ CLIENT_FMT_TIME_FULL, CClText::FormatTimeFull },
|
|
{ CLIENT_FMT_TIME_MEDIUM, CClText::FormatTimeMedium },
|
|
{ CLIENT_FMT_TIME_SHORT, CClText::FormatTimeShort },
|
|
{ CLIENT_FMT_TIME_DIFF, CClText::FormatTimeDiff },
|
|
{ CLIENT_FMT_TIME_COUNT, CClText::FormatTimeCount },
|
|
{ CLIENT_FMT_LEVEL, CClText::FormatLevel },
|
|
{ CLIENT_FMT_THREAD_ID, CClText::FormatThreadId },
|
|
{ CLIENT_FMT_THREAD_NAME, CClText::FormatThreadName },
|
|
{ CLIENT_FMT_CPU_CORE, CClText::FormatCpuCore },
|
|
{ CLIENT_FMT_MODULE_ID, CClText::FormatModuleId },
|
|
{ CLIENT_FMT_MODULE_NAME, CClText::FormatModuleName },
|
|
{ CLIENT_FMT_FILE_FULL, CClText::FormatFilePath },
|
|
{ CLIENT_FMT_FILE_SHORT, CClText::FormatFileName },
|
|
{ CLIENT_FMT_FILE_LINE, CClText::FormatFileLine },
|
|
{ CLIENT_FMT_FUNCTION, CClText::FormatFunction },
|
|
{ CLIENT_FMT_MSG, CClText::FormatMsg }
|
|
};
|
|
|
|
|
|
#define LEVEL_TEXT_LENGTH (5)
|
|
static const tXCHAR *g_pLevel[EP7TRACE_LEVEL_COUNT] =
|
|
{
|
|
TM("TRACE"),
|
|
TM("DEBUG"),
|
|
TM("INFO "),
|
|
TM("WARN."),
|
|
TM("ERROR"),
|
|
TM("PANIC")
|
|
};
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
CClText::fnFormat GetFormatFunction(const tXCHAR *i_pField)
|
|
{
|
|
if (!*i_pField) //at least 2 chars
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
for (size_t l_szI = 0; l_szI < LENGTH(g_pFields); l_szI++)
|
|
{
|
|
#ifdef UTF8_ENCODING
|
|
if ((*(tUINT16*)i_pField) == (*(tUINT16*)g_pFields[l_szI].pField))
|
|
#else
|
|
if ((*(tUINT32*)i_pField) == (*(tUINT32*)g_pFields[l_szI].pField))
|
|
#endif
|
|
{
|
|
return g_pFields[l_szI].pFormat;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// sTraceDescEx
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
sTraceDescEx::sTraceDescEx(const sP7Trace_Format *i_pFormat,
|
|
CFormatter::sBuffer *i_pBuffer,
|
|
tBOOL i_bBigEndian
|
|
)
|
|
: sTraceDesc()
|
|
, pBuffer(NULL)
|
|
, dwSize(0)
|
|
, pFormat(NULL)
|
|
, pArgs(NULL)
|
|
, dwArgsLen(0)
|
|
{
|
|
size_t l_szLen = 0;
|
|
|
|
if (i_pFormat)
|
|
{
|
|
dwSize = i_pFormat->sCommon.dwSize;
|
|
pBuffer = (tUINT8*)malloc(dwSize);
|
|
}
|
|
|
|
if (pBuffer)
|
|
{
|
|
memcpy(pBuffer, i_pFormat, dwSize);
|
|
wLine = i_pFormat->wLine;
|
|
dwArgsLen = i_pFormat->wArgs_Len;
|
|
dwModuleID = i_pFormat->wModuleID;
|
|
pArgs = (sP7Trace_Arg*)(pBuffer + sizeof(sP7Trace_Format));
|
|
|
|
#ifdef UTF8_ENCODING
|
|
tWCHAR *l_pFormat = (tWCHAR *)(pArgs + dwArgsLen);
|
|
size_t l_szUtf8Chars = 0;
|
|
size_t l_szUtf8Bytes = 0;
|
|
l_szLen = Get_UTF8_Stat(l_pFormat, l_szUtf8Bytes, l_szUtf8Chars);
|
|
l_szUtf8Bytes += 8;
|
|
|
|
pFormat = (tXCHAR*)malloc(l_szUtf8Bytes * sizeof(tXCHAR));
|
|
Convert_UTF16_To_UTF8(l_pFormat, (tACHAR*)pFormat, l_szUtf8Bytes);
|
|
|
|
pFilePath = (char*)(l_pFormat + l_szLen + 1);
|
|
szFilePath = strlen(pFilePath);
|
|
pFunction = (char*)(pFilePath + szFilePath + 1);
|
|
szFunction = strlen(pFunction);
|
|
#else
|
|
char *l_pFilePath;
|
|
char *l_pFunction;
|
|
pFormat = (tXCHAR *)(pArgs + dwArgsLen);
|
|
l_szLen = PStrLen(pFormat);
|
|
l_pFilePath = (char*)(pFormat + l_szLen + 1);
|
|
szFilePath = strlen(l_pFilePath);
|
|
l_pFunction = (char*)(l_pFilePath + szFilePath + 1);
|
|
szFunction = strlen(l_pFunction);
|
|
pFilePath = (tXCHAR*)malloc((szFilePath + 16)*sizeof(tXCHAR));
|
|
pFunction = (tXCHAR*)malloc((szFunction + 16)*sizeof(tXCHAR));
|
|
Convert_UTF8_To_UTF16(l_pFilePath, pFilePath, (tUINT32)szFilePath + 1);
|
|
Convert_UTF8_To_UTF16(l_pFunction, pFunction, (tUINT32)szFunction + 1);
|
|
#endif
|
|
|
|
if ( (pFileName = PStrrChr(pFilePath, TM('\\')))
|
|
|| (pFileName = PStrrChr(pFilePath, TM('/')))
|
|
)
|
|
{
|
|
pFileName ++;
|
|
}
|
|
else
|
|
{
|
|
pFileName = pFilePath;
|
|
};
|
|
|
|
szFileName = PStrLen(pFileName);
|
|
|
|
pFormatter = new CFormatter(pFormat, pArgs, (size_t)dwArgsLen, i_pBuffer);
|
|
|
|
if (i_bBigEndian)
|
|
{
|
|
pFormatter->EnableBigEndian();
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
sTraceDescEx::~sTraceDescEx()
|
|
{
|
|
if (pBuffer)
|
|
{
|
|
free(pBuffer);
|
|
pBuffer = NULL;
|
|
}
|
|
|
|
if (pFormatter)
|
|
{
|
|
delete pFormatter;
|
|
pFormatter = NULL;
|
|
}
|
|
|
|
#ifdef UTF8_ENCODING
|
|
if (pFormat)
|
|
{
|
|
free(pFormat);
|
|
pFormat = NULL;
|
|
}
|
|
#else
|
|
if (pFilePath)
|
|
{
|
|
free(pFilePath);
|
|
}
|
|
if (pFunction)
|
|
{
|
|
free(pFunction);
|
|
}
|
|
pFilePath = NULL;
|
|
pFunction = NULL;
|
|
pFileName = NULL;
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// CTxtChannel
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//CTxtChannel()
|
|
CTxtChannel::CTxtChannel(const sP7Trace_Info *i_pInfo, tBOOL i_bBig_Endian)
|
|
: m_qwStreamTime(0ull)
|
|
, m_qwTimer_Value(i_pInfo->qwTimer_Value)
|
|
, m_qwTimer_Frequency(i_pInfo->qwTimer_Frequency)
|
|
, m_qwFlags(i_pInfo->qwFlags)
|
|
, m_pText(NULL)
|
|
, m_szText(TRACE_TEXT_LENGTH)
|
|
, m_qwTimeLast(i_pInfo->qwTimer_Value)
|
|
, m_szName(0)
|
|
, m_pBuffer(NULL)
|
|
, m_bBig_Endian(i_bBig_Endian)
|
|
{
|
|
#ifdef UTF8_ENCODING
|
|
Convert_UTF16_To_UTF8(i_pInfo->pName, (tACHAR*)m_pName, P7TRACE_NAME_LENGTH);
|
|
#else
|
|
PStrCpy(m_pName, P7TRACE_NAME_LENGTH, (const wchar_t*)i_pInfo->pName);
|
|
#endif
|
|
|
|
m_pBuffer = new CFormatter::sBuffer(4096);
|
|
|
|
m_szName = PStrLen(m_pName);
|
|
|
|
m_qwStreamTime = (tUINT64)i_pInfo->dwTime_Lo + (((tUINT64)i_pInfo->dwTime_Hi) << 32);
|
|
|
|
//fill list by empty elements, prepare data ...
|
|
for (tUINT32 l_dwIDX = 0; l_dwIDX < 1536; l_dwIDX ++)
|
|
{
|
|
m_cDesc.Add_After(NULL, NULL);
|
|
}
|
|
//trick to build index, this is new list and index is not build
|
|
//when we try to access to element by index - we create internal index
|
|
//table
|
|
m_cDesc[0];
|
|
|
|
//fill list by empty elements, prepare data ...
|
|
for (tUINT32 l_dwIDX = 0; l_dwIDX < 128; l_dwIDX ++)
|
|
{
|
|
m_cModules.Add_After(NULL, NULL);
|
|
}
|
|
|
|
//trick to build index, this is new list and index is not build
|
|
//when we try to access to element by index - we create internal index
|
|
//table
|
|
m_cModules[0];
|
|
|
|
m_pText = (tXCHAR*)malloc(m_szText * sizeof(tXCHAR));
|
|
}//CTxtChannel()
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//~CTxtChannel()
|
|
CTxtChannel::~CTxtChannel()
|
|
{
|
|
m_cDesc.Clear(TRUE);
|
|
m_cModules.Clear(TRUE);
|
|
m_cThreads.Clear();
|
|
|
|
if (m_pText)
|
|
{
|
|
free(m_pText);
|
|
m_pText = NULL;
|
|
}
|
|
|
|
if (m_pBuffer)
|
|
{
|
|
m_pBuffer->Release();
|
|
m_pBuffer = NULL;
|
|
}
|
|
}//~CTxtChannel()
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//PutFormat
|
|
void CTxtChannel::PutFormat(const sP7Trace_Format *i_pDesc)
|
|
{
|
|
//fill by empty elements if ID is larger than elements count
|
|
while (m_cDesc.Count() <= i_pDesc->wID)
|
|
{
|
|
m_cDesc.Add_After(m_cDesc.Get_Last(), NULL);
|
|
}
|
|
|
|
if (NULL == m_cDesc[i_pDesc->wID])
|
|
{
|
|
m_cDesc.Put_Data(m_cDesc.Get_ByIndex(i_pDesc->wID),
|
|
new sTraceDescEx(i_pDesc, m_pBuffer, m_bBig_Endian),
|
|
TRUE
|
|
);
|
|
}
|
|
}//PutFormat
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//PutModule
|
|
void CTxtChannel::PutModule(const sP7Trace_Module *i_pMod)
|
|
{
|
|
//fill by empty elements if ID is larger than elements count
|
|
while (m_cModules.Count() <= i_pMod->wModuleID)
|
|
{
|
|
m_cModules.Add_After(m_cModules.Get_Last(), NULL);
|
|
}
|
|
|
|
if (NULL == m_cModules[i_pMod->wModuleID])
|
|
{
|
|
sP7TraceMod *l_pMod = new sP7TraceMod();
|
|
l_pMod->eVerbosity = i_pMod->eVerbosity;
|
|
#ifdef UTF8_ENCODING
|
|
memcpy(l_pMod->pName, i_pMod->pName, P7TRACE_MODULE_NAME_LENGTH);
|
|
#else
|
|
Convert_UTF8_To_UTF16(i_pMod->pName,
|
|
(tWCHAR*)l_pMod->pName,
|
|
P7TRACE_MODULE_NAME_LENGTH
|
|
);
|
|
#endif
|
|
l_pMod->szName = PStrLen(l_pMod->pName);
|
|
|
|
m_cModules.Put_Data(m_cModules.Get_ByIndex(i_pMod->wModuleID), l_pMod, TRUE);
|
|
}
|
|
}//PutModule
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//RegisterThread
|
|
void CTxtChannel::RegisterThread(const sP7Trace_Thread_Start *i_pStart)
|
|
{
|
|
sThread *l_pThread = new sThread();
|
|
l_pThread->dwThreadID = i_pStart->dwThreadID;
|
|
l_pThread->qwStart = i_pStart->qwTimer;
|
|
l_pThread->qwStop = MAXUINT64;
|
|
|
|
#ifdef UTF8_ENCODING
|
|
memcpy(l_pThread->pName, i_pStart->pName, P7TRACE_THREAD_NAME_LENGTH);
|
|
#else
|
|
Convert_UTF8_To_UTF16(i_pStart->pName,
|
|
(tWCHAR*)l_pThread->pName,
|
|
P7TRACE_THREAD_NAME_LENGTH
|
|
);
|
|
#endif
|
|
|
|
l_pThread->szName = PStrLen(l_pThread->pName);
|
|
|
|
sRbThread *l_pRbCurr = m_cThreads.Find(l_pThread->dwThreadID);
|
|
|
|
if (l_pRbCurr)
|
|
{
|
|
sRbThread *l_pRbPrev = NULL;
|
|
while (l_pRbCurr)
|
|
{
|
|
if (l_pThread->qwStart > l_pRbCurr->pThread->qwStart)
|
|
{
|
|
sRbThread *l_pRbNew = NULL;
|
|
if (l_pRbPrev)
|
|
{
|
|
l_pRbNew = new sRbThread(l_pThread, l_pRbCurr);
|
|
l_pRbPrev->pNext = l_pRbNew;
|
|
}
|
|
else //if it is first element in queue
|
|
{
|
|
l_pRbNew = new sRbThread(NULL, NULL);
|
|
//Move current (first) to new one
|
|
*l_pRbNew = *l_pRbCurr;
|
|
//Set current (first) with new data
|
|
l_pRbCurr->pThread = l_pThread;
|
|
l_pRbCurr->pNext = l_pRbNew;
|
|
//initialize pointer to new one
|
|
l_pRbNew = l_pRbCurr;
|
|
}
|
|
|
|
if ( (l_pRbNew->pNext)
|
|
&& (MAXUINT64 == l_pRbNew->pNext->pThread->qwStop)
|
|
)
|
|
{
|
|
l_pRbNew->pNext->pThread->qwStop = l_pRbNew->pThread->qwStart - 1ull;
|
|
}
|
|
|
|
break;
|
|
}
|
|
else if (l_pThread->qwStart == l_pRbCurr->pThread->qwStart)
|
|
{
|
|
//repeat !!!
|
|
//l_pRbCurr->pThread->qwStop = i_pThread->qwStop;
|
|
delete l_pThread;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
l_pRbPrev = l_pRbCurr;
|
|
l_pRbCurr = l_pRbCurr->pNext;
|
|
}
|
|
}
|
|
}
|
|
else //not found
|
|
{
|
|
m_cThreads.Push(new sRbThread(l_pThread, NULL), l_pThread->dwThreadID);
|
|
}
|
|
}//RegisterThread
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//UnregisterThread
|
|
void CTxtChannel::UnregisterThread(const sP7Trace_Thread_Stop *i_pStop)
|
|
{
|
|
sRbThread *l_pRbCurr = m_cThreads.Find(i_pStop->dwThreadID);
|
|
|
|
if ( (l_pRbCurr)
|
|
&& (l_pRbCurr->pThread)
|
|
)
|
|
{
|
|
l_pRbCurr->pThread->qwStop = i_pStop->qwTimer;
|
|
}
|
|
}//UnregisterThread
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//Format()
|
|
tBOOL CTxtChannel::Format(sP7Trace_Data *i_pData, CClTextSink::sLog &o_rLog)
|
|
{
|
|
tBOOL l_bReturn = TRUE;
|
|
sTraceDescEx *l_pDesc = NULL;
|
|
tUINT8 *l_pValues = ((tUINT8*)i_pData) + sizeof(sP7Trace_Data);
|
|
sRbThread *l_pRbThread = NULL;
|
|
int l_iCount = 0;
|
|
tUINT8 *l_pExt = (tUINT8*)i_pData + i_pData->sCommon.dwSize - 1;
|
|
tUINT8 l_bCount = l_pExt[0];
|
|
tDOUBLE l_dbTimeDiff= 0.0;
|
|
|
|
l_pDesc = m_cDesc[i_pData->wID];
|
|
|
|
if ( (NULL == l_pDesc)
|
|
|| (!m_pText)
|
|
)
|
|
{
|
|
l_bReturn = FALSE;
|
|
goto l_lblExit;
|
|
}
|
|
|
|
o_rLog.dwModuleID = 0u;
|
|
|
|
while (l_bCount--) //Parse extensions, there is no need to check the presence, it is always here because of using locally
|
|
{
|
|
--l_pExt;
|
|
if (EP7TRACE_EXT_MODULE_ID == l_pExt[0])
|
|
{
|
|
l_pExt -= 2;
|
|
o_rLog.dwModuleID = *(tUINT16*)l_pExt;
|
|
--l_pExt;
|
|
}
|
|
}
|
|
|
|
while (!l_iCount)
|
|
{
|
|
l_iCount = l_pDesc->pFormatter->Format(m_pText, m_szText, l_pValues);
|
|
|
|
if ( (l_iCount < 0)
|
|
|| ((size_t)(l_iCount + 1) >= m_szText)
|
|
)
|
|
{
|
|
free(m_pText);
|
|
m_szText *= 2;
|
|
m_pText = (tXCHAR*)malloc(m_szText * sizeof(tXCHAR));
|
|
l_iCount = 0;
|
|
if (!m_pText)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
o_rLog.pChannel = m_pName;
|
|
o_rLog.szChannel = m_szName;
|
|
o_rLog.szMessage = l_iCount;
|
|
|
|
//Get thread name if it is ...
|
|
o_rLog.pThreadName = TM("Unkn.");
|
|
o_rLog.szThreadName = 5;
|
|
|
|
l_pRbThread = m_cThreads.Find(i_pData->dwThreadID);
|
|
|
|
if (l_pRbThread)
|
|
{
|
|
while (l_pRbThread)
|
|
{
|
|
if ( (i_pData->qwTimer >= l_pRbThread->pThread->qwStart)
|
|
&& (i_pData->qwTimer <= l_pRbThread->pThread->qwStop)
|
|
)
|
|
{
|
|
o_rLog.pThreadName = l_pRbThread->pThread->pName;
|
|
o_rLog.szThreadName = l_pRbThread->pThread->szName;
|
|
break;
|
|
}
|
|
|
|
l_pRbThread = l_pRbThread->pNext;
|
|
}
|
|
}
|
|
|
|
if (m_cModules[o_rLog.dwModuleID])
|
|
{
|
|
o_rLog.pModuleName = m_cModules[o_rLog.dwModuleID]->pName;
|
|
o_rLog.szModuleName = m_cModules[o_rLog.dwModuleID]->szName;
|
|
}
|
|
else
|
|
{
|
|
o_rLog.pModuleName = TM("Unkn.");
|
|
o_rLog.szModuleName = 5;
|
|
}
|
|
|
|
l_dbTimeDiff = (((tDOUBLE)i_pData->qwTimer - (tDOUBLE)m_qwTimer_Value) * (tDOUBLE)TIME_SEC_100NS) / (tDOUBLE)m_qwTimer_Frequency;
|
|
|
|
UnpackLocalTime(m_qwStreamTime + (tUINT64)l_dbTimeDiff,
|
|
o_rLog.dwYear,
|
|
o_rLog.dwMonth,
|
|
o_rLog.dwDay,
|
|
o_rLog.dwHour,
|
|
o_rLog.dwMinutes,
|
|
o_rLog.dwSeconds,
|
|
o_rLog.dwMilliseconds,
|
|
o_rLog.dwMicroseconds,
|
|
o_rLog.dwNanoseconds
|
|
);
|
|
|
|
|
|
o_rLog.qwRawTime = m_qwStreamTime + (tUINT64)l_dbTimeDiff;
|
|
o_rLog.qwRawTimeOffset = (tUINT64)l_dbTimeDiff;
|
|
o_rLog.pChannel = m_pName;
|
|
o_rLog.qwIndex = i_pData->dwSequence;
|
|
o_rLog.dwId = i_pData->wID;
|
|
o_rLog.eLevel = (eP7Trace_Level)i_pData->bLevel;
|
|
o_rLog.dwCpuCore = i_pData->bProcessor;
|
|
o_rLog.dwThreadId = i_pData->dwThreadID;
|
|
o_rLog.pDesc = static_cast<sTraceDesc*>(l_pDesc);
|
|
o_rLog.pMessage = m_pText;
|
|
|
|
m_qwTimeLast = i_pData->qwTimer;
|
|
|
|
l_lblExit:
|
|
return l_bReturn;
|
|
}//Format()
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// CClText
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//CClText()
|
|
CClText::CClText(tXCHAR **i_pArgs, tINT32 i_iCount)
|
|
: CClient(IP7_Client::eText, i_pArgs, i_iCount)
|
|
, m_lReject_Mem(0)
|
|
, m_lReject_Con(0)
|
|
, m_lReject_Int(0)
|
|
, m_bThread(FALSE)
|
|
, m_hThread(0) //NULL
|
|
, m_bNoData(FALSE)
|
|
, m_pBuffer_Current(0)
|
|
, m_dwBuffer_Size(0)
|
|
, m_dwBuffers_Count(0)
|
|
, m_bBig_Endian(FALSE)
|
|
, m_pChunk(0)
|
|
, m_szChunkMax(0)
|
|
, m_szChunkUsd(0)
|
|
, m_pFormat(NULL)
|
|
, m_pMsg(NULL)
|
|
, m_pMsgCur(NULL)
|
|
, m_szMsg(0)
|
|
, m_pSink(NULL)
|
|
, m_bSinkExternal(FALSE)
|
|
{
|
|
memset(m_pTxtCh, 0, sizeof(m_pTxtCh));
|
|
|
|
//1. base init
|
|
if (ECLIENT_STATUS_OK == m_eStatus)
|
|
{
|
|
m_eStatus = Init_Base(i_pArgs, i_iCount);
|
|
}
|
|
|
|
//2. Initialize Pool
|
|
if (ECLIENT_STATUS_OK == m_eStatus)
|
|
{
|
|
m_eStatus = Init_Pool(i_pArgs, i_iCount);
|
|
}
|
|
|
|
//3. Initialize backend
|
|
if (ECLIENT_STATUS_OK == m_eStatus)
|
|
{
|
|
m_eStatus = Init_Backend(i_pArgs, i_iCount);
|
|
}
|
|
|
|
//4. Initialize variables
|
|
if (ECLIENT_STATUS_OK == m_eStatus)
|
|
{
|
|
m_eStatus = Init_Thread(i_pArgs, i_iCount);
|
|
}
|
|
|
|
//5. Initialize crash handler
|
|
if (ECLIENT_STATUS_OK == m_eStatus)
|
|
{
|
|
Init_Crash_Handler(i_pArgs, i_iCount);
|
|
}
|
|
}//CClText()
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//~CClText()
|
|
CClText::~CClText()
|
|
{
|
|
Uninit_Crash_Handler();
|
|
|
|
Close();
|
|
|
|
if (m_pSink)
|
|
{
|
|
if (!m_bSinkExternal)
|
|
{
|
|
delete m_pSink;
|
|
}
|
|
m_pSink = NULL;
|
|
}
|
|
|
|
if (m_pBuffer_Current)
|
|
{
|
|
delete m_pBuffer_Current;
|
|
m_pBuffer_Current = NULL;
|
|
}
|
|
|
|
if (m_pChunk)
|
|
{
|
|
free(m_pChunk);
|
|
m_pChunk = NULL;
|
|
}
|
|
|
|
m_szChunkMax = 0;
|
|
|
|
m_cBuffer_Empty.Clear(TRUE);
|
|
m_cBuffer_Ready.Clear(TRUE);
|
|
|
|
for (size_t l_szI = 0; l_szI < LENGTH(m_pChannels); l_szI++)
|
|
{
|
|
if (m_pTxtCh[l_szI])
|
|
{
|
|
delete m_pTxtCh[l_szI];
|
|
m_pTxtCh[l_szI] = NULL;
|
|
}
|
|
}
|
|
|
|
while (m_pFormat)
|
|
{
|
|
sFormat *l_pTmp = m_pFormat;
|
|
m_pFormat = m_pFormat->pNext;
|
|
|
|
if (l_pTmp->pStr)
|
|
{
|
|
free(l_pTmp->pStr);
|
|
l_pTmp->pStr = NULL;
|
|
}
|
|
|
|
free(l_pTmp);
|
|
}
|
|
|
|
CClient::Unshare();
|
|
|
|
|
|
if (m_pMsg)
|
|
{
|
|
free(m_pMsg);
|
|
m_pMsg = NULL;
|
|
}
|
|
|
|
m_pMsgCur = NULL;
|
|
|
|
//printf("Reject mem:%d, con:%d, init:%d\n", m_lReject_Mem, m_lReject_Con, m_lReject_Int);
|
|
}//~CClText()
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//Init_Base
|
|
eClient_Status CClText::Init_Base(tXCHAR **i_pArgs,
|
|
tINT32 i_iCount
|
|
)
|
|
{
|
|
eClient_Status l_eReturn = ECLIENT_STATUS_WRONG_FORMAT;
|
|
tXCHAR *l_pFormatStr = NULL;
|
|
tUINT32 l_dwEndian = 0x1;
|
|
tUINT8 l_bLittleE = *(tUINT8*)&l_dwEndian;
|
|
|
|
if (!l_bLittleE)
|
|
{
|
|
m_bBig_Endian = TRUE;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//getting pool size
|
|
l_pFormatStr = Get_Argument_Text_Value(i_pArgs, i_iCount,
|
|
(tXCHAR*)CLIENT_COMMAND_FORMAT);
|
|
if (l_pFormatStr)
|
|
{
|
|
l_eReturn = ParseFormat(l_pFormatStr);
|
|
}
|
|
|
|
if (ECLIENT_STATUS_OK != l_eReturn)
|
|
{
|
|
l_eReturn = ParseFormat(TM("%") CLIENT_FMT_CHANNEL TM(" ")
|
|
TM("#%") CLIENT_FMT_MSG_INDEX TM(" ")
|
|
TM("[%") CLIENT_FMT_TIME_FULL TM("] ")
|
|
TM("%") CLIENT_FMT_LEVEL TM(" ")
|
|
TM("Tr:#%") CLIENT_FMT_THREAD_ID TM(":")
|
|
TM("%") CLIENT_FMT_THREAD_NAME TM(" ")
|
|
TM("CPU:%") CLIENT_FMT_CPU_CORE TM(" ")
|
|
TM("Md:%") CLIENT_FMT_MODULE_NAME TM(" ")
|
|
TM("{%") CLIENT_FMT_FILE_SHORT TM(":")
|
|
TM("%") CLIENT_FMT_FILE_LINE TM(":")
|
|
TM("%") CLIENT_FMT_FUNCTION TM("} ")
|
|
TM("%") CLIENT_FMT_MSG
|
|
);
|
|
}
|
|
|
|
return l_eReturn;
|
|
}//Init_Base
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//Init_Pool
|
|
eClient_Status CClText::Init_Pool(tXCHAR **i_pArgs,
|
|
tINT32 i_iCount
|
|
)
|
|
{
|
|
eClient_Status l_eReturn = ECLIENT_STATUS_OK;
|
|
tXCHAR *l_pArg_Value = NULL;
|
|
tUINT32 l_dwPool_Size = DEF_POOL_SIZE;
|
|
tUINT32 l_dwBuffer_Size = MAX_BUFFER_SIZE * 2;
|
|
tUINT32 l_dwBuffers_Count = 0;
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//getting pool size
|
|
l_pArg_Value = Get_Argument_Text_Value(i_pArgs, i_iCount,
|
|
(tXCHAR*)CLIENT_COMMAND_POOL_SIZE);
|
|
if (l_pArg_Value)
|
|
{
|
|
l_dwPool_Size = 1024 * (tUINT32)PStrToInt(l_pArg_Value);
|
|
|
|
if (MIN_POOL_SIZE > l_dwPool_Size)
|
|
{
|
|
l_dwPool_Size = MIN_POOL_SIZE;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//calculate buffer size and buffers count
|
|
//Starting from largest buffer size trying to calculate how much buffers we
|
|
//can allocate, is amount is smaller than minimum - device buffer size by 2
|
|
//and repeat procedure
|
|
while (l_dwBuffers_Count < MIN_BUFFERS_COUNT)
|
|
{
|
|
l_dwBuffer_Size /= 2;
|
|
l_dwBuffers_Count = l_dwPool_Size / l_dwBuffer_Size;
|
|
}
|
|
|
|
if ( (MIN_BUFFER_SIZE > l_dwBuffer_Size)
|
|
|| (MIN_BUFFERS_COUNT > l_dwBuffers_Count)
|
|
)
|
|
{
|
|
P7_Set_Last_Error(eP7_Error_UserSettings);
|
|
|
|
JOURNAL_ERROR(m_pLog,
|
|
TM("Pool: Memory calculation error, buffer size = %d, buffers count = %d"),
|
|
l_dwBuffer_Size,
|
|
l_dwBuffers_Count
|
|
);
|
|
l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR;
|
|
goto l_lblExit;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//allocate buffers
|
|
m_dwBuffer_Size = l_dwBuffer_Size;
|
|
m_dwBuffers_Count = l_dwBuffers_Count;
|
|
|
|
for (tUINT32 l_dwI = 0; l_dwI < m_dwBuffers_Count; l_dwI++)
|
|
{
|
|
sBuffer *l_pBuffer = new sBuffer(m_dwBuffer_Size);
|
|
if (l_pBuffer)
|
|
{
|
|
m_cBuffer_Empty.Add_After(NULL, l_pBuffer);
|
|
}
|
|
else
|
|
{
|
|
P7_Set_Last_Error(eP7_Error_MemoryAllocation);
|
|
JOURNAL_ERROR(m_pLog, TM("Pool: Memory allocation failed"));
|
|
l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR;
|
|
goto l_lblExit;
|
|
}
|
|
}
|
|
|
|
m_szChunkMax = 4096;
|
|
m_pChunk = (tUINT8*)malloc(m_szChunkMax);
|
|
if (NULL == m_pChunk)
|
|
{
|
|
P7_Set_Last_Error(eP7_Error_MemoryAllocation);
|
|
JOURNAL_ERROR(m_pLog, TM("Pool: Memory fragment allocation failed"));
|
|
l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR;
|
|
goto l_lblExit;
|
|
}
|
|
|
|
|
|
m_szMsg = 4096;
|
|
m_pMsg = (tXCHAR*)malloc(m_szMsg * sizeof(tXCHAR));
|
|
m_pMsgCur = m_pMsg;
|
|
|
|
if (NULL == m_pMsg)
|
|
{
|
|
P7_Set_Last_Error(eP7_Error_MemoryAllocation);
|
|
JOURNAL_ERROR(m_pLog, TM("Pool: Memory message allocation failed"));
|
|
l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR;
|
|
goto l_lblExit;
|
|
}
|
|
|
|
l_lblExit:
|
|
return l_eReturn;
|
|
}//Init_Pool
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//Init_File
|
|
eClient_Status CClText::Init_Backend(tXCHAR **i_pArgs, tINT32 i_iCount)
|
|
{
|
|
eClient_Status l_eReturn = ECLIENT_STATUS_OK;
|
|
tXCHAR *l_pSink = NULL;
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//getting pool size
|
|
l_pSink = Get_Argument_Text_Value(i_pArgs, i_iCount,
|
|
(tXCHAR*)CLIENT_COMMAND_LINE_SINK);
|
|
if (l_pSink)
|
|
{
|
|
if (0 == PStrICmp(l_pSink, CLIENT_SINK_CONSOLE))
|
|
{
|
|
m_pSink = static_cast<CClTextSink *>(new CClTextConsole());
|
|
}
|
|
else if (0 == PStrICmp(l_pSink, CLIENT_SINK_FILE_TXT))
|
|
{
|
|
m_pSink = static_cast<CClTextSink *>(new CClTextFile());
|
|
}
|
|
else if (0 == PStrICmp(l_pSink, CLIENT_SINK_SYSLOG))
|
|
{
|
|
m_pSink = static_cast<CClTextSink *>(new CClTextSyslog());
|
|
}
|
|
//WARNING: this code is dedicated only for self-testing.
|
|
// USE THIS OPTION ONLY ON YOUR OWN RISK!
|
|
else if (0 == PStrICmp(l_pSink, TM("ExternalSinc")))
|
|
{
|
|
l_pSink = Get_Argument_Text_Value(i_pArgs, i_iCount, (tXCHAR*)TM("/P7.ExtAddr="));
|
|
|
|
if (l_pSink)
|
|
{
|
|
tUINT64 l_qwAddr = 0;
|
|
PStrScan(l_pSink, TM("%llX"), &l_qwAddr);
|
|
void *l_pAddr = (void*)l_qwAddr;
|
|
m_pSink = static_cast<CClTextSink *>(l_pAddr);
|
|
m_bSinkExternal = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!m_pSink)
|
|
{
|
|
m_pSink = static_cast<CClTextSink *>(new CClTextConsole());
|
|
}
|
|
|
|
if (m_pSink)
|
|
{
|
|
l_eReturn = m_pSink->Initialize(i_pArgs, i_iCount);
|
|
}
|
|
|
|
return l_eReturn;
|
|
}//Init_File
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//Init_Thread
|
|
eClient_Status CClText::Init_Thread(tXCHAR **i_pArgs,
|
|
tINT32 i_iCount
|
|
)
|
|
{
|
|
eClient_Status l_eReturn = ECLIENT_STATUS_OK;
|
|
|
|
UNUSED_ARG(i_pArgs);
|
|
UNUSED_ARG(i_iCount);
|
|
|
|
if (ECLIENT_STATUS_OK == l_eReturn)
|
|
{
|
|
if (FALSE == m_cEvThread.Init(eThreadEventsCount, EMEVENT_SINGLE_AUTO, EMEVENT_MULTI, EMEVENT_SINGLE_AUTO))
|
|
{
|
|
P7_Set_Last_Error(eP7_Error_OS);
|
|
l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR;
|
|
JOURNAL_ERROR(m_pLog, TM("Exit event wasn't created !"));
|
|
}
|
|
|
|
if (FALSE == m_cEvData.Init(1, EMEVENT_SINGLE_AUTO))
|
|
{
|
|
P7_Set_Last_Error(eP7_Error_OS);
|
|
l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR;
|
|
JOURNAL_ERROR(m_pLog, TM("Exit event wasn't created !"));
|
|
}
|
|
}
|
|
|
|
if (ECLIENT_STATUS_OK == l_eReturn)
|
|
{
|
|
if (FALSE == CThShell::Create(&Static_Routine,
|
|
this,
|
|
&m_hThread,
|
|
TM("P7:Comm")
|
|
)
|
|
)
|
|
{
|
|
P7_Set_Last_Error(eP7_Error_OS);
|
|
l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR;
|
|
JOURNAL_ERROR(m_pLog, TM("Communication thread wasn't created !"));
|
|
}
|
|
else
|
|
{
|
|
m_bThread = TRUE;
|
|
}
|
|
}
|
|
|
|
return l_eReturn;
|
|
}//Init_Thread
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//ParseFormat
|
|
eClient_Status CClText::ParseFormat(const tXCHAR *i_pFormat)
|
|
{
|
|
eClient_Status l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR;
|
|
const tXCHAR *l_pCursor = NULL;
|
|
|
|
l_pCursor = i_pFormat;
|
|
|
|
while (*l_pCursor)
|
|
{
|
|
if (TM('%') == *l_pCursor)
|
|
{
|
|
fnFormat l_pFn = GetFormatFunction(l_pCursor + 1);
|
|
if (l_pFn)
|
|
{
|
|
if (AddFormatNode(i_pFormat, l_pCursor - i_pFormat, l_pFn))
|
|
{
|
|
l_eReturn = ECLIENT_STATUS_OK;
|
|
l_pCursor += 2;
|
|
i_pFormat = l_pCursor+ 1;
|
|
}
|
|
else
|
|
{
|
|
l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
l_pCursor ++;
|
|
}
|
|
|
|
if ( (ECLIENT_STATUS_OK == l_eReturn)
|
|
&& (*i_pFormat)
|
|
)
|
|
{
|
|
if (!AddFormatNode(i_pFormat, l_pCursor - i_pFormat, NULL))
|
|
{
|
|
l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR;
|
|
}
|
|
}
|
|
|
|
if (ECLIENT_STATUS_OK == l_eReturn)
|
|
{
|
|
if (!m_pFormat)
|
|
{
|
|
l_eReturn = ECLIENT_STATUS_WRONG_FORMAT;
|
|
}
|
|
else
|
|
{
|
|
sFormat *l_pFormat = m_pFormat;
|
|
l_eReturn = ECLIENT_STATUS_WRONG_FORMAT;
|
|
while (l_pFormat)
|
|
{
|
|
if (l_pFormat->pFormat)
|
|
{
|
|
l_eReturn = ECLIENT_STATUS_OK;
|
|
break;
|
|
}
|
|
|
|
l_pFormat = l_pFormat->pNext;
|
|
}
|
|
}
|
|
}
|
|
|
|
return l_eReturn;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//AddFormatNode
|
|
CClText::sFormat *CClText::AddFormatNode(const tXCHAR *i_pPrefix, size_t i_szPrefix, fnFormat i_pFn)
|
|
{
|
|
sFormat *l_pReturn = (sFormat*)malloc(sizeof(sFormat));
|
|
|
|
if (!l_pReturn)
|
|
{
|
|
return l_pReturn;
|
|
}
|
|
|
|
memset(l_pReturn, 0, sizeof(sFormat));
|
|
|
|
if (!m_pFormat)
|
|
{
|
|
m_pFormat = l_pReturn;
|
|
}
|
|
else
|
|
{
|
|
sFormat *l_pNext = m_pFormat;
|
|
while (l_pNext->pNext) { l_pNext = l_pNext->pNext; }
|
|
l_pNext->pNext = l_pReturn;
|
|
}
|
|
|
|
if (i_szPrefix)
|
|
{
|
|
l_pReturn->pStr = (tXCHAR*)malloc((i_szPrefix + 1) * sizeof(tXCHAR));
|
|
if (l_pReturn->pStr)
|
|
{
|
|
memcpy(l_pReturn->pStr, i_pPrefix, i_szPrefix * sizeof(tXCHAR));
|
|
l_pReturn->pStr[i_szPrefix] = 0;
|
|
l_pReturn->szStr = i_szPrefix;
|
|
}
|
|
}
|
|
|
|
l_pReturn->pFormat = i_pFn;
|
|
return l_pReturn;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//Sent
|
|
eClient_Status CClText::Sent(tUINT32 i_dwChannel_ID,
|
|
sP7C_Data_Chunk *i_pChunks,
|
|
tUINT32 i_dwCount,
|
|
tUINT32 i_dwSize
|
|
)
|
|
{
|
|
eClient_Status l_eReturn = ECLIENT_STATUS_OK;
|
|
sH_User_Data l_sHeader = {i_dwSize + (tUINT32)sizeof(l_sHeader), i_dwChannel_ID};
|
|
sP7C_Data_Chunk l_sHeader_Chunk = {&l_sHeader, (tUINT32)sizeof(l_sHeader)};
|
|
//Warn: variables without default values!
|
|
tBOOL l_bExit;
|
|
sP7C_Data_Chunk *l_pChunk;
|
|
tUINT32 l_dwChunk_Offs;
|
|
pAList_Cell l_pEl;
|
|
tUINT32 l_dwFree_Size;
|
|
|
|
if (ECLIENT_STATUS_OK != m_eStatus)
|
|
{
|
|
ATOMIC_INC(&m_lReject_Int);
|
|
return m_eStatus;
|
|
}
|
|
|
|
if ( (NULL == i_pChunks)
|
|
|| (0 >= i_dwCount)
|
|
|| (USER_PACKET_MAX_SIZE <= l_sHeader.dwSize)
|
|
|| (USER_PACKET_CHANNEL_ID_MAX_SIZE <= i_dwChannel_ID)
|
|
)
|
|
{
|
|
ATOMIC_INC(&m_lReject_Int);
|
|
return ECLIENT_STATUS_WRONG_PARAMETERS;
|
|
}
|
|
|
|
//N.B. We do not check i_dwSize and real size of all chunks in release mode!!!
|
|
#ifdef _DEBUG
|
|
tUINT32 l_dwReal_Size = 0;
|
|
for (tUINT32 l_dwI = 0; l_dwI < i_dwCount; l_dwI ++)
|
|
{
|
|
if (i_pChunks[l_dwI].pData)
|
|
{
|
|
l_dwReal_Size += i_pChunks[l_dwI].dwSize;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (l_dwReal_Size != i_dwSize)
|
|
{
|
|
ATOMIC_INC(&m_lReject_Int);
|
|
return ECLIENT_STATUS_WRONG_PARAMETERS;
|
|
}
|
|
#endif
|
|
|
|
LOCK_ENTER(m_hCS);
|
|
|
|
if (FALSE == m_bConnected)
|
|
{
|
|
l_eReturn = ECLIENT_STATUS_OFF;
|
|
ATOMIC_INC(&m_lReject_Con);
|
|
goto l_lExit;
|
|
}
|
|
|
|
if (l_sHeader.dwSize >= (m_dwBuffer_Size * m_dwBuffers_Count))
|
|
{
|
|
l_eReturn = ECLIENT_STATUS_NO_FREE_BUFFERS;
|
|
ATOMIC_INC(&m_lReject_Mem);
|
|
goto l_lExit;
|
|
}
|
|
|
|
do
|
|
{
|
|
l_dwFree_Size = (m_cBuffer_Empty.Count() * m_dwBuffer_Size)
|
|
+ ((m_pBuffer_Current) ? (m_dwBuffer_Size - (tUINT32)m_pBuffer_Current->szUsed) : 0);
|
|
|
|
//if size is more than available ...
|
|
if (l_dwFree_Size < l_sHeader.dwSize)
|
|
{
|
|
m_bNoData = TRUE;
|
|
|
|
LOCK_EXIT(m_hCS);
|
|
m_cEvData.Wait(FREE_DATA_WAIT_TIMEOUT);
|
|
LOCK_ENTER(m_hCS);
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
} while (1);
|
|
|
|
//because we add header as chunk
|
|
i_dwCount ++;
|
|
|
|
l_bExit = FALSE;
|
|
l_pChunk = &l_sHeader_Chunk; //&i_pChunks[0];
|
|
l_dwChunk_Offs = 0;
|
|
|
|
while (FALSE == l_bExit)
|
|
{
|
|
//if packet is null we need to extract another one
|
|
if (NULL == m_pBuffer_Current)
|
|
{
|
|
l_pEl = m_cBuffer_Empty.Get_First();
|
|
m_pBuffer_Current = m_cBuffer_Empty.Get_Data(l_pEl);
|
|
m_cBuffer_Empty.Del(l_pEl, FALSE);
|
|
}
|
|
|
|
while ( (m_pBuffer_Current)
|
|
&& (i_dwCount)
|
|
)
|
|
{
|
|
//if packet free size is larger or equal to chunk size
|
|
if ( TAIL_SIZE(m_pBuffer_Current) >= l_pChunk->dwSize )
|
|
{
|
|
memcpy(m_pBuffer_Current->pBuffer + m_pBuffer_Current->szUsed,
|
|
((tUINT8*)l_pChunk->pData) + l_dwChunk_Offs,
|
|
l_pChunk->dwSize
|
|
);
|
|
|
|
m_pBuffer_Current->szUsed += l_pChunk->dwSize;
|
|
|
|
//current chunk was moved, we reduce chunks amount
|
|
--i_dwCount;
|
|
|
|
if (0 >= i_dwCount)
|
|
{
|
|
l_bExit = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//we are finish with that chunk
|
|
//l_pChunk->dwSize = 0;
|
|
l_dwChunk_Offs = 0;
|
|
|
|
if (l_pChunk == &l_sHeader_Chunk)
|
|
{
|
|
l_pChunk = &i_pChunks[0];
|
|
}
|
|
else
|
|
{
|
|
//go to next chunk
|
|
l_pChunk ++;
|
|
}
|
|
|
|
//if packet is filled - put it to data queue
|
|
if (0 >= TAIL_SIZE(m_pBuffer_Current))
|
|
{
|
|
m_cBuffer_Ready.Add_After(m_cBuffer_Ready.Get_Last(),
|
|
m_pBuffer_Current
|
|
);
|
|
m_pBuffer_Current = NULL;
|
|
m_cEvThread.Set(eThreadEventHasData);
|
|
}
|
|
}
|
|
}
|
|
else //if chunk data is greater than packet free space
|
|
{
|
|
memcpy(m_pBuffer_Current->pBuffer + m_pBuffer_Current->szUsed,
|
|
((tUINT8*)l_pChunk->pData) + l_dwChunk_Offs,
|
|
TAIL_SIZE(m_pBuffer_Current)
|
|
);
|
|
l_dwChunk_Offs += TAIL_SIZE(m_pBuffer_Current);
|
|
l_pChunk->dwSize -= TAIL_SIZE(m_pBuffer_Current);
|
|
|
|
m_pBuffer_Current->szUsed += TAIL_SIZE(m_pBuffer_Current);
|
|
|
|
m_cBuffer_Ready.Add_After(m_cBuffer_Ready.Get_Last(),
|
|
m_pBuffer_Current
|
|
);
|
|
m_pBuffer_Current = NULL;
|
|
m_cEvThread.Set(eThreadEventHasData);
|
|
}
|
|
} //while ( (m_pBuffer_Current) && (i_dwCount) )
|
|
} //while (FALSE == l_bExit)
|
|
|
|
l_lExit:
|
|
|
|
LOCK_EXIT(m_hCS);
|
|
|
|
return l_eReturn;
|
|
}//Sent
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//Get_Info
|
|
tBOOL CClText::Get_Info(sP7C_Info *o_pInfo)
|
|
{
|
|
if (NULL == o_pInfo)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
LOCK_ENTER(m_hCS);
|
|
|
|
o_pInfo->dwMem_Alloc = m_dwBuffer_Size * m_dwBuffers_Count;
|
|
o_pInfo->dwMem_Free = m_cBuffer_Empty.Count() * m_dwBuffer_Size;
|
|
o_pInfo->dwMem_Used = m_cBuffer_Ready.Count() * m_dwBuffer_Size;
|
|
|
|
o_pInfo->dwReject_Mem = m_lReject_Mem;
|
|
o_pInfo->dwReject_Con = m_lReject_Con;
|
|
o_pInfo->dwReject_Int = m_lReject_Int;
|
|
LOCK_EXIT(m_hCS);
|
|
|
|
return TRUE;
|
|
}//Get_Info
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//Flush
|
|
tBOOL CClText::Close()
|
|
{
|
|
tBOOL l_bStack_Trace = TRUE;
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//notify channels about closing
|
|
sP7C_Status l_sStatus = {FALSE, 0};
|
|
l_sStatus.bConnected = FALSE;
|
|
l_sStatus.dwResets = 0;
|
|
|
|
if (m_bFlushChannels)
|
|
{
|
|
LOCK_ENTER(m_hCS_Reg);
|
|
for (tUINT32 l_dwI = 0; l_dwI < USER_PACKET_CHANNEL_ID_MAX_SIZE; l_dwI++)
|
|
{
|
|
if (m_pChannels[l_dwI])
|
|
{
|
|
m_pChannels[l_dwI]->On_Flush(l_dwI, &l_bStack_Trace);
|
|
m_pChannels[l_dwI]->On_Status(l_dwI, &l_sStatus);
|
|
}
|
|
}
|
|
LOCK_EXIT(m_hCS_Reg);
|
|
}
|
|
|
|
m_cEvThread.Set(eThreadEventExit);
|
|
|
|
if (m_bThread)
|
|
{
|
|
if (TRUE == CThShell::Close(m_hThread, 60000))
|
|
{
|
|
m_hThread = 0;//NULL;
|
|
m_bThread = FALSE;
|
|
}
|
|
else
|
|
{
|
|
JOURNAL_CRITICAL(m_pLog, TM("Can't close file thread !"));
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//Lock
|
|
LOCK_ENTER(m_hCS);
|
|
|
|
pAList_Cell l_pEl = NULL;
|
|
while ((l_pEl = m_cBuffer_Ready.Get_Next(l_pEl)))
|
|
{
|
|
sBuffer *l_pBuffer = m_cBuffer_Ready.Get_Data(l_pEl);
|
|
if (l_pBuffer)
|
|
{
|
|
Parse_Buffer(l_pBuffer->pBuffer, l_pBuffer->szUsed);
|
|
}
|
|
}
|
|
|
|
if (m_pBuffer_Current)
|
|
{
|
|
Parse_Buffer(m_pBuffer_Current->pBuffer, m_pBuffer_Current->szUsed);
|
|
}
|
|
|
|
m_bConnected = FALSE;
|
|
|
|
if (m_pSink)
|
|
{
|
|
if (!m_bSinkExternal)
|
|
{
|
|
delete m_pSink;
|
|
}
|
|
m_pSink = NULL;
|
|
}
|
|
|
|
LOCK_EXIT(m_hCS);
|
|
//unlock
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
return TRUE;
|
|
}//Flush
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//Flush
|
|
void CClText::Flush()
|
|
{
|
|
m_cEvThread.Set(eThreadEventDataFlush);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//Parse_Buffer
|
|
eClient_Status CClText::Parse_Buffer(tUINT8 *i_pBuffer, size_t i_szBuffer)
|
|
{
|
|
eClient_Status l_eReturn = ECLIENT_STATUS_OK;
|
|
size_t l_szOffset = 0;
|
|
size_t l_szTail = 0;
|
|
while (l_szOffset < i_szBuffer)
|
|
{
|
|
l_szTail = i_szBuffer - l_szOffset;
|
|
|
|
if (m_szChunkUsd)
|
|
{
|
|
//if header has been copied
|
|
if (sizeof(sH_User_Data) <= m_szChunkUsd)
|
|
{
|
|
if (((sH_User_Data*)m_pChunk)->dwSize > m_szChunkMax)
|
|
{
|
|
size_t l_szChunkMax = (((sH_User_Data*)m_pChunk)->dwSize + 1023) & (~1023);
|
|
tUINT8 *l_pChunk = (tUINT8*)realloc(m_pChunk, l_szChunkMax);
|
|
|
|
if (!l_pChunk)
|
|
{
|
|
l_pChunk = (tUINT8*)malloc(l_szChunkMax);
|
|
|
|
if ( (l_pChunk)
|
|
&& (m_pChunk)
|
|
)
|
|
{
|
|
memcpy(l_pChunk, m_pChunk, m_szChunkMax);
|
|
}
|
|
|
|
if (m_pChunk) { free(m_pChunk); }
|
|
}
|
|
|
|
m_pChunk = l_pChunk;
|
|
|
|
if (m_pChunk)
|
|
{
|
|
m_szChunkMax = l_szChunkMax;
|
|
}
|
|
else
|
|
{
|
|
m_szChunkMax = 0;
|
|
}
|
|
}
|
|
|
|
if (m_pChunk)
|
|
{
|
|
size_t l_szPacketTail = ((sH_User_Data*)m_pChunk)->dwSize - m_szChunkUsd;
|
|
|
|
if (l_szPacketTail > l_szTail)
|
|
{
|
|
l_szPacketTail = l_szTail;
|
|
}
|
|
|
|
memcpy(m_pChunk + m_szChunkUsd, i_pBuffer + l_szOffset, l_szPacketTail);
|
|
m_szChunkUsd += l_szPacketTail;
|
|
l_szOffset += l_szPacketTail;
|
|
|
|
if (m_szChunkUsd == ((sH_User_Data*)m_pChunk)->dwSize)
|
|
{
|
|
l_eReturn = Parse_Packet(((sH_User_Data*)m_pChunk)->dwChannel_ID,
|
|
m_pChunk + sizeof(sH_User_Data),
|
|
((sH_User_Data*)m_pChunk)->dwSize - sizeof(sH_User_Data));
|
|
m_szChunkUsd = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR;
|
|
}
|
|
}
|
|
else //copy header reminder
|
|
{
|
|
size_t l_szHeaderTail = sizeof(sH_User_Data) - m_szChunkUsd;
|
|
if (l_szHeaderTail > l_szTail)
|
|
{
|
|
l_szHeaderTail = l_szTail;
|
|
}
|
|
|
|
memcpy(m_pChunk + m_szChunkUsd, i_pBuffer + l_szOffset, l_szHeaderTail);
|
|
|
|
m_szChunkUsd += l_szHeaderTail;
|
|
l_szOffset += l_szHeaderTail;
|
|
}
|
|
} //if buffer contains enough data for analysis
|
|
else if ( (sizeof(sH_User_Data) < l_szTail)
|
|
&& (((sH_User_Data*)(i_pBuffer + l_szOffset))->dwSize <= l_szTail)
|
|
)
|
|
{
|
|
l_eReturn = Parse_Packet(((sH_User_Data*)(i_pBuffer + l_szOffset))->dwChannel_ID,
|
|
i_pBuffer + l_szOffset + sizeof(sH_User_Data),
|
|
((sH_User_Data*)(i_pBuffer + l_szOffset))->dwSize - sizeof(sH_User_Data)
|
|
);
|
|
l_szOffset += ((sH_User_Data*)(i_pBuffer + l_szOffset))->dwSize;
|
|
}
|
|
else //if size of the remaining data is smaller that size of user data
|
|
{
|
|
if (l_szTail > m_szChunkMax)
|
|
{
|
|
size_t l_szChunkMax = (l_szTail + 1023) & (~1023);
|
|
tUINT8 *l_pChunk = (tUINT8*)realloc(m_pChunk, l_szChunkMax);
|
|
|
|
if (!l_pChunk)
|
|
{
|
|
l_pChunk = (tUINT8*)malloc(l_szChunkMax);
|
|
|
|
if ( (l_pChunk)
|
|
&& (m_pChunk)
|
|
)
|
|
{
|
|
memcpy(l_pChunk, m_pChunk, m_szChunkMax);
|
|
}
|
|
|
|
if (m_pChunk) { free(m_pChunk); }
|
|
}
|
|
|
|
m_pChunk = l_pChunk;
|
|
|
|
if (m_pChunk)
|
|
{
|
|
m_szChunkMax = l_szChunkMax;
|
|
}
|
|
else
|
|
{
|
|
m_szChunkMax = 0;
|
|
}
|
|
}
|
|
|
|
if (m_pChunk)
|
|
{
|
|
memcpy(m_pChunk, i_pBuffer + l_szOffset, l_szTail);
|
|
m_szChunkUsd = l_szTail;
|
|
l_szOffset += l_szTail;
|
|
}
|
|
else
|
|
{
|
|
l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR;
|
|
}
|
|
}
|
|
|
|
if (ECLIENT_STATUS_OK != l_eReturn)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return l_eReturn;
|
|
}//Parse_Buffer
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//Parse_Packet
|
|
eClient_Status CClText::Parse_Packet(tUINT32 i_dwChannel,
|
|
tUINT8 *i_pPacket,
|
|
size_t i_szPacket
|
|
)
|
|
{
|
|
eClient_Status l_eReturn = ECLIENT_STATUS_OK;
|
|
size_t l_szOffset = 0;
|
|
sP7Ext_Header *l_pHeader = (sP7Ext_Header *)i_pPacket;
|
|
CTxtChannel *&l_pChannel = m_pTxtCh[i_dwChannel];
|
|
sP7Ext_Raw l_sRaw; //not initialized on purpose
|
|
|
|
while (l_szOffset < i_szPacket)
|
|
{
|
|
l_pHeader = (sP7Ext_Header *)(i_pPacket + l_szOffset);
|
|
|
|
//N.B.: Bits reconstruction, sP7Ext_Header is formed manually to avoid complier influence to bit fields (Using structures with
|
|
// bit fields isn't regulated by standard, every compiler is free to use own bits ordering). Headers formed in Trace or
|
|
// Telemetry may be used on different systems and they have to be unified
|
|
l_sRaw.dwBits = ((sP7Ext_Raw*)l_pHeader)->dwBits;
|
|
l_pHeader->dwType = GET_EXT_HEADER_TYPE(l_sRaw);
|
|
l_pHeader->dwSubType = GET_EXT_HEADER_SUBTYPE(l_sRaw);
|
|
l_pHeader->dwSize = GET_EXT_HEADER_SIZE(l_sRaw);
|
|
|
|
l_szOffset += l_pHeader->dwSize;
|
|
|
|
if (EP7USER_TYPE_TRACE != l_pHeader->dwType)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (l_pChannel)
|
|
{
|
|
if (EP7TRACE_TYPE_DATA == l_pHeader->dwSubType)
|
|
{
|
|
if (l_pChannel->Format((sP7Trace_Data*)l_pHeader, m_sLog))
|
|
{
|
|
sFormat *l_pCursor = m_pFormat;
|
|
m_pMsgCur = m_pMsg;
|
|
|
|
while (l_pCursor)
|
|
{
|
|
if (l_pCursor->pStr)
|
|
{
|
|
REALLOC_MESSAGE(l_pCursor->szStr, this);
|
|
memcpy(m_pMsgCur, l_pCursor->pStr, l_pCursor->szStr * sizeof(tXCHAR));
|
|
m_pMsgCur += l_pCursor->szStr;
|
|
}
|
|
|
|
if (l_pCursor->pFormat)
|
|
{
|
|
l_pCursor->pFormat(this);
|
|
}
|
|
|
|
l_pCursor = l_pCursor->pNext;
|
|
}
|
|
*m_pMsgCur = 0;
|
|
|
|
m_pSink->Log(m_sLog, m_pMsg, m_pMsgCur - m_pMsg);
|
|
}
|
|
}
|
|
else if (EP7TRACE_TYPE_DESC == l_pHeader->dwSubType)
|
|
{
|
|
l_pChannel->PutFormat((const sP7Trace_Format*)l_pHeader);
|
|
}
|
|
else if (EP7TRACE_TYPE_VERB == l_pHeader->dwSubType)
|
|
{
|
|
}
|
|
else if (EP7TRACE_TYPE_CLOSE == l_pHeader->dwSubType)
|
|
{
|
|
delete l_pChannel;
|
|
l_pChannel = NULL;
|
|
}
|
|
else if (EP7TRACE_TYPE_THREAD_START == l_pHeader->dwSubType)
|
|
{
|
|
l_pChannel->RegisterThread((const sP7Trace_Thread_Start*)l_pHeader);
|
|
}
|
|
else if (EP7TRACE_TYPE_THREAD_STOP == l_pHeader->dwSubType)
|
|
{
|
|
l_pChannel->UnregisterThread((const sP7Trace_Thread_Stop*)l_pHeader);
|
|
}
|
|
else if (EP7TRACE_TYPE_MODULE == l_pHeader->dwSubType)
|
|
{
|
|
l_pChannel->PutModule((const sP7Trace_Module*)l_pHeader);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (EP7TRACE_TYPE_INFO == l_pHeader->dwSubType)
|
|
{
|
|
if (l_pChannel)
|
|
{
|
|
delete l_pChannel;
|
|
}
|
|
|
|
l_pChannel = new CTxtChannel((const sP7Trace_Info*)l_pHeader, m_bBig_Endian);
|
|
}
|
|
else
|
|
{
|
|
l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (l_szOffset > i_szPacket)
|
|
{
|
|
l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR;
|
|
}
|
|
|
|
return l_eReturn;
|
|
}//Parse_Packet
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//Routine
|
|
void CClText::Routine()
|
|
{
|
|
pAList_Cell l_pEl = NULL;
|
|
tBOOL l_bExit = FALSE;
|
|
tUINT32 l_dwSignal = MEVENT_TIME_OUT;
|
|
tUINT32 l_dwRollTime = GetTickCount();
|
|
tUINT32 l_dwDumpTime = GetTickCount();
|
|
sBuffer *l_pBuffer = NULL;
|
|
eClient_Status l_eStatus = ECLIENT_STATUS_OK;
|
|
|
|
while ( (FALSE == l_bExit)
|
|
&& (ECLIENT_STATUS_OK == l_eStatus)
|
|
)
|
|
{
|
|
l_dwSignal = m_cEvThread.Wait(THREAD_IDLE_TIMEOUT);
|
|
|
|
if ( (eThreadEventHasData == l_dwSignal) //one buffer to write!
|
|
|| (MEVENT_TIME_OUT == l_dwSignal)
|
|
)
|
|
{
|
|
l_dwDumpTime = GetTickCount();
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
//extract buffer
|
|
LOCK_ENTER(m_hCS);
|
|
l_pEl = m_cBuffer_Ready.Get_First();
|
|
if (l_pEl)
|
|
{
|
|
l_pBuffer = m_cBuffer_Ready.Get_Data(l_pEl);
|
|
m_cBuffer_Ready.Del(l_pEl, FALSE);
|
|
}
|
|
else
|
|
{
|
|
l_pBuffer = m_pBuffer_Current;
|
|
m_pBuffer_Current = NULL;
|
|
}
|
|
LOCK_EXIT(m_hCS);
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
//format data & put data to free queue back
|
|
if (l_pBuffer)
|
|
{
|
|
l_eStatus = Parse_Buffer(l_pBuffer->pBuffer, l_pBuffer->szUsed);
|
|
|
|
LOCK_ENTER(m_hCS);
|
|
l_pBuffer->szUsed = 0;
|
|
m_cBuffer_Empty.Add_After(NULL, l_pBuffer);
|
|
if (m_bNoData)
|
|
{
|
|
m_cEvData.Set(DATA_FREE_SIGNAL);
|
|
m_bNoData = FALSE;
|
|
}
|
|
LOCK_EXIT(m_hCS);
|
|
}
|
|
}
|
|
else if (eThreadEventExit == l_dwSignal)
|
|
{
|
|
l_bExit = TRUE;
|
|
}
|
|
else if (eThreadEventDataFlush == l_dwSignal)
|
|
{
|
|
LOCK_ENTER(m_hCS);
|
|
if ( (m_pBuffer_Current)
|
|
&& (m_pBuffer_Current->szUsed)
|
|
)
|
|
{
|
|
m_cBuffer_Ready.Add_After(m_cBuffer_Ready.Get_Last(), m_pBuffer_Current);
|
|
m_pBuffer_Current = NULL;
|
|
m_cEvThread.Set(eThreadEventHasData);
|
|
}
|
|
LOCK_EXIT(m_hCS);
|
|
}
|
|
|
|
|
|
if (m_pSink)
|
|
{
|
|
if (CTicks::Difference(GetTickCount(), l_dwRollTime) > 60000) //1 minute
|
|
{
|
|
m_pSink->TryRoll();
|
|
l_dwRollTime = GetTickCount();
|
|
}
|
|
|
|
if (CTicks::Difference(GetTickCount(), l_dwDumpTime) > 1000) //1 second
|
|
{
|
|
m_pSink->DumpBuffers();
|
|
l_dwDumpTime = GetTickCount();
|
|
}
|
|
}
|
|
}
|
|
}//Comm_Routine
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//FormatChannel
|
|
void CClText::FormatChannel(CClText *i_pClient)
|
|
{
|
|
REALLOC_MESSAGE(i_pClient->m_sLog.szChannel + 16, i_pClient);
|
|
memcpy(i_pClient->m_pMsgCur, i_pClient->m_sLog.pChannel, i_pClient->m_sLog.szChannel * sizeof(tXCHAR));
|
|
i_pClient->m_pMsgCur += i_pClient->m_sLog.szChannel;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//FormatMessageId
|
|
void CClText::FormatMessageId(CClText *i_pClient)
|
|
{
|
|
REALLOC_MESSAGE(64, i_pClient);
|
|
|
|
tINT32 l_iRes = PSPrint(i_pClient->m_pMsgCur,
|
|
i_pClient->m_szMsg - (i_pClient->m_pMsgCur - i_pClient->m_pMsg),
|
|
TM("%04d"),
|
|
i_pClient->m_sLog.dwId
|
|
);
|
|
if (0 < l_iRes)
|
|
{
|
|
i_pClient->m_pMsgCur += l_iRes;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//FormatMessageIndex
|
|
void CClText::FormatMessageIndex(CClText *i_pClient)
|
|
{
|
|
REALLOC_MESSAGE(64, i_pClient);
|
|
|
|
tINT32 l_iRes = PSPrint(i_pClient->m_pMsgCur,
|
|
i_pClient->m_szMsg - (i_pClient->m_pMsgCur - i_pClient->m_pMsg),
|
|
TM("%04lld"),
|
|
i_pClient->m_sLog.qwIndex
|
|
);
|
|
if (0 < l_iRes)
|
|
{
|
|
i_pClient->m_pMsgCur += l_iRes;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//FormatTimeFull
|
|
void CClText::FormatTimeFull(CClText *i_pClient)
|
|
{
|
|
REALLOC_MESSAGE(64, i_pClient);
|
|
|
|
tINT32 l_iRes = PSPrint(i_pClient->m_pMsgCur,
|
|
i_pClient->m_szMsg - (i_pClient->m_pMsgCur - i_pClient->m_pMsg),
|
|
TM("%02d.%02d.%04d %02d:%02d:%02d.%03d'%03d\"%d"),
|
|
i_pClient->m_sLog.dwDay,
|
|
i_pClient->m_sLog.dwMonth,
|
|
i_pClient->m_sLog.dwYear,
|
|
i_pClient->m_sLog.dwHour,
|
|
i_pClient->m_sLog.dwMinutes,
|
|
i_pClient->m_sLog.dwSeconds,
|
|
i_pClient->m_sLog.dwMilliseconds,
|
|
i_pClient->m_sLog.dwMicroseconds,
|
|
i_pClient->m_sLog.dwNanoseconds
|
|
);
|
|
if (0 < l_iRes)
|
|
{
|
|
i_pClient->m_pMsgCur += l_iRes;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//FormatTimeMedium
|
|
void CClText::FormatTimeMedium(CClText *i_pClient)
|
|
{
|
|
REALLOC_MESSAGE(64, i_pClient);
|
|
|
|
tINT32 l_iRes = PSPrint(i_pClient->m_pMsgCur,
|
|
i_pClient->m_szMsg - (i_pClient->m_pMsgCur - i_pClient->m_pMsg),
|
|
TM("%02d:%02d:%02d.%03d'%03d\"%d"),
|
|
i_pClient->m_sLog.dwHour,
|
|
i_pClient->m_sLog.dwMinutes,
|
|
i_pClient->m_sLog.dwSeconds,
|
|
i_pClient->m_sLog.dwMilliseconds,
|
|
i_pClient->m_sLog.dwMicroseconds,
|
|
i_pClient->m_sLog.dwNanoseconds
|
|
);
|
|
if (0 < l_iRes)
|
|
{
|
|
i_pClient->m_pMsgCur += l_iRes;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//FormatTimeShort
|
|
void CClText::FormatTimeShort(CClText *i_pClient)
|
|
{
|
|
REALLOC_MESSAGE(64, i_pClient);
|
|
|
|
tINT32 l_iRes = PSPrint(i_pClient->m_pMsgCur,
|
|
i_pClient->m_szMsg - (i_pClient->m_pMsgCur - i_pClient->m_pMsg),
|
|
TM("%02d:%02d.%03d'%03d\"%d"),
|
|
i_pClient->m_sLog.dwMinutes,
|
|
i_pClient->m_sLog.dwSeconds,
|
|
i_pClient->m_sLog.dwMilliseconds,
|
|
i_pClient->m_sLog.dwMicroseconds,
|
|
i_pClient->m_sLog.dwNanoseconds
|
|
);
|
|
if (0 < l_iRes)
|
|
{
|
|
i_pClient->m_pMsgCur += l_iRes;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//FormatTimeDiff
|
|
void CClText::FormatTimeDiff(CClText *i_pClient)
|
|
{
|
|
tUINT64 l_qwTime = i_pClient->m_sLog.qwRawTimeOffset;
|
|
tUINT64 l_dwReminder = l_qwTime % TIME_MSC_100NS; //micro & 100xNanoseconds
|
|
tUINT64 l_dwNano = l_qwTime % 10;
|
|
tUINT64 l_dwMicro = l_dwReminder / 10;
|
|
|
|
l_qwTime -= l_dwReminder;
|
|
|
|
tUINT64 l_qwSec = l_qwTime / TIME_SEC_100NS;
|
|
tUINT64 l_qwMSc = (l_qwTime - (l_qwSec * TIME_SEC_100NS)) / TIME_MSC_100NS;
|
|
|
|
REALLOC_MESSAGE(64, i_pClient);
|
|
|
|
tINT32 l_iRes = PSPrint(i_pClient->m_pMsgCur,
|
|
i_pClient->m_szMsg - (i_pClient->m_pMsgCur - i_pClient->m_pMsg),
|
|
TM("+%06d.%03d'%03d\"%d"),
|
|
(tUINT32)l_qwSec,
|
|
(tUINT32)l_qwMSc,
|
|
(tUINT32)l_dwMicro,
|
|
(tUINT32)l_dwNano
|
|
);
|
|
if (0 < l_iRes)
|
|
{
|
|
i_pClient->m_pMsgCur += l_iRes;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//FormatTimeCount
|
|
void CClText::FormatTimeCount(CClText *i_pClient)
|
|
{
|
|
REALLOC_MESSAGE(64, i_pClient);
|
|
|
|
tINT32 l_iRes = PSPrint(i_pClient->m_pMsgCur,
|
|
i_pClient->m_szMsg - (i_pClient->m_pMsgCur - i_pClient->m_pMsg),
|
|
TM("%019lld"),
|
|
i_pClient->m_sLog.qwRawTime
|
|
);
|
|
if (0 < l_iRes)
|
|
{
|
|
i_pClient->m_pMsgCur += l_iRes;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//FormatLevel
|
|
void CClText::FormatLevel(CClText *i_pClient)
|
|
{
|
|
if ( (i_pClient->m_sLog.eLevel >= EP7TRACE_LEVEL_COUNT)
|
|
|| (i_pClient->m_sLog.eLevel < 0)
|
|
)
|
|
{
|
|
i_pClient->m_sLog.eLevel = EP7TRACE_LEVEL_CRITICAL;
|
|
}
|
|
REALLOC_MESSAGE(LEVEL_TEXT_LENGTH + 16, i_pClient);
|
|
memcpy(i_pClient->m_pMsgCur, g_pLevel[i_pClient->m_sLog.eLevel], LEVEL_TEXT_LENGTH * sizeof(tXCHAR));
|
|
i_pClient->m_pMsgCur += LEVEL_TEXT_LENGTH;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//FormatThreadId
|
|
void CClText::FormatThreadId(CClText *i_pClient)
|
|
{
|
|
REALLOC_MESSAGE(64, i_pClient);
|
|
|
|
tINT32 l_iRes = PSPrint(i_pClient->m_pMsgCur,
|
|
i_pClient->m_szMsg - (i_pClient->m_pMsgCur - i_pClient->m_pMsg),
|
|
TM("0x%05X"),
|
|
i_pClient->m_sLog.dwThreadId
|
|
);
|
|
if (0 < l_iRes)
|
|
{
|
|
i_pClient->m_pMsgCur += l_iRes;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//FormatThreadName
|
|
void CClText::FormatThreadName(CClText *i_pClient)
|
|
{
|
|
REALLOC_MESSAGE(i_pClient->m_sLog.szThreadName + 16, i_pClient);
|
|
memcpy(i_pClient->m_pMsgCur,
|
|
i_pClient->m_sLog.pThreadName,
|
|
i_pClient->m_sLog.szThreadName * sizeof(tXCHAR)
|
|
);
|
|
i_pClient->m_pMsgCur += i_pClient->m_sLog.szThreadName;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//FormatCpuCore
|
|
void CClText::FormatCpuCore(CClText *i_pClient)
|
|
{
|
|
REALLOC_MESSAGE(64, i_pClient);
|
|
|
|
tINT32 l_iRes = PSPrint(i_pClient->m_pMsgCur,
|
|
i_pClient->m_szMsg - (i_pClient->m_pMsgCur - i_pClient->m_pMsg),
|
|
TM("%02d"),
|
|
i_pClient->m_sLog.dwCpuCore
|
|
);
|
|
if (0 < l_iRes)
|
|
{
|
|
i_pClient->m_pMsgCur += l_iRes;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//FormatModuleId
|
|
void CClText::FormatModuleId(CClText *i_pClient)
|
|
{
|
|
REALLOC_MESSAGE(64, i_pClient);
|
|
|
|
tINT32 l_iRes = PSPrint(i_pClient->m_pMsgCur,
|
|
i_pClient->m_szMsg - (i_pClient->m_pMsgCur - i_pClient->m_pMsg),
|
|
TM("%03d"),
|
|
i_pClient->m_sLog.dwModuleID
|
|
);
|
|
if (0 < l_iRes)
|
|
{
|
|
i_pClient->m_pMsgCur += l_iRes;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//FormatModuleName
|
|
void CClText::FormatModuleName(CClText *i_pClient)
|
|
{
|
|
REALLOC_MESSAGE(i_pClient->m_sLog.szModuleName + 16, i_pClient);
|
|
memcpy(i_pClient->m_pMsgCur,
|
|
i_pClient->m_sLog.pModuleName,
|
|
i_pClient->m_sLog.szModuleName * sizeof(tXCHAR)
|
|
);
|
|
i_pClient->m_pMsgCur += i_pClient->m_sLog.szModuleName;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//FormatFilePath
|
|
void CClText::FormatFilePath(CClText *i_pClient)
|
|
{
|
|
REALLOC_MESSAGE(i_pClient->m_sLog.pDesc->szFilePath + 16, i_pClient);
|
|
memcpy(i_pClient->m_pMsgCur,
|
|
i_pClient->m_sLog.pDesc->pFilePath,
|
|
i_pClient->m_sLog.pDesc->szFilePath * sizeof(tXCHAR)
|
|
);
|
|
i_pClient->m_pMsgCur += i_pClient->m_sLog.pDesc->szFilePath;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//FormatFileName
|
|
void CClText::FormatFileName(CClText *i_pClient)
|
|
{
|
|
REALLOC_MESSAGE(i_pClient->m_sLog.pDesc->szFileName + 16, i_pClient);
|
|
memcpy(i_pClient->m_pMsgCur,
|
|
i_pClient->m_sLog.pDesc->pFileName,
|
|
i_pClient->m_sLog.pDesc->szFileName * sizeof(tXCHAR)
|
|
);
|
|
i_pClient->m_pMsgCur += i_pClient->m_sLog.pDesc->szFileName;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//FormatFileLine
|
|
void CClText::FormatFileLine(CClText *i_pClient)
|
|
{
|
|
REALLOC_MESSAGE(64, i_pClient);
|
|
|
|
tINT32 l_iRes = PSPrint(i_pClient->m_pMsgCur,
|
|
i_pClient->m_szMsg - (i_pClient->m_pMsgCur - i_pClient->m_pMsg),
|
|
TM("%03d"),
|
|
(tUINT32)i_pClient->m_sLog.pDesc->wLine
|
|
);
|
|
if (0 < l_iRes)
|
|
{
|
|
i_pClient->m_pMsgCur += l_iRes;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//FormatFunction
|
|
void CClText::FormatFunction(CClText *i_pClient)
|
|
{
|
|
REALLOC_MESSAGE(i_pClient->m_sLog.pDesc->szFunction + 16, i_pClient);
|
|
memcpy(i_pClient->m_pMsgCur,
|
|
i_pClient->m_sLog.pDesc->pFunction,
|
|
i_pClient->m_sLog.pDesc->szFunction * sizeof(tXCHAR)
|
|
);
|
|
i_pClient->m_pMsgCur += i_pClient->m_sLog.pDesc->szFunction;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//FormatMsg
|
|
void CClText::FormatMsg(CClText *i_pClient)
|
|
{
|
|
REALLOC_MESSAGE(i_pClient->m_sLog.szMessage + 16, i_pClient);
|
|
memcpy(i_pClient->m_pMsgCur,
|
|
i_pClient->m_sLog.pMessage,
|
|
i_pClient->m_sLog.szMessage * sizeof(tXCHAR)
|
|
);
|
|
i_pClient->m_pMsgCur += i_pClient->m_sLog.szMessage;
|
|
}
|
|
|