legatt 32f4597c4d Base frontend module
- 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
2025-08-08 00:07:32 +03:00

576 lines
18 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 file provide trace functionality /
////////////////////////////////////////////////////////////////////////////////
#ifndef TRACE_H
#define TRACE_H
#define P7TRACE_ITEM_BLOCK_ASTRING (-1)
#define P7TRACE_ITEM_BLOCK_USTRING16 (-2)
#define P7TRACE_ITEM_BLOCK_USTRING8 (-3)
#define P7TRACE_ITEM_BLOCK_USTRING32 (-4)
#define P7TRACE_ITEM_BLOCK_ASTRING_FIX (-5)
#define P7TRACE_ITEM_BLOCK_WSTRING_FIX (-6)
#define P7TRACE_KEY_LENGTH (2)
//#define P7TRACE_MAP_FILE_NAME L"Local\\P7Trace"
//#define P7TRACE_MAP_FILE_SIZE (sizeof(CP7Trace*) + sizeof(IP7_Client*))
#define P7TRACE_THREADS_POOL_SIZE (32)
#define P7TRACE_THREADS_MAX_SIZE (128)
#define P7TRACE_MODULES_POOL_SIZE (32)
#define P7TRACE_MODULES_MAX_SIZE (512)
#define P7TRACE_MEMORY_ALIGNMENT (8)
////////////////////////////////////////////////////////////////////////////////
//Memory manager, used for trace descriptions, avoid calling New & malloc
class CMemoryManager
{
public:
enum eBuffer
{
eFileName,
eFunctionName,
eArguments,
eVaValues,
eCount
};
protected:
struct sBlock
{
void *pData;
sBlock *pNext;
};
struct sBuffer
{
void *pData;
size_t szBuffer;
};
sBlock *m_pCurrent; //dynamic, internal buffers - allocated once
size_t m_szCurrent;
size_t m_szCurrentUsed;
size_t m_szTotal;
size_t m_szMax;
size_t m_szRecommended;
sBlock *m_pBusy;
sBuffer m_pBuffers[CMemoryManager::eCount]; //static buffers, reusable
public:
////////////////////////////////////////////////////////////////////////////
//CMemoryManager
CMemoryManager(size_t i_szInitial, size_t i_szMax = 0xFFFFFFF)
: m_pCurrent(NULL)
, m_szCurrent(i_szInitial)
, m_szCurrentUsed(0)
, m_szTotal(i_szInitial)
, m_szMax(i_szMax)
, m_szRecommended(i_szInitial)
, m_pBusy(NULL)
{
memset(m_pBuffers, 0, sizeof(m_pBuffers));
m_pCurrent = (sBlock*)malloc(m_szCurrent + sizeof(sBlock));
if (m_pCurrent)
{
m_pCurrent->pData = (tUINT8*)m_pCurrent + sizeof(sBlock);
m_pCurrent->pNext = NULL;
}
}//CMemoryManager
////////////////////////////////////////////////////////////////////////////
//~CMemoryManager
~CMemoryManager()
{
while (m_pCurrent)
{
sBlock *l_pTmp = m_pCurrent;
m_pCurrent = m_pCurrent->pNext;
free(l_pTmp);
}
while (m_pBusy)
{
sBlock *l_pTmp = m_pBusy;
m_pBusy = m_pBusy->pNext;
free(l_pTmp);
}
for (size_t l_szI = 0; l_szI < LENGTH(m_pBuffers); l_szI++)
{
if (m_pBuffers[l_szI].pData)
{
free(m_pBuffers[l_szI].pData);
m_pBuffers[l_szI].pData = NULL;
}
}
}//~CMemoryManager
////////////////////////////////////////////////////////////////////////////
//Reuse - function is used for reusable temporary buffers
void *Reuse(CMemoryManager::eBuffer i_eBuffer, size_t i_szBuffer)
{
sBuffer *l_pBuffer = &m_pBuffers[i_eBuffer];
if ( (l_pBuffer->pData)
&& (l_pBuffer->szBuffer >= i_szBuffer)
)
{
return l_pBuffer->pData;
}
size_t l_szNew = (i_szBuffer + (size_t)255) & (~(size_t)255);
void *l_pNew = realloc(l_pBuffer->pData, l_szNew);
if (l_pNew)
{
l_pBuffer->pData = l_pNew;
l_pBuffer->szBuffer = l_szNew;
}
return l_pNew;
}//Reuse
////////////////////////////////////////////////////////////////////////////
//Size
size_t Size(CMemoryManager::eBuffer i_eBuffer)
{
return m_pBuffers[i_eBuffer].szBuffer;
}//Size
////////////////////////////////////////////////////////////////////////////
//Alloc - function is used for constant buffers used until class is a live
void *Alloc(size_t i_szBuffer)
{
tUINT8 *l_pReturn = NULL;
i_szBuffer = (i_szBuffer + P7TRACE_MEMORY_ALIGNMENT - 1) & ~(P7TRACE_MEMORY_ALIGNMENT - 1);
if ( (m_pCurrent)
&& ((m_szCurrent - m_szCurrentUsed) >= i_szBuffer)
)
{
l_pReturn = (tUINT8*)m_pCurrent->pData + m_szCurrentUsed;
m_szCurrentUsed += i_szBuffer;
}
else if ((m_szTotal + i_szBuffer) <= m_szMax)
{
//add current buffer to busy queue
m_pCurrent->pNext = m_pBusy;
m_pBusy = m_pCurrent;
//allocate new buffer
m_szCurrentUsed = 0;
m_szCurrent = (i_szBuffer <= m_szRecommended) ? m_szRecommended : i_szBuffer;
m_pCurrent = (sBlock*)malloc(sizeof(sBlock) + m_szCurrent);
if (m_pCurrent)
{
m_pCurrent->pData = (tUINT8*)m_pCurrent + sizeof(sBlock);
m_pCurrent->pNext = NULL;
l_pReturn = (tUINT8*)m_pCurrent->pData;
m_szCurrentUsed += i_szBuffer;
m_szTotal += m_szCurrent;
}
}
return l_pReturn;
}//Alloc
};
////////////////////////////////////////////////////////////////////////////////
//sData_Block
template <typename tData_Type>
struct sData_Block
{
tUINT32 dwCount;
tUINT32 dwUsed;
tData_Type *pData;
sData_Block(tUINT32 i_dwCount)
: dwCount(i_dwCount)
, dwUsed(0)
, pData((tData_Type*)malloc(i_dwCount * sizeof(tData_Type)))
{
if (pData)
{
memset(pData, 0, i_dwCount * sizeof(tData_Type));
}
}
~sData_Block()
{
if (pData)
{
free(pData);
pData = NULL;
}
dwCount = 0;
dwUsed = 0;
}
};//sData_Block
////////////////////////////////////////////////////////////////////////////////
//CP7Trace_Desc
class CP7Trace_Desc
{
tUINT16 m_wID;
tUINT16 m_wModuleID;
//count of connections drops... see sP7C_Status. If this value and
//value from IP7_Client are different - it mean we loose connection
tUINT32 m_dwResets;
tUINT32 m_dwSize;
tUINT8 *m_pBuffer;//Buffer will contain sP7Trace_Format
tINT32 *m_pBlocks;
tINT32 m_dwBlocks_Count;
sP7Trace_Arg *m_pArgs;
tUINT32 m_dwArgs_Count;
tKeyType m_pKey[P7TRACE_KEY_LENGTH];
tBOOL m_bInitialized;
public:
CP7Trace_Desc(CMemoryManager &i_rMemory,
tUINT16 i_wID,
tUINT16 i_wLine,
tUINT16 i_wModuleID,
const char *i_pFile,
const char *i_pFunction,
const tXCHAR **i_pFormat,
tKeyType i_pKeys[P7TRACE_KEY_LENGTH],
tUINT32 i_dwFlags
);
CP7Trace_Desc(CMemoryManager &i_rMemory,
tUINT16 i_wID,
tUINT16 i_wLine,
tUINT16 i_wModuleID,
const tXCHAR *i_pFile,
const tXCHAR *i_pFunction,
tKeyType i_pKeys[P7TRACE_KEY_LENGTH]
);
~CP7Trace_Desc() {}
tBOOL Is_Initialized();
tUINT8 *Get_Buffer(tUINT32 *o_pSize);
tINT32 *Get_Blocks(tUINT32 *o_pCount);
void Set_Resets(tUINT32 i_dwDrops);
tUINT32 Get_Resets();
tUINT32 Get_Arguments_Count();
const sP7Trace_Arg *Get_Arguments(tUINT32 &o_rCount);
tBOOL Is_Equal(tKeyType *i_pKey);
tBOOL Is_Greater(tKeyType *i_pKey);
tUINT16 Get_ID();
tUINT16 Get_MID();
};//CP7Trace_Desc
////////////////////////////////////////////////////////////////////////////////
//CDesc_Tree
class CDesc_Tree:
public CRBTree<CP7Trace_Desc*, tKeyType*>
{
public:
////////////////////////////////////////////////////////////////////////////
//~CDesc_Tree
virtual ~CDesc_Tree()
{
Clear();
}//~CRBTree
protected:
////////////////////////////////////////////////////////////////////////////
virtual tBOOL Data_Release(CP7Trace_Desc* i_pData)
{
UNUSED_ARG(i_pData);
return TRUE; //memory used from pool, not necessary to return
}// Data_Release
////////////////////////////////////////////////////////////////////////////
//Return
//TRUE - if (i_pKey < i_pData::key)
//FALSE - otherwise
tBOOL Is_Key_Less(tKeyType *i_pKey, CP7Trace_Desc *i_pData)
{
return i_pData->Is_Greater(i_pKey);
}
////////////////////////////////////////////////////////////////////////////
//Return
//TRUE - if (i_pKey == i_pData::key)
//FALSE - otherwise
tBOOL Is_Qual(tKeyType *i_pKey, CP7Trace_Desc *i_pData)
{
return i_pData->Is_Equal(i_pKey);
}
};//CDesc_Tree
////////////////////////////////////////////////////////////////////////////////
//sModuleMap
struct sModuleMap
{
sP7Trace_Module *pModule;
tXCHAR *pName;
sModuleMap(const tXCHAR *i_pName, sP7Trace_Module *i_pModule)
: pModule(i_pModule)
, pName(PStrDub(i_pName))
{
}
~sModuleMap()
{
if (pName)
{
PStrFreeDub(pName);
pName = NULL;
}
pModule = NULL;
}
};//sModuleMap
////////////////////////////////////////////////////////////////////////////////
//CModules_Tree
class CModules_Tree:
public CRBTree<sModuleMap*, const tXCHAR*>
{
public:
CModules_Tree()
: CRBTree<sModuleMap*, const tXCHAR*>(16, TRUE)
{
}
protected:
////////////////////////////////////////////////////////////////////////////
//Return
//TRUE - if (i_pKey < i_pData::key)
//FALSE - otherwise
tBOOL Is_Key_Less(const tXCHAR *i_pKey, sModuleMap *i_pData)
{
return (0 < PStrCmp(i_pKey, i_pData->pName)) ? TRUE : FALSE;
}
////////////////////////////////////////////////////////////////////////////
//Return
//TRUE - if (i_pKey == i_pData::key)
//FALSE - otherwise
tBOOL Is_Qual(const tXCHAR *i_pKey, sModuleMap *i_pData)
{
return (0 == PStrCmp(i_pKey, i_pData->pName)) ? TRUE : FALSE;
}
};//CModules_Tree
////////////////////////////////////////////////////////////////////////////////
#define P7_TRACE_DESC_HARDCODED_COUNT (1024)
class CP7Trace
: public IP7_Trace
{
struct sStack_Desc
{
enum eType
{
eTypeU32,
eTypeU64,
eTypeD64
};
union uVal
{
tUINT32 dw32;
tUINT64 dw64;
tDOUBLE db64;
};
CP7Trace::sStack_Desc::uVal uValue;
CP7Trace::sStack_Desc::eType eType;
tBOOL bLast;
};
typedef sData_Block<sP7Trace_Thread_Start> sThreadsR; //running threads
typedef sData_Block<sP7Trace_Thread_Stop> sThreadsS; //stopped threads
typedef sData_Block<sP7Trace_Module> sModules; //modules
//put volatile variables at the top, to obtain 32 bit alignment.
//Project has 8 bytes alignment by default
tINT32 volatile m_lReference;
tUINT32 m_dwSequence;
IP7_Client *m_pClient;
tUINT32 m_dwChannel_ID;
CP7Trace_Desc *m_pDesc_Array[P7_TRACE_DESC_HARDCODED_COUNT];
CDesc_Tree m_cDescU_Tree;
CDesc_Tree m_cDescM_Tree;
tUINT16 m_wDesc_Tree_ID;
tLOCK m_sCS;
tUINT32 m_dwLast_ID;
tBOOL m_bInitialized;
tBOOL m_bActive;
eP7Trace_Level m_eVerbosity;
sP7Trace_Info m_sHeader_Info;
sP7Trace_Data m_sHeader_Data;
sP7Trace_Utc_Offs m_sHeader_Utc;
sP7C_Status m_sStatus;
sP7C_Data_Chunk *m_pChk_Head;
sP7C_Data_Chunk *m_pChk_Tail;
sP7C_Data_Chunk *m_pChk_Curs;
tUINT32 m_dwChk_Count;
tUINT32 m_dwChk_Size;
tBOOL m_bIs_Channel;
tUINT32 m_dwFlags;
CAList<sThreadsR*> m_cThreadsR;
CAList<sThreadsS*> m_cThreadsS;
tUINT16 m_wLast_ModuleID;
CAList<sModules*> m_cModules;
CModules_Tree m_cModules_Map;
CShared::hShared m_hShared;
CMemoryManager m_cMemory;
tUINT8 *m_pVargs;
size_t m_szVargs;
tUINT8 m_pExtensions[4];
stTrace_Conf m_sConf;
public:
CP7Trace(IP7_Client *i_pClient,
const tXCHAR *i_pName,
const stTrace_Conf *i_pConf); //for arguments description see P7_Client.h
virtual ~CP7Trace();
tBOOL Is_Initialized();
IP7C_Channel::eType Get_Type() { return IP7C_Channel::eTrace; }
void On_Init(sP7C_Channel_Info *i_pInfo);
void On_Receive(tUINT32 i_dwChannel, tUINT8 *i_pBuffer, tUINT32 i_dwSize, tBOOL i_bBigEndian);
void On_Status(tUINT32 i_dwChannel, const sP7C_Status *i_pStatus);
void On_Flush(tUINT32 i_dwChannel, tBOOL *io_pCrash);
tBOOL Register_Thread(const tXCHAR *i_pName, tUINT32 i_dwThreadId);
tBOOL Unregister_Thread(tUINT32 i_dwThreadId);
tBOOL Register_Module(const tXCHAR *i_pName, IP7_Trace::hModule *o_hModule);
void Set_Verbosity(IP7_Trace::hModule i_hModule, eP7Trace_Level i_eVerbosity);
eP7Trace_Level Get_Verbosity(IP7_Trace::hModule i_hModule);
tBOOL Trace(tUINT16 i_wTrace_ID,
eP7Trace_Level i_eLevel,
IP7_Trace::hModule i_hModule,
tUINT16 i_wLine,
const char *i_pFile,
const char *i_pFunction,
const tXCHAR *i_pFormat,
...
);
tBOOL Trace_Embedded(tUINT16 i_wTrace_ID,
eP7Trace_Level i_eLevel,
IP7_Trace::hModule i_hModule,
tUINT16 i_wLine,
const char *i_pFile,
const char *i_pFunction,
const tXCHAR **i_ppFormat
);
tBOOL Trace_Embedded(tUINT16 i_wTrace_ID,
eP7Trace_Level i_eLevel,
IP7_Trace::hModule i_hModule,
tUINT16 i_wLine,
const char *i_pFile,
const char *i_pFunction,
const tXCHAR **i_ppFormat,
va_list *i_pVa_List
);
tBOOL Trace_Managed(tUINT16 i_wTrace_ID,
eP7Trace_Level i_eLevel,
IP7_Trace::hModule i_hModule,
tUINT16 i_wLine,
const tXCHAR *i_pFile,
const tXCHAR *i_pFunction,
const tXCHAR *i_pMessage
);
virtual tINT32 Add_Ref()
{
return ATOMIC_INC(&m_lReference);
}
virtual tINT32 Release()
{
tINT32 l_lResult = ATOMIC_DEC(&m_lReference);
if ( 0 >= l_lResult )
{
delete this;
}
return l_lResult;
}
tBOOL Share(const tXCHAR *i_pName);
private:
void Flush();
tBOOL Trace_Raw(tUINT16 i_wTrace_ID,
eP7Trace_Level i_eLevel,
IP7_Trace::hModule i_hModule,
tUINT16 i_wLine,
const char *i_pFile,
const char *i_pFunction,
tKeyType *i_pKey,
const tXCHAR **i_ppFormat,
va_list *i_pVa_List
);
tBOOL Inc_Chunks(tUINT32 i_dwInc);
tBOOL Is_VarArgs(const CP7Trace::sStack_Desc *i_pDesc, ...);
};
#endif //TRACE_H