184 lines
5.1 KiB
C++
184 lines
5.1 KiB
C++
/*
|
|
PIP - Platform Independent Primitives
|
|
|
|
Stephan Fomenko
|
|
|
|
This program 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 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "piplatform.h"
|
|
#ifdef WINDOWS
|
|
# undef _WIN32_WINNT
|
|
# define _WIN32_WINNT 0x0600
|
|
#endif
|
|
|
|
#include "piconditionvar.h"
|
|
#include "pithread.h"
|
|
#include "pitime.h"
|
|
#include "piincludes_p.h"
|
|
#ifdef WINDOWS
|
|
# include <synchapi.h>
|
|
# include <windef.h>
|
|
# include <winbase.h>
|
|
#endif
|
|
#ifdef FREERTOS
|
|
# include <event_groups.h>
|
|
#endif
|
|
|
|
|
|
PRIVATE_DEFINITION_START(PIConditionVariable)
|
|
#if defined(WINDOWS)
|
|
CONDITION_VARIABLE
|
|
#elif defined(FREERTOS)
|
|
EventGroupHandle_t
|
|
#else
|
|
pthread_cond_t
|
|
#endif
|
|
nativeHandle;
|
|
PRIVATE_DEFINITION_END(PIConditionVariable)
|
|
|
|
|
|
PIConditionVariable::PIConditionVariable() {
|
|
#if defined(WINDOWS)
|
|
InitializeConditionVariable(&PRIVATE->nativeHandle);
|
|
#elif defined(FREERTOS)
|
|
PRIVATE->nativeHandle = xEventGroupCreate();
|
|
#else
|
|
pthread_condattr_t condattr;
|
|
pthread_condattr_init(&condattr);
|
|
# if !defined(MAC_OS)
|
|
pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC);
|
|
# endif
|
|
memset(&(PRIVATE->nativeHandle), 0, sizeof(PRIVATE->nativeHandle));
|
|
pthread_cond_init(&PRIVATE->nativeHandle, &condattr);
|
|
#endif
|
|
}
|
|
|
|
|
|
PIConditionVariable::~PIConditionVariable() {
|
|
#if defined(WINDOWS)
|
|
#elif defined(FREERTOS)
|
|
vEventGroupDelete(PRIVATE->nativeHandle);
|
|
#else
|
|
pthread_cond_destroy(&PRIVATE->nativeHandle);
|
|
#endif
|
|
}
|
|
|
|
|
|
void PIConditionVariable::wait(PIMutex& lk) {
|
|
#if defined(WINDOWS)
|
|
SleepConditionVariableCS(&PRIVATE->nativeHandle, (PCRITICAL_SECTION)lk.handle(), INFINITE);
|
|
#elif defined(FREERTOS)
|
|
xEventGroupClearBits(PRIVATE->nativeHandle, 1);
|
|
xEventGroupWaitBits(PRIVATE->nativeHandle, 1, pdTRUE, pdTRUE, portMAX_DELAY);
|
|
#else
|
|
pthread_cond_wait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle());
|
|
#endif
|
|
}
|
|
|
|
|
|
void PIConditionVariable::wait(PIMutex& lk, const std::function<bool()>& condition) {
|
|
bool isCondition;
|
|
while (true) {
|
|
isCondition = condition();
|
|
if (isCondition) break;
|
|
#if defined(WINDOWS)
|
|
SleepConditionVariableCS(&PRIVATE->nativeHandle, (PCRITICAL_SECTION)lk.handle(), INFINITE);
|
|
#elif defined(FREERTOS)
|
|
xEventGroupClearBits(PRIVATE->nativeHandle, 1);
|
|
xEventGroupWaitBits(PRIVATE->nativeHandle, 1, pdTRUE, pdTRUE, portMAX_DELAY);
|
|
#else
|
|
pthread_cond_wait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle());
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
bool PIConditionVariable::waitFor(PIMutex &lk, int timeoutMs) {
|
|
bool isNotTimeout;
|
|
#if defined(WINDOWS)
|
|
isNotTimeout = SleepConditionVariableCS(&PRIVATE->nativeHandle, (PCRITICAL_SECTION)lk.handle(), timeoutMs) != 0;
|
|
#elif defined(FREERTOS)
|
|
xEventGroupClearBits(PRIVATE->nativeHandle, 1);
|
|
EventBits_t uxBits;
|
|
uxBits = xEventGroupWaitBits(PRIVATE->nativeHandle, 1, pdTRUE, pdTRUE, timeoutMs / portTICK_PERIOD_MS);
|
|
isNotTimeout = (uxBits & 1) != 0;
|
|
#else
|
|
timespec expire_ts;
|
|
PISystemTime st = PISystemTime::current(true);
|
|
st.addMilliseconds(timeoutMs);
|
|
st.toTimespec(&expire_ts);
|
|
isNotTimeout = pthread_cond_timedwait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle(), &expire_ts) == 0;
|
|
#endif
|
|
return isNotTimeout;
|
|
}
|
|
|
|
|
|
bool PIConditionVariable::waitFor(PIMutex& lk, int timeoutMs, const std::function<bool()> &condition) {
|
|
bool isCondition;
|
|
#if defined(WINDOWS) || defined(FREERTOS)
|
|
PITimeMeasurer measurer;
|
|
#else
|
|
timespec expire_ts;
|
|
PISystemTime st = PISystemTime::current(true);
|
|
st.addMilliseconds(timeoutMs);
|
|
st.toTimespec(&expire_ts);
|
|
#endif
|
|
#ifdef FREERTOS
|
|
xEventGroupClearBits(PRIVATE->nativeHandle, 1);
|
|
#endif
|
|
while (true) {
|
|
isCondition = condition();
|
|
if (isCondition) break;
|
|
bool isTimeout;
|
|
#if defined(WINDOWS)
|
|
isTimeout = SleepConditionVariableCS(
|
|
&PRIVATE->nativeHandle,
|
|
(PCRITICAL_SECTION)lk.handle(),
|
|
timeoutMs - (int)measurer.elapsed_m()) == 0;
|
|
#elif defined(FREERTOS)
|
|
EventBits_t uxBits;
|
|
uxBits = xEventGroupWaitBits(PRIVATE->nativeHandle, 1, pdTRUE, pdTRUE, (timeoutMs - (int)measurer.elapsed_m()) / portTICK_PERIOD_MS);
|
|
isTimeout = (uxBits & 1) == 0;
|
|
#else
|
|
isTimeout = pthread_cond_timedwait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle(), &expire_ts) != 0;
|
|
#endif
|
|
if (isTimeout) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
void PIConditionVariable::notifyOne() {
|
|
#if defined(WINDOWS)
|
|
WakeConditionVariable(&PRIVATE->nativeHandle);
|
|
#elif defined(FREERTOS)
|
|
xEventGroupSetBits(PRIVATE->nativeHandle, 1);
|
|
#else
|
|
pthread_cond_signal(&PRIVATE->nativeHandle);
|
|
#endif
|
|
}
|
|
|
|
|
|
void PIConditionVariable::notifyAll() {
|
|
#if defined(WINDOWS)
|
|
WakeAllConditionVariable(&PRIVATE->nativeHandle);
|
|
#elif defined(FREERTOS)
|
|
xEventGroupSetBits(PRIVATE->nativeHandle, 1);
|
|
#else
|
|
pthread_cond_broadcast(&PRIVATE->nativeHandle);
|
|
#endif
|
|
}
|
|
|