/* 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 . */ #include "piconditionvar.h" #include "pithread.h" #include "pitime.h" #include "piincludes_p.h" #ifdef WINDOWS # undef _WIN32_WINNT # define _WIN32_WINNT 0x0600 # include # include # include #endif #ifdef FREERTOS # include #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& 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 &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 }