23 #ifndef CONDITIONVARIABLE_H
24 #define CONDITIONVARIABLE_H
33 #include <condition_variable>
36 #if defined(__APPLE__)
37 # define HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP 1
43 #if (AI_BUILD_TYPE == AI_RELEASE)
44 #define __ConditionVariableThrowOnError(err) \
47 #elif (AI_BUILD_TYPE == AI_DEBUG)
48 #define __ConditionVariableThrowOnError(err) \
50 if (__builtin_expect((err != 0), 0)) \
51 throw std::system_error(std::error_code(err, std::system_category())); \
55 #error Unknown AI build type
71 pthread_condattr_t attr;
72 pthread_condattr_init(&attr);
73 #if !defined(HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP)
74 pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
77 pthread_cond_init(&mCond, &attr);
79 pthread_condattr_destroy(&attr);
87 int err = pthread_cond_destroy(&mCond);
90 __ConditionVariableThrowOnError(err);
92 catch(
const std::system_error& exception)
94 AI_LOG_FATAL(
"Condition variable failed to be destroyed %s", exception.what());
101 int err = pthread_cond_signal(&mCond);
102 __ConditionVariableThrowOnError(err);
107 int err = pthread_cond_broadcast(&mCond);
108 __ConditionVariableThrowOnError(err);
112 struct timespec calcTimeoutAbs(const std::chrono::nanoseconds& rel_time)
115 clock_gettime(CLOCK_MONOTONIC, &ts);
117 ts.tv_sec += std::chrono::duration_cast<std::chrono::seconds>(rel_time).count();
118 ts.tv_nsec += (rel_time % std::chrono::seconds(1)).count();
120 if (ts.tv_nsec >= 1000000000L)
122 ts.tv_nsec -= 1000000000L;
125 else if (ts.tv_nsec < 0L)
129 ts.tv_nsec += 1000000000L;
136 struct timespec calcTimeoutRel(const std::chrono::nanoseconds& rel_time)
140 ts.tv_sec = std::chrono::duration_cast<std::chrono::seconds>(rel_time).count();
141 ts.tv_nsec = (rel_time % std::chrono::seconds(1)).count();
147 void wait(std::unique_lock<AICommon::Mutex>& lock)
149 int err = pthread_cond_wait(&mCond, lock.mutex()->native_handle());
150 __ConditionVariableThrowOnError(err);
153 template<
class Predicate>
154 void wait(std::unique_lock<AICommon::Mutex>& lock, Predicate pred)
158 int err = pthread_cond_wait(&mCond, lock.mutex()->native_handle());
159 __ConditionVariableThrowOnError(err);
164 template<
class Rep,
class Period>
165 std::cv_status wait_for(std::unique_lock<AICommon::Mutex>& lock,
166 const std::chrono::duration<Rep, Period>& rel_time)
168 if (rel_time.count() < 0)
170 AI_LOG_DEBUG(
"Negative wait period, timeout occured");
171 return std::cv_status::timeout;
173 #if defined(HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP)
174 const struct timespec ts = calcTimeoutRel(std::chrono::duration_cast<std::chrono::nanoseconds>(rel_time));
175 int err = pthread_cond_timedwait_relative_np(&mCond, lock.mutex()->native_handle(), &ts);
177 const struct timespec ts = calcTimeoutAbs(std::chrono::duration_cast<std::chrono::nanoseconds>(rel_time));
178 int err = pthread_cond_timedwait(&mCond, lock.mutex()->native_handle(), &ts);
182 return std::cv_status::no_timeout;
184 if (err == ETIMEDOUT)
186 return std::cv_status::timeout;
190 __ConditionVariableThrowOnError(err);
191 return std::cv_status::timeout;
195 template<
class Rep,
class Period,
class Predicate>
196 bool wait_for(std::unique_lock<AICommon::Mutex>& lock,
197 const std::chrono::duration<Rep, Period>& rel_time,
200 if (rel_time.count() < 0)
202 AI_LOG_DEBUG(
"Negative wait period, timeout occured");
205 #if defined(HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP)
206 const struct timespec ts = calcTimeoutRel(std::chrono::duration_cast<std::chrono::nanoseconds>(rel_time));
208 const struct timespec ts = calcTimeoutAbs(std::chrono::duration_cast<std::chrono::nanoseconds>(rel_time));
213 #if defined(HAS_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP)
214 int err = pthread_cond_timedwait_relative_np(&mCond, lock.mutex()->native_handle(), &ts);
216 int err = pthread_cond_timedwait(&mCond, lock.mutex()->native_handle(), &ts);
218 if (err == ETIMEDOUT)
224 AI_LOG_FATAL(
"Condition variable error in wait_for '%d'", err);
225 __ConditionVariableThrowOnError(err);
233 std::cv_status wait_until(std::unique_lock<AICommon::Mutex>& lock,
234 const std::chrono::time_point<std::chrono::steady_clock>& timeout_time)
236 auto rel_time = (timeout_time - std::chrono::steady_clock::now());
237 return wait_for(lock, rel_time);
240 template<
class Predicate>
241 bool wait_until(std::unique_lock<AICommon::Mutex>& lock,
242 const std::chrono::time_point<std::chrono::steady_clock>& timeout_time,
245 auto rel_time = (timeout_time - std::chrono::steady_clock::now());
246 return wait_for(lock, rel_time, pred);
250 typedef pthread_cond_t* native_handle_type;
251 native_handle_type native_handle()
257 pthread_cond_t mCond;
Definition: ConditionVariable.h:67