📄 htrace.cpp
字号:
} ULONG l_lTextAreaSize =
s_Impl.m_BufferPointers.m_dwTextAreaSize;
if(!l_lTextAreaSize)
{ return false;
} ULONG * l_pdwBytesWritten = &s_Impl.
m_BufferPointers.m_pGlobalFooter->m_dwNumBytesWritten;
if(s_Impl.m_BufferPointers.m_pGlobalFooter->m_dwFrozen)
{ return false;
} char* l_pszTextArea = (char*)s_Impl.m_BufferPointers.m_pTextArea;
if((ULONG)l_iLenBytes > l_lTextAreaSize)
l_iLenBytes = l_lTextAreaSize;
//To ensure thread safety, we access the m_iWriteTo
//variable only from the single atomic operation
ULONG l_dwWriteAt = InterlockedExchangeAdd
((long*)l_pdwBytesWritten,l_iLenBytes);
if(l_dwWriteAt + l_iLenBytes > s_Impl.m_BufferPointers.
m_pGlobalFooter->m_dwStopAfterThreshold)
{
s_Impl.m_BufferPointers.m_pGlobalFooter->m_dwFrozen = 1;
return false;
}
//Now we reserved a space in the buffer,which other threads
//will not touch, unless the buffer is filled too fast. In
//that case we will have meaningless garbage in the buffer.
//Wrap around (circular buffer):
l_dwWriteAt %= l_lTextAreaSize;
if(l_dwWriteAt + l_iLenBytes <= l_lTextAreaSize)
{
memcpy(l_pszTextArea + l_dwWriteAt, p_pszString, l_iLenBytes);
}
else
{
ULONG l_dwWriteAtTheTail = l_lTextAreaSize - l_dwWriteAt;
memcpy(l_pszTextArea + l_dwWriteAt, p_pszString,
l_dwWriteAtTheTail);
ULONG l_dwWriteAtTheBeginning =
l_iLenBytes -l_dwWriteAtTheTail;
memcpy(l_pszTextArea, p_pszString + l_dwWriteAtTheTail,
l_dwWriteAtTheBeginning);
}
return true;
}//bool AddToTraceBuffer
#if defined(WINAPP) //{
/*-------------------------------------------------------------
FUNCTION: CreateOpenFileMapping
PURPOSE: Create file mapping for use as a shared memory
buffer by WIN32 applications
-------------------------------------------------------------*/
HANDLE CreateOpenFileMapping
(
LPCTSTR p_pszMemMapFilePath,
int p_iFileSize,
bool *p_pbReturnIsCreated
)
{
*p_pbReturnIsCreated = false;
#if !defined(_WIN32_WCE)
HANDLE l_hFileMapping = OpenFileMapping(
FILE_MAP_ALL_ACCESS, FALSE, g_szMemMapFileName);
if(l_hFileMapping)
return l_hFileMapping;
HANDLE l_hFileHandle = CreateFile(p_pszMemMapFilePath,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE | FILE_SHARE_READ, 0,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
#else
HANDLE l_hFileHandle = CreateFileForMapping(p_pszMemMapFilePath,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE | FILE_SHARE_READ, 0,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
#endif
if(GetLastError() != ERROR_SHARING_VIOLATION)
{
*p_pbReturnIsCreated = true;
if(l_hFileHandle == INVALID_HANDLE_VALUE)
{
HTRACE(TG_Error,
_T("ERROR: Cannot open file %s for mapping (%s)"),
p_pszMemMapFilePath, ERR_EXPL(GetLastError()));
return NULL;
}//if(l_hFileHandle == INVALID_HANDLE_VALUE)
}
HANDLE l_hFileMapping = CreateFileMapping(l_hFileHandle,
NULL, PAGE_READWRITE, 0, p_iFileSize, g_szMemMapFileName);
CloseHandle(l_hFileHandle);
if(!l_hFileMapping)
{//May be somebody else created it?
#if !defined(_WIN32_WCE)
l_hFileMapping = OpenFileMapping(
FILE_MAP_ALL_ACCESS, FALSE,
g_szMemMapFileName);
#endif
if(!l_hFileMapping)
{
HTRACE(TG_Error,
_T("Failed to create file mapping(%s)"),
ERR_EXPL(GetLastError()));
return false;
}
}
return l_hFileMapping;
}//HANDLE CreateNewFileMapping
/*-------------------------------------------------------------
FUNCTION: TraceImpl::CreateAndMapFile
PURPOSE: Open an existing memory mapped file or create new
one for use as shared memory buffer by WIN32 applications
-------------------------------------------------------------*/
bool TraceImpl::CreateAndMapFile
(
LPCTSTR p_pszMemMapFilePath,
int p_iFileSize
)
{
if(m_BufferPointers.m_pGlobalHeader)
return false;
TCHAR l_szFileName[260];
if(p_pszMemMapFilePath == NULL ||
!_tcschr(p_pszMemMapFilePath, '\\'))
{
#if defined(_WIN32_WCE)
//Just put it in the root
int l_iLen = 1;
l_szFileName[0] = '\\';
#else
//No directory specified. Try to create the file in the
//current directory
GetCurrentDirectory(
sizeof(l_szFileName)/sizeof(l_szFileName[0]),
l_szFileName);
int l_iLen = strlen(l_szFileName);
if(l_iLen > 0 && l_szFileName[l_iLen-1] != '\\')
l_szFileName[l_iLen++] = '\\';
#endif
if(p_pszMemMapFilePath)
_tcscpy(l_szFileName + l_iLen, p_pszMemMapFilePath);
else
_tcscpy(l_szFileName + l_iLen, g_szMemMapFileName);
p_pszMemMapFilePath = l_szFileName;
}
bool l_bFileCreated = false;
if(!m_hFileMapping)
{
if(p_iFileSize <= 0)
p_iFileSize = g_iDefaultMemMapFileSize;
p_iFileSize += TRACE_BUFFER_EXTRA_SIZE;
m_hFileMapping = CreateOpenFileMapping(p_pszMemMapFilePath,
p_iFileSize, &l_bFileCreated);
}//if(!m_hFileMapping)
GlobalTraceBufferHeader * l_pBufferHeader =
(GlobalTraceBufferHeader * )
MapViewOfFile(m_hFileMapping, FILE_MAP_ALL_ACCESS,
0,0,0);
if(!l_pBufferHeader)
{
return false;
}
if(l_bFileCreated)
{
memset(l_pBufferHeader, 0, p_iFileSize);
int l_iSizeTextArea =
p_iFileSize - TRACE_BUFFER_EXTRA_SIZE;
l_pBufferHeader->m_dwSignature =
TRACE_BUFFER_SIGNATURE;
SetTextAreaSizeHex(l_pBufferHeader->m_cSizeTextArea,
l_iSizeTextArea); } AssignTraceBufferPtr(l_pBufferHeader); if(l_bFileCreated) { m_BufferPointers.m_pGlobalFooter->m_dwStopAfterThreshold = (ULONG)-1; m_BufferPointers.m_pGlobalFooter->m_dwFrozen = 0; }
m_bBufferMapped = true;
return true;
}//bool TraceImpl::CreateAndMapFile
#endif //#if defined(WINAPP) }
#if defined(__linux__)//{
//First we need to define semaphore routines for linux.
//define _TEST_SEM to trace and test semaphore routines
//in a console app.
//#define _TEST_SEM
#ifdef _TEST_SEM
#define SEM_TRACE(format, param1, param2, param3) \
{printf(format, param1, param2, param3);\
printf("Press Enter key to continue\n");\
getchar();}
#else
#define SEM_TRACE(format, param1, param2, param3)
#endif
static bool DoSemOp(int p_iSemID, int p_iNum,
int p_iIncDec, bool p_bUndoable)
{
SEM_TRACE("Before calling semop %d #%d Inc %d\n",
p_iSemID, p_iNum, p_iIncDec);
sembuf l_SemBuf;
l_SemBuf.sem_num = p_iNum;
l_SemBuf.sem_op = p_iIncDec;
l_SemBuf.sem_flg = p_bUndoable? SEM_UNDO : 0;
if(semop(p_iSemID, &l_SemBuf, 1) != 0)
{
SEM_TRACE("semop failed. %s\n",
strerror(errno),0,0);
HTRACE(TG_Error, "semop failed. %s\n",
strerror(errno));
return false;
}
SEM_TRACE("After calling semop %d #%d Inc %d\n",
p_iSemID, p_iNum, p_iIncDec);
return true;
}
//We will use a semaphore to achieve InterlockedIncrement/
//InterlockedDecrement behavior between processes. We cannot
//use regular InterlockedIncrement on a shared memory variable
//because a process may be killed as a result of a crash or by
//quitting debugging session, which will leave the shared
//variable in incremented state forever. Increment of a
//semaphore, on the other hand, is automatically undone
//by the OS on the process death if SEM_UNDO flag is set.
//The problem with semaphores is that IPC semaphore API is too
//inflexible: it does not allow to increment the semaphore
//value and get the previous value in the same atomic
//operation. Therefore, we need to use two operations:
//semctl(GETVAL) and semop(+1) and protect these operations
//by a second semaphore to make them atomic. Despite using
//2 semaphores, this function is not blocking: it may wait
//for the second semaphore very briefly until the another
//process exits from it's call to
//InterlockedExchangeAddUsingSemaphore.
static bool InterlockedExchangeAddUsingSemaphore
(
int p_iSemKey,
int & p_riSemID,
int p_iAdd,
int & p_riReturnPreviousValue
)
{
bool l_bResult = true;
bool l_bCreatedNew = false;
if(p_riSemID <= 0)
{
//Need to create the semaphore.
//We create a set of 2 semaphores: first is the
//interlocked counter. The second is to protect
//the modification of the first one.
int l_iSemID = semget(p_iSemKey,2,
IPC_CREAT|IPC_EXCL|0660);
if(l_iSemID < 0)
{
SEM_TRACE(
"Failed to create exclusive semaphore"
" %d. %s\n",
p_iSemKey, strerror(errno), 0);
//This is not an error
//OK, get it non-exclusively
l_iSemID = semget(p_iSemKey, 2,
IPC_CREAT|0660);
if(l_iSemID < 0)
{
HTRACE(TG_Error,
"Failed to get semaphore %d. %s\n",
p_iSemKey, strerror(errno));
return false;
}
SEM_TRACE("Opened semaphore key %d id %d\n",
p_iSemKey, l_iSemID, 0);
//wait and acquire the second semaphore
if(!DoSemOp(l_iSemID,1,-1, true))
return false;
}
else
{
//We just created the semaphores. Both of them
//should have value 0, which means that other
//processes will be blocked on the second
//semaphore until we release it below.
l_bCreatedNew = true;
SEM_TRACE(
"Exclusively created semaphore key %d id %d\n",
p_iSemKey, l_iSemID, 0);
}
p_riSemID = l_iSemID;
}//if(p_riSemID <= 0)
else
{
//wait and acquire the second semaphore
if(!DoSemOp(p_riSemID,1,-1, true))
return false;
}
p_riReturnPreviousValue = semctl(p_riSemID, 0, GETVAL);
SEM_TRACE("semctl(%d,0,GETVAL) returned %d"
" going to increment by %d\n",
p_riSemID, p_riReturnPreviousValue, p_iAdd);
if(p_riReturnPreviousValue < 0)
{
HTRACE(TG_Error,
"ERROR: semctl(%d, GETVAL) failed. %s\n",
p_riSemID, strerror(errno));
l_bResult = false;
}
else if(p_riReturnPreviousValue + p_iAdd < 0)
{
HTRACE(TG_Error,
"ERROR: InterlockedExchangeAddUsingSemaphore"
" called with semaphore value %d and add = %d."
" Result will be negative",
p_riReturnPreviousValue, p_iAdd);
l_bResult = false;
}
else
{
//increase/decrease value of the first semaphore.
if(!DoSemOp(p_riSemID,0,p_iAdd, true))
l_bResult = false;
}
//Release second semaphore.
//We should use non-undoable release if we just created
//the semaphore, because it should be left in released
//state after the process terminates.
if(!DoSemOp(p_riSemID,1,+1, l_bCreatedNew? false : true))
return false;
return l_bResult;
}//bool InterlockedExchangeAddUsingSemaphore
bool PrepareMemMapFile
(
int p_iMemMapFile,
const char * p_pszMemMapFilePath,
int p_iTextAreaSize,
bool p_bInitialize,
int * p_piReturnTotalSize,
GlobalTraceBufferHeader ** p_ppReturnHeader
)
{
int l_iTotalFileSize =
p_iTextAreaSize + TRACE_BUFFER_EXTRA_SIZE;
if(p_bInitialize)
{ //We are the first process, which created the
//file and must initialize it.
//First, make sure the file is long enough
int l_iSize = lseek(p_iMemMapFile, 0, SEEK_END);
if(l_iSize < l_iTotalFileSize)
{
if(lseek(p_iMemMapFile,l_iTotalFileSize-1,SEEK_SET)
!= l_iTotalFileSize-1)
{
HTRACE(TG_Error,
"ERROR: lseek(%s, %d) failed: %s",
p_pszMemMapFilePath, l_iTotalFileSize-1,
strerror(errno));
return false;
}
if(write(p_iMemMapFile, "", 1) < 0)
{
HTRACE(TG_Error,
"ERROR: write of 1 byte to %s failed: %s",
p_pszMemMapFilePath, strerror(errno));
return false;
}
}
else if(l_iSize > l_iTotalFileSize)
{
if(ftruncate(p_iMemMapFile, l_iTotalFileSize) < 0)
{
HTRACE(TG_Error, "ERROR: ftruncate failed. %s",
strerror(errno));
return false;
}
}
l_iSize = lseek(p_iMemMapFile, 0, SEEK_END);
}//if(p_bInitialize)
else
{ //The file is already in u
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -