- 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
470 lines
12 KiB
C++
470 lines
12 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. /
|
|
// /
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
#ifndef PMEVENT_H
|
|
#define PMEVENT_H
|
|
|
|
#include <semaphore.h>
|
|
|
|
// Infinite timeout
|
|
#define INFINITE 0xFFFFFFFF
|
|
|
|
//#define PMEVENT_COND_VARIABLE
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//CMEvent - class designed to avoid problem of "wait" POSIX functions. They are
|
|
// based on abs. time and they are affected by system time changes.
|
|
class CMEvent
|
|
: public IMEvent //virtual
|
|
{
|
|
struct sEvent
|
|
{
|
|
volatile tINT32 iCounter;
|
|
eMEvent_Type eType;
|
|
tUINT32 dwIdx;
|
|
sEvent *pNext;
|
|
};
|
|
|
|
pthread_mutex_t m_sMutex;
|
|
|
|
#ifdef PMEVENT_COND_VARIABLE
|
|
pthread_cond_t m_sCV;
|
|
#else
|
|
sem_t m_sSem;
|
|
#endif
|
|
|
|
tUINT8 m_bCount;
|
|
tBOOL m_bInit;
|
|
tBOOL m_bError;
|
|
sEvent *m_pEvents;
|
|
sEvent *m_pEvent_Cur;
|
|
tINT32 m_iSignals;
|
|
public:
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//CMEvent
|
|
CMEvent()
|
|
: m_bCount(0)
|
|
, m_bInit(FALSE)
|
|
, m_bError(FALSE)
|
|
, m_pEvents(NULL)
|
|
, m_pEvent_Cur(NULL)
|
|
, m_iSignals(0)
|
|
{
|
|
}//CMEvent
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//~CMEvent
|
|
virtual ~CMEvent()
|
|
{
|
|
if (m_bInit)
|
|
{
|
|
pthread_mutex_destroy(&m_sMutex);
|
|
|
|
#ifdef PMEVENT_COND_VARIABLE
|
|
pthread_cond_destroy(&m_sCV);
|
|
#else
|
|
sem_destroy(&m_sSem);
|
|
#endif
|
|
|
|
}
|
|
|
|
Cleanup();
|
|
|
|
m_bCount = 0;
|
|
}//~CMEvent
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//Init
|
|
tBOOL Init(tUINT8 i_bCount, ...)
|
|
{
|
|
va_list l_pVA;
|
|
tUINT8 l_bIDX = 0;
|
|
tBOOL l_bCA = FALSE;
|
|
tBOOL l_bSig = FALSE;
|
|
tBOOL l_bMutex = FALSE;
|
|
pthread_condattr_t l_sCA;
|
|
|
|
|
|
if ( (TRUE == m_bInit)
|
|
|| (TRUE == m_bError)
|
|
|| (0 >= i_bCount)
|
|
)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
#ifdef PMEVENT_COND_VARIABLE
|
|
////////////////////////////////////////////////////////////////////////
|
|
//initialize Cond.Variable
|
|
clockid_t l_iClock = CLOCK_REALTIME;
|
|
|
|
if (0 != pthread_condattr_init(&l_sCA))
|
|
{
|
|
goto l_lExit; //error
|
|
}
|
|
else
|
|
{
|
|
l_bCA = TRUE;
|
|
}
|
|
|
|
//#ifdef __USE_XOPEN2K
|
|
if (0 != pthread_condattr_setclock(&l_sCA, CLOCK_MONOTONIC))
|
|
{
|
|
goto l_lExit; //error
|
|
}
|
|
|
|
if ( (0 != pthread_condattr_getclock(&l_sCA, &l_iClock))
|
|
|| (CLOCK_MONOTONIC != l_iClock)
|
|
)
|
|
{
|
|
goto l_lExit; //error
|
|
}
|
|
//#else
|
|
//#endif
|
|
|
|
if (0 != pthread_cond_init(&m_sCV, &l_sCA))
|
|
{
|
|
goto l_lExit; //error
|
|
}
|
|
else
|
|
{
|
|
l_bSig = TRUE;
|
|
}
|
|
#else
|
|
////////////////////////////////////////////////////////////////////////
|
|
//initialize semaphore
|
|
if (0 != sem_init(&m_sSem, 0, 0))
|
|
{
|
|
goto l_lExit; //error
|
|
}
|
|
else
|
|
{
|
|
l_bSig = TRUE;
|
|
}
|
|
#endif
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//initialize mutex
|
|
if (0 != pthread_mutex_init(&m_sMutex, NULL))
|
|
{
|
|
m_bError = TRUE;
|
|
goto l_lExit;
|
|
}
|
|
else
|
|
{
|
|
l_bMutex = TRUE;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//initialize events structure
|
|
m_pEvents = new sEvent[i_bCount];
|
|
if (NULL == m_pEvents)
|
|
{
|
|
goto l_lExit;
|
|
}
|
|
|
|
memset(m_pEvents, 0, sizeof(sEvent) * i_bCount);
|
|
|
|
m_pEvent_Cur = &m_pEvents[0];
|
|
|
|
va_start(l_pVA, i_bCount);
|
|
while (l_bIDX < i_bCount)
|
|
{
|
|
m_pEvents[l_bIDX].eType = (eMEvent_Type)va_arg(l_pVA, /*eMEvent_Type*/int);
|
|
m_pEvents[l_bIDX].iCounter = 0;
|
|
m_pEvents[l_bIDX].dwIdx = l_bIDX;
|
|
|
|
//make round trip links
|
|
if ((l_bIDX + 1) < i_bCount)
|
|
{
|
|
m_pEvents[l_bIDX].pNext = &m_pEvents[l_bIDX + 1];
|
|
}
|
|
else
|
|
{
|
|
m_pEvents[l_bIDX].pNext = &m_pEvents[0];
|
|
}
|
|
|
|
l_bIDX++;
|
|
}
|
|
|
|
va_end(l_pVA);
|
|
|
|
m_bInit = TRUE;
|
|
m_bCount = i_bCount;
|
|
|
|
l_lExit:
|
|
if (l_bCA)
|
|
{
|
|
pthread_condattr_destroy(&l_sCA);
|
|
}
|
|
|
|
if (FALSE == m_bInit)
|
|
{
|
|
m_bError = TRUE;
|
|
|
|
if (l_bMutex)
|
|
{
|
|
pthread_mutex_destroy(&m_sMutex);
|
|
}
|
|
|
|
if (l_bSig)
|
|
{
|
|
#ifdef PMEVENT_COND_VARIABLE
|
|
pthread_cond_destroy(&m_sCV);
|
|
#else
|
|
sem_destroy(&m_sSem);
|
|
#endif
|
|
}
|
|
|
|
Cleanup();
|
|
}
|
|
|
|
return m_bInit;
|
|
}//Init
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//Set
|
|
tBOOL Set(tUINT32 i_dwID)
|
|
{
|
|
if ( (i_dwID >= m_bCount)
|
|
|| (FALSE == m_bInit)
|
|
)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
pthread_mutex_lock(&m_sMutex);
|
|
|
|
m_iSignals++;
|
|
m_pEvents[i_dwID].iCounter ++;
|
|
|
|
#ifdef PMEVENT_COND_VARIABLE
|
|
pthread_cond_signal(&m_sCV);
|
|
#else
|
|
sem_post(&m_sSem);
|
|
#endif
|
|
|
|
pthread_mutex_unlock(&m_sMutex);
|
|
|
|
return TRUE;
|
|
}//Set
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//Clr
|
|
tBOOL Clr(tUINT32 i_dwID)
|
|
{
|
|
tBOOL l_bReturn = FALSE;
|
|
if ( (i_dwID >= m_bCount)
|
|
|| (EMEVENT_SINGLE_MANUAL != m_pEvents[i_dwID].eType)
|
|
)
|
|
{
|
|
return l_bReturn;
|
|
}
|
|
|
|
pthread_mutex_lock(&m_sMutex);
|
|
|
|
if (m_pEvents[i_dwID].iCounter)
|
|
{
|
|
m_iSignals --;
|
|
m_pEvents[i_dwID].iCounter --;
|
|
|
|
sem_trywait(&m_sSem); //decrease semaphore
|
|
|
|
l_bReturn = TRUE;
|
|
}
|
|
|
|
pthread_mutex_unlock(&m_sMutex);
|
|
|
|
return l_bReturn;
|
|
}//Clr
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//Wait
|
|
tUINT32 Wait()
|
|
{
|
|
tUINT32 l_dwReturn = MEVENT_TIME_OUT;
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//LOCK
|
|
|
|
#ifdef PMEVENT_COND_VARIABLE
|
|
int l_iCV_Res = 0;
|
|
|
|
pthread_mutex_lock(&m_sMutex);
|
|
|
|
while (0 == m_iSignals)
|
|
{
|
|
l_iCV_Res = pthread_cond_wait(&m_sCV, &m_sMutex);
|
|
if (0 != l_iCV_Res)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
l_dwReturn = Get_Signal();
|
|
|
|
pthread_mutex_unlock(&m_sMutex);
|
|
#else
|
|
sem_wait(&m_sSem);
|
|
|
|
pthread_mutex_lock(&m_sMutex);
|
|
l_dwReturn = Get_Signal();
|
|
pthread_mutex_unlock(&m_sMutex);
|
|
#endif
|
|
|
|
|
|
//UNLOCK
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
return l_dwReturn;
|
|
}//Wait
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//Wait
|
|
tUINT32 Wait(tUINT32 i_dwMSec)
|
|
{
|
|
tUINT64 l_qwNano = (tUINT64)i_dwMSec * 1000000ULL;
|
|
tUINT32 l_dwReturn = MEVENT_TIME_OUT;
|
|
struct timespec l_sTime = {0, 0};
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//LOCK
|
|
|
|
#ifdef PMEVENT_COND_VARIABLE
|
|
int l_iRes = 0;
|
|
pthread_mutex_lock(&m_sMutex);
|
|
clock_gettime(CLOCK_MONOTONIC, &l_sTime);
|
|
|
|
l_qwNano += l_sTime.tv_nsec;
|
|
l_sTime.tv_sec += static_cast<__time_t>(l_qwNano / 1000000000ULL);
|
|
l_sTime.tv_nsec = static_cast<long int>(l_qwNano % 1000000000ULL);
|
|
|
|
while (0 == m_iSignals)
|
|
{
|
|
//ETIMEDOUT
|
|
l_iRes = pthread_cond_timedwait(&m_sCV, &m_sMutex, &l_sTime);
|
|
if (0 != l_iRes)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
l_dwReturn = Get_Signal();
|
|
pthread_mutex_unlock(&m_sMutex);
|
|
#else
|
|
if (0 == i_dwMSec)
|
|
{
|
|
if (0 == sem_trywait(&m_sSem))
|
|
{
|
|
pthread_mutex_lock(&m_sMutex);
|
|
l_dwReturn = Get_Signal();
|
|
pthread_mutex_unlock(&m_sMutex);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
clock_gettime(CLOCK_REALTIME, &l_sTime);
|
|
|
|
l_qwNano += l_sTime.tv_nsec;
|
|
l_sTime.tv_sec += static_cast<time_t>(l_qwNano/1000000000ULL);
|
|
l_sTime.tv_nsec = static_cast<long>(l_qwNano%1000000000ULL);
|
|
|
|
if (0 == sem_timedwait(&m_sSem, &l_sTime))
|
|
{
|
|
pthread_mutex_lock(&m_sMutex);
|
|
l_dwReturn = Get_Signal();
|
|
pthread_mutex_unlock(&m_sMutex);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//UNLOCK
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
return l_dwReturn;
|
|
}//Wait
|
|
|
|
private:
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//Get_Signal
|
|
tUINT32 Get_Signal()
|
|
{
|
|
tUINT32 l_dwReturn = MEVENT_TIME_OUT;
|
|
|
|
if (0 == m_iSignals) //if we register some signal
|
|
{
|
|
return l_dwReturn;
|
|
}
|
|
|
|
sEvent *l_pStart = m_pEvent_Cur;
|
|
//we will walk through all events in attempt to find signal
|
|
do
|
|
{
|
|
m_pEvent_Cur = m_pEvent_Cur->pNext;
|
|
|
|
if (m_pEvent_Cur->iCounter)
|
|
{
|
|
l_dwReturn = m_pEvent_Cur->dwIdx;
|
|
if (EMEVENT_SINGLE_MANUAL == m_pEvent_Cur->eType)
|
|
{
|
|
sem_post(&m_sSem); //return sem value to signal again
|
|
}
|
|
else
|
|
{
|
|
m_pEvent_Cur->iCounter --;
|
|
m_iSignals --;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
//if we do round trip
|
|
} while (l_pStart != m_pEvent_Cur);
|
|
|
|
if (MEVENT_TIME_OUT == l_dwReturn)
|
|
{
|
|
//error: signal event wasn't found !
|
|
m_iSignals --;
|
|
}
|
|
|
|
return l_dwReturn;
|
|
}//Get_Signal
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//Cleanup
|
|
void Cleanup()
|
|
{
|
|
if (m_pEvents)
|
|
{
|
|
delete [] m_pEvents;
|
|
m_pEvents = NULL;
|
|
}
|
|
}//Cleanup
|
|
};
|
|
|
|
#endif //PMEVENT_H
|