Files
pip/lib/main/thread/piconditionvar.cpp
Ivan Pelipenko 2ffc457566 merged concurrent to main library
removed PIConditionLock, use PIMutex instead
2020-07-30 18:50:42 +03:00

142 lines
3.8 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 "piconditionvar.h"
#include "pithread.h"
#include "pitime.h"
#ifdef WINDOWS
# undef _WIN32_WINNT
# define _WIN32_WINNT 0x0600
# include <synchapi.h>
# include <windef.h>
# include <winbase.h>
#endif
PRIVATE_DEFINITION_START(PIConditionVariable)
#ifdef WINDOWS
CONDITION_VARIABLE nativeHandle;
#else
pthread_cond_t nativeHandle;
PIMutex * currentLock;
#endif
bool isDestroying;
PRIVATE_DEFINITION_END(PIConditionVariable)
PIConditionVariable::PIConditionVariable() {
#ifdef WINDOWS
InitializeConditionVariable(&PRIVATE->nativeHandle);
#else
PRIVATE->isDestroying = false;
PRIVATE->currentLock = nullptr;
memset(&(PRIVATE->nativeHandle), 0, sizeof(PRIVATE->nativeHandle));
pthread_cond_init(&PRIVATE->nativeHandle, NULL);
#endif
}
PIConditionVariable::~PIConditionVariable() {
#ifdef WINDOWS
#else
pthread_cond_destroy(&PRIVATE->nativeHandle);
#endif
}
void PIConditionVariable::wait(PIMutex& lk) {
#ifdef WINDOWS
SleepConditionVariableCS(&PRIVATE->nativeHandle, (PCRITICAL_SECTION)lk.handle(), INFINITE);
#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;
#ifdef WINDOWS
SleepConditionVariableCS(&PRIVATE->nativeHandle, (PCRITICAL_SECTION)lk.handle(), INFINITE);
#else
pthread_cond_wait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle());
#endif
if (PRIVATE->isDestroying) return;
}
}
bool PIConditionVariable::waitFor(PIMutex &lk, int timeoutMs) {
bool isNotTimeout;
#ifdef WINDOWS
isNotTimeout = SleepConditionVariableCS(&PRIVATE->nativeHandle, (PCRITICAL_SECTION)lk.handle(), timeoutMs) != 0;
#else
timespec abstime = {.tv_sec = timeoutMs / 1000, .tv_nsec = timeoutMs * 1000 * 1000};
isNotTimeout = pthread_cond_timedwait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle(), &abstime) == 0;
#endif
if (PRIVATE->isDestroying) return false;
return isNotTimeout;
}
bool PIConditionVariable::waitFor(PIMutex& lk, int timeoutMs, const std::function<bool()> &condition) {
bool isCondition;
PITimeMeasurer measurer;
while (true) {
isCondition = condition();
if (isCondition) break;
#ifdef WINDOWS
WINBOOL isTimeout = SleepConditionVariableCS(
&PRIVATE->nativeHandle,
(PCRITICAL_SECTION)lk.handle(),
timeoutMs - (int)measurer.elapsed_m());
if (isTimeout == 0) return false;
#else
int timeoutCurr = timeoutMs - (int)measurer.elapsed_m();
timespec abstime = {.tv_sec = timeoutCurr / 1000, .tv_nsec = timeoutCurr * 1000 * 1000};
bool isTimeout = pthread_cond_timedwait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle(), &abstime) == 0;
if (isTimeout) return false;
#endif
if (PRIVATE->isDestroying) return false;
}
return true;
}
void PIConditionVariable::notifyOne() {
#ifdef WINDOWS
WakeConditionVariable(&PRIVATE->nativeHandle);
#else
pthread_cond_signal(&PRIVATE->nativeHandle);
#endif
}
void PIConditionVariable::notifyAll() {
#ifdef WINDOWS
WakeAllConditionVariable(&PRIVATE->nativeHandle);
#else
pthread_cond_broadcast(&PRIVATE->nativeHandle);
#endif
}