/* 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 "piplatform.h" #ifdef WINDOWS # undef _WIN32_WINNT # define _WIN32_WINNT 0x0600 #endif #ifdef PIP_HAS_THREADS # include "piconditionvar.h" # include "piincludes_p.h" # ifdef WINDOWS # 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 piZeroMemory(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, std::function condition) { while (true) { if (condition()) 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, PISystemTime timeout) { bool isNotTimeout; # if defined(WINDOWS) isNotTimeout = SleepConditionVariableCS(&PRIVATE->nativeHandle, (PCRITICAL_SECTION)lk.handle(), timeout.toMilliseconds()) != 0; # elif defined(FREERTOS) xEventGroupClearBits(PRIVATE->nativeHandle, 1); EventBits_t uxBits; uxBits = xEventGroupWaitBits(PRIVATE->nativeHandle, 1, pdTRUE, pdTRUE, timeout.toMilliseconds() / portTICK_PERIOD_MS); isNotTimeout = (uxBits & 1) != 0; # else PISystemTime st = PISystemTime::current(true) + timeout; timespec expire_ts; 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, PISystemTime timeout, std::function condition) { # if defined(WINDOWS) || defined(FREERTOS) PITimeMeasurer measurer; # else PISystemTime st = PISystemTime::current(true) + timeout; timespec expire_ts; st.toTimespec(&expire_ts); # endif # ifdef FREERTOS xEventGroupClearBits(PRIVATE->nativeHandle, 1); # endif while (true) { if (condition()) break; bool isTimeout; # if defined(WINDOWS) { int remain = (int)(timeout.toMilliseconds() - (int)measurer.elapsed_m()); if (remain <= 0) return false; isTimeout = SleepConditionVariableCS(&PRIVATE->nativeHandle, (PCRITICAL_SECTION)lk.handle(), remain) == 0; } # elif defined(FREERTOS) { int remain = (int)(timeout.toMilliseconds() - (int)measurer.elapsed_m()); if (remain <= 0) return false; EventBits_t uxBits; uxBits = xEventGroupWaitBits(PRIVATE->nativeHandle, 1, pdTRUE, pdTRUE, remain / 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 } #endif // PIP_HAS_THREADS