//////////////////////////////////////////////////////////////////////////////// // / // 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 //#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(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(new CClTextConsole()); } else if (0 == PStrICmp(l_pSink, CLIENT_SINK_FILE_TXT)) { m_pSink = static_cast(new CClTextFile()); } else if (0 == PStrICmp(l_pSink, CLIENT_SINK_SYSLOG)) { m_pSink = static_cast(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(l_pAddr); m_bSinkExternal = TRUE; } } } if (!m_pSink) { m_pSink = static_cast(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; }