srsLTE/lib/include/srslte/srslog/detail/support/thread_utils.h

172 lines
4.1 KiB
C++

/**
*
* \section COPYRIGHT
*
* Copyright 2013-2020 Software Radio Systems Limited
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the distribution.
*
*/
#ifndef SRSLOG_DETAIL_SUPPORT_THREAD_UTILS_H
#define SRSLOG_DETAIL_SUPPORT_THREAD_UTILS_H
#include <pthread.h>
namespace srslog {
namespace detail {
//:TODO: these are temp helpers that will be replaced by std utils.
/// Abstraction of a pthread mutex.
class mutex
{
public:
mutex(const mutex&) = delete;
mutex& operator=(const mutex&) = delete;
mutex() { ::pthread_mutex_init(&m, nullptr); }
~mutex() { ::pthread_mutex_destroy(&m); }
/// Mutex lock.
void lock() { ::pthread_mutex_lock(&m); }
/// Mutex unlock.
void unlock() { ::pthread_mutex_unlock(&m); }
/// Mutex try lock. Returns true if the lock was obtained, false otherwise.
bool try_lock() { return (::pthread_mutex_trylock(&m) == 0); }
/// Accessor to the raw mutex structure.
pthread_mutex_t* raw() { return &m; }
const pthread_mutex_t* raw() const { return &m; }
private:
pthread_mutex_t m;
};
/// RAII style object for automatically locking and unlocking a mutex.
class scoped_lock
{
mutex& m;
public:
explicit scoped_lock(mutex& m) : m(m) { m.lock(); }
scoped_lock(const scoped_lock&) = delete;
scoped_lock& operator=(const scoped_lock&) = delete;
~scoped_lock() { m.unlock(); }
};
/// This class allows accessing and modifying data atomically.
template <typename T>
class shared_variable
{
T value;
mutable mutex m;
public:
shared_variable(const T& value) : value(value) {}
shared_variable(const shared_variable&) = delete;
shared_variable& operator=(const shared_variable&) = delete;
/// Set this shared variable to a new value guarded by the associated mutex.
shared_variable<T>& operator=(const T& other)
{
scoped_lock lock(m);
value = other;
return *this;
}
/// Get the value of this shared variable guarded by the associated mutex.
operator T() const
{
scoped_lock lock(m);
return value;
}
};
/// Abstraction of a pthread condition variable.
class condition_variable
{
public:
condition_variable() { ::pthread_cond_init(&cond_var, nullptr); }
condition_variable(const condition_variable&) = delete;
condition_variable& operator=(const condition_variable&) = delete;
~condition_variable() { ::pthread_cond_destroy(&cond_var); }
/// Internal mutex control.
void lock() { m.lock(); }
void unlock() { m.unlock(); }
/// Blocks the calling thread on this condition variable.
void wait() { ::pthread_cond_wait(&cond_var, m.raw()); }
/// Unblocks at least one waiting thread that is blocked on this condition
/// variable.
void signal() { ::pthread_cond_signal(&cond_var); }
/// Unblocks all waiting threads being blocked on this condition variable.
void broadcast() { ::pthread_cond_broadcast(&cond_var); }
/// Blocks the calling thread on this condition variable up to the specified
/// timeout. Returns true on timeout expiration, otherwise false.
bool wait(timespec ts)
{
return (::pthread_cond_timedwait(&cond_var, m.raw(), &ts) == ETIMEDOUT);
}
/// Builds an absolute time timespec structure adding the specified time out
/// in ms.
static timespec build_timeout(unsigned timeout_ms)
{
timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_sec += timeout_ms / 1000;
ts.tv_nsec += (timeout_ms % 1000) * 1000000;
if (ts.tv_nsec >= 1000000000) {
++ts.tv_sec;
ts.tv_nsec -= 1000000000;
}
return ts;
}
private:
mutable mutex m;
pthread_cond_t cond_var;
};
/// RAII style object for automatically locking and unlocking a condition
/// variable.
class cond_var_scoped_lock
{
condition_variable& cond_var;
public:
explicit cond_var_scoped_lock(condition_variable& cond_var) :
cond_var(cond_var)
{
cond_var.lock();
}
cond_var_scoped_lock(const cond_var_scoped_lock&) = delete;
cond_var_scoped_lock& operator=(const cond_var_scoped_lock&) = delete;
~cond_var_scoped_lock() { cond_var.unlock(); }
};
} // namespace detail
} // namespace srslog
#endif // SRSLOG_DETAIL_SUPPORT_THREAD_UTILS_H