Commit 8bce1e20 authored by Joseph Noir's avatar Joseph Noir

Add files for thread compatibility with RIOT

These headers implement thread, mutex and condition_variable
based on RIOT thread and mutex. A new configure option allows
a build for RIOT and uses these implementations instead of the
STL ones.
parent be24fb3c
...@@ -253,6 +253,8 @@ endif() ...@@ -253,6 +253,8 @@ endif()
if(CAF_FOR_RIOT) if(CAF_FOR_RIOT)
add_definitions(-D__RIOTBUILD_FLAG) add_definitions(-D__RIOTBUILD_FLAG)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32")
set(LD_FLAGS "${LD_FLAGS} -m32")
endif() endif()
...@@ -348,6 +350,12 @@ if (CAF_USE_ASIO) ...@@ -348,6 +350,12 @@ if (CAF_USE_ASIO)
endif() endif()
endif() endif()
# include files to build for RIOT
if(CAF_FOR_RIOT)
include_directories("${RIOT_BASE_DIR}/sys/include/.")
include_directories("${RIOT_BASE_DIR}/core/include/.")
include_directories("${RIOT_BASE_DIR}/cpu/native/include/.")
endif()
################################################################################ ################################################################################
# add subprojects # # add subprojects #
......
...@@ -50,7 +50,7 @@ Usage: $0 [OPTION]... [VAR=VALUE]... ...@@ -50,7 +50,7 @@ Usage: $0 [OPTION]... [VAR=VALUE]...
--no-auto-libc++ do not automatically enable libc++ for Clang --no-auto-libc++ do not automatically enable libc++ for Clang
--warnings-as-errors enables -Werror --warnings-as-errors enables -Werror
--with-asio enable ASIO multiplexer --with-asio enable ASIO multiplexer
--for-riot build CAF for riot --for-riot=DIR build CAF for riot
- uses RIOT thread impl - uses RIOT thread impl
- build without memory management - build without memory management
- static build only - static build only
...@@ -233,10 +233,11 @@ while [ $# -ne 0 ]; do ...@@ -233,10 +233,11 @@ while [ $# -ne 0 ]; do
--no-compiler-check) --no-compiler-check)
append_cache_entry CAF_NO_COMPILER_CHECK BOOL yes append_cache_entry CAF_NO_COMPILER_CHECK BOOL yes
;; ;;
--for-riot) --for-riot=*)
append_cache_entry CAF_FOR_RIOT BOOL yes append_cache_entry CAF_FOR_RIOT BOOL yes
append_cache_entry CAF_NO_MEM_MANAGEMENT BOOL yes append_cache_entry CAF_NO_MEM_MANAGEMENT BOOL yes
append_cache_entry CAF_BUILD_STATIC_ONLY STRING yes append_cache_entry CAF_BUILD_STATIC_ONLY STRING yes
append_cache_entry RIOT_BASE_DIR STRING $optarg
;; ;;
--no-auto-libc++) --no-auto-libc++)
append_cache_entry CAF_NO_AUTO_LIBCPP BOOL yes append_cache_entry CAF_NO_AUTO_LIBCPP BOOL yes
......
...@@ -84,6 +84,14 @@ set (LIBCAF_CORE_SRCS ...@@ -84,6 +84,14 @@ set (LIBCAF_CORE_SRCS
src/uniform_type_info.cpp src/uniform_type_info.cpp
src/uniform_type_info_map.cpp) src/uniform_type_info_map.cpp)
if (CAF_FOR_RIOT)
set (LIBCAF_CORE_SRCS
src/thread.cpp
src/mutex.cpp
src/condition_variable.cpp
${LIBCAF_CORE_SRCS})
endif()
add_custom_target(libcaf_core) add_custom_target(libcaf_core)
# build shared library if not compiling static only # build shared library if not compiling static only
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2014 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENCE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_CONDITION_VARIABLE_HPP
#define CAF_CONDITION_VARIABLE_HPP
#ifdef __RIOTBUILD_FLAG
#include <chrono>
#include "mutex.hpp"
namespace caf {
enum class cv_status { no_timeout, timeout };
class condition_variable {
public:
using native_handle_type = priority_queue_t*;
// constexpr condition_variable() : m_queue{NULL} { }
inline condition_variable() {
m_queue.first = NULL;
}
~condition_variable();
void notify_one() noexcept;
void notify_all() noexcept;
void wait(unique_lock<mutex>& lock) noexcept;
template <class Predicate>
void wait(unique_lock<mutex>& lock, Predicate pred);
template <class Clock, class Duration>
cv_status wait_until(unique_lock<mutex>& lock,
const std::chrono::time_point<Clock, Duration>& timeout_time);
template <class Clock, class Duration, class Predicate>
bool wait_until(unique_lock<mutex>& lock,
const std::chrono::time_point<Clock,Duration>& timeout_time,
Predicate pred);
template <class Rep, class Period>
cv_status wait_for(unique_lock<mutex>& lock,
const std::chrono::duration<Rep, Period>& rel_time);
template <class Rep, class Period, class Predicate>
bool wait_for(unique_lock<mutex>& lock,
const std::chrono::duration<Rep, Period>& rel_time,
Predicate pred);
inline native_handle_type native_handle() { return &m_queue; }
private:
condition_variable(const condition_variable&);
condition_variable& operator=(const condition_variable&);
void do_timed_wait(unique_lock<mutex>& lock,
std::chrono::time_point<std::chrono::system_clock,
std::chrono::nanoseconds>) noexcept;
priority_queue_t m_queue;
};
template <class T, class Rep, class Period>
inline typename std::enable_if<std::chrono::__is_duration<T>::value,T>::type
ceil(std::chrono::duration<Rep, Period> duration) {
using namespace std::chrono;
T res = duration_cast<T>(duration);
if (res < duration) {
++res;
}
return res;
}
template <class Predicate>
void condition_variable::wait(unique_lock<mutex>& lock, Predicate pred) {
while(!pred()) {
wait(lock);
}
}
template <class Clock, class Duration>
cv_status condition_variable::wait_until(unique_lock<mutex>& lock,
const std::chrono::time_point<Clock,
Duration>& timeout_time) {
wait_for(lock, timeout_time - Clock::now());
return Clock::now() < timeout_time ?
cv_status::no_timeout : cv_status::timeout;
}
template <class Clock, class Duration, class Predicate>
bool condition_variable::wait_until(unique_lock<mutex>& lock,
const std::chrono::time_point<Clock,Duration>& timeout_time,
Predicate pred) {
while (!pred()) {
if (wait_until(lock, timeout_time) == cv_status::timeout) {
return pred();
}
}
return true;
}
template <class Rep, class Period>
cv_status condition_variable::wait_for(unique_lock<mutex>& lock,
const std::chrono::duration<Rep, Period>& timeout_duration) {
using namespace std::chrono;
using std::chrono::duration;
if (timeout_duration <= timeout_duration.zero()) {
return cv_status::timeout;
}
typedef time_point<system_clock, duration<long double, std::nano>> __sys_tpf;
typedef time_point<system_clock, nanoseconds> __sys_tpi;
__sys_tpf _Max = __sys_tpi::max();
system_clock::time_point __s_now = system_clock::now();
steady_clock::time_point __c_now = steady_clock::now();
if (_Max - timeout_duration > __s_now) {
do_timed_wait(lock, __s_now + ceil<nanoseconds>(timeout_duration));
} else {
do_timed_wait(lock, __sys_tpi::max());
}
return steady_clock::now() - __c_now < timeout_duration ?
cv_status::no_timeout : cv_status::timeout;
}
template <class Rep, class Period, class Predicate>
inline bool condition_variable::wait_for(unique_lock<mutex>& lock,
const std::chrono::duration<Rep, Period>& timeout_duration,
Predicate pred) {
return wait_until(lock, std::chrono::steady_clock::now() + timeout_duration,
std::move(pred));
}
} // namespace caf
#else
#include <condition_variable>
using cv_status = std::cv_status;
using condition_variable = std::condition_variable;
#endif
#endif // CAF_CONDITION_VARIABLE_HPP
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2014 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENCE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_MUTEX_HPP
#define CAF_MUTEX_HPP
#ifdef __RIOTBUILD_FLAG
#include <utility>
#include <system_error>
#include <cstdio>
extern "C" {
#include "mutex.h"
}
namespace caf {
class mutex {
public:
using native_handle_type = mutex_t*;
inline constexpr mutex() noexcept : m_mtx{0, PRIORITY_QUEUE_INIT} { }
~mutex();
void lock();
bool try_lock() noexcept;
void unlock() noexcept;
inline native_handle_type native_handle() { return &m_mtx; }
private:
mutex(const mutex&);
mutex& operator=(const mutex&);
mutex_t m_mtx;
};
struct defer_lock_t {};
struct try_to_lock_t {};
struct adopt_lock_t {};
constexpr defer_lock_t defer_lock = defer_lock_t();
constexpr try_to_lock_t try_to_lock = try_to_lock_t();
constexpr adopt_lock_t adopt_lock = adopt_lock_t();
template<class Mutex>
class lock_guard {
public:
using mutex_type = Mutex;
inline explicit lock_guard(mutex_type& mtx) : m_mtx{mtx} { m_mtx.lock(); }
inline lock_guard(mutex_type& mtx, adopt_lock_t) : m_mtx{mtx} {}
inline ~lock_guard() { m_mtx.unlock(); }
private:
mutex_type& m_mtx;
};
template<class Mutex>
class unique_lock {
public:
using mutex_type = Mutex;
inline unique_lock() noexcept : m_mtx{nullptr}, m_owns{false} {}
inline explicit unique_lock(mutex_type& mtx) : m_mtx{&mtx}, m_owns{true} {
m_mtx->lock();
}
inline unique_lock(mutex_type& mtx, defer_lock_t) noexcept
: m_mtx{&mtx}, m_owns{false} { }
inline unique_lock(mutex_type& mtx, try_to_lock_t)
: m_mtx{&mtx}, m_owns{ mtx.try_lock() } { }
inline unique_lock(mutex_type& mtx, adopt_lock_t)
: m_mtx{&mtx}, m_owns{true} { }
template<class Clock, class Duration>
// inline unique_lock(mutex_type& mtx,
// const std::chrono::time_point<Clock,
// Duration>& timeout_time)
// : m_mtx{&mtx}, m_owns{mtx.try_lock_until(timeout_time)} { }
// template<class Rep, class Period>
// inline unique_lock(mutex_type& mtx,
// const chrono::duration<Rep,Period>& timeout_duration)
// : m_mtx{&mtx}, m_owns{mtx.try_lock_for(timeout_duration)} { }
// inline ~unique_lock() {
// if (m_owns) {
// m_mtx->unlock();
// }
// }
inline unique_lock(unique_lock&& lock) noexcept
: m_mtx{lock.m_mtx},
m_owns{lock.m_owns} {
lock.m_mtx = nullptr;
lock.m_owns = false;
}
inline unique_lock& operator=(unique_lock&& lock) noexcept {
if (m_owns) {
m_mtx->unlock();
}
m_mtx = lock.m_mtx;
m_owns = lock.m_owns;
lock.m_mtx = nullptr;
lock.m_owns = false;
return *this;
}
void lock();
bool try_lock();
// template <class Rep, class Period>
// bool try_lock_for(const chrono::duration<Rep, Period>& timeout_duration);
// template <class Clock, class Duration>
// bool try_lock_until(const chrono::time_point<Clock,Duration>& timeout_time);
void unlock();
inline void swap(unique_lock& lock) noexcept {
std::swap(m_mtx, lock.m_mtx);
std::swap(m_owns, lock.m_owns);
}
inline mutex_type* release() noexcept {
mutex_type* mtx = m_mtx;
m_mtx = nullptr;
m_owns = false;
return mtx;
}
inline bool owns_lock() const noexcept { return m_owns; }
inline explicit operator bool () const noexcept { return m_owns; }
inline mutex_type* mutex() const noexcept { return m_mtx; }
private:
unique_lock(unique_lock const&);
unique_lock& operator=(unique_lock const&);
mutex_type* m_mtx;
bool m_owns;
};
template<class Mutex>
void unique_lock<Mutex>::lock() {
if (m_mtx == nullptr) {
std::__throw_system_error(EPERM, "unique_lock::lock: references null mutex");
}
if (m_owns) {
std::__throw_system_error(EDEADLK, "unique_lock::lock: already locked");
}
m_mtx->lock();
m_owns = true;
}
template<class Mutex>
bool unique_lock<Mutex>::try_lock() {
if (m_mtx == nullptr) {
std::__throw_system_error(EPERM,
"unique_lock::try_lock: references null mutex");
}
if (m_owns) {
std::__throw_system_error(EDEADLK, "unique_lock::try_lock: already locked");
}
m_owns = m_mtx->try_lock();
return m_owns;
}
//template<class Mutex>
//template<class Rep, class Period>
//bool unique_lock<Mutex>
// ::try_lock_for(const std::chrono::duration<Rep,Period>& timeout_duration) {
// if (m_mtx == nullptr) {
// std::__throw_system_error(EPERM, "unique_lock::try_lock_for:"
// " references null mutex");
// }
// if (m_owns) {
// std::__throw_system_error(EDEADLK,
// "unique_lock::try_lock_for: already locked");
// }
// m_owns = m_mtx->try_lock_until(timeout_duration);
// return m_owns;
//}
//template <class Mutex>
//template <class Clock, class Duration>
//bool unique_lock<Mutex>
// ::try_lock_until(const chrono::time_point<Clock, Duration>& timeout_time) {
// if (m_mtx == nullptr)
// __throw_system_error(EPERM, "unique_lock::try_lock_until: "
// "references null mutex");
// if (m_owns)
// __throw_system_error(EDEADLK, "unique_lock::try_lock_until: "
// "already locked");
// m_owns = m_mtx->try_lock_until(timeout_time);
// return m_owns;
//}
template<class Mutex>
void unique_lock<Mutex>::unlock() {
if (!m_owns) {
std::__throw_system_error(EPERM, "unique_lock::unlock: not locked");
}
m_mtx->unlock();
m_owns = false;
}
template<class Mutex>
inline void swap(unique_lock<Mutex>& lhs, unique_lock<Mutex>& rhs) noexcept {
lhs.swap(rhs);
}
} // namespace caf
#else
#include <mutex>
namespace caf {
using mutex = std::mutex;
template <class Mutex> using lock_guard = std::lock_guard<Mutex>;
template <class Mutex> using unique_lock = std::unique_lock<Mutex>;
} // namespace caf
#endif
#endif // CAF_MUTEX_HPP
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2014 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENCE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_THREAD_HPP
#define CAF_THREAD_HPP
#include <time.h>
#ifdef __RIOTBUILD_FLAG
#include <tuple>
#include <chrono>
#include <utility>
#include <exception>
#include <functional>
#include <type_traits>
#include <system_error>
extern "C" {
#include "thread.h"
}
#include "mutex.hpp"
#include "condition_variable.hpp"
#include "thread_util.hpp"
#include "caf/detail/int_list.hpp"
#include "caf/detail/apply_args.hpp"
namespace caf {
namespace {
constexpr kernel_pid_t thread_uninitialized = -1;
}
class thread_id {
template <class T,class Traits>
friend std::basic_ostream<T,Traits>&
operator<<(std::basic_ostream<T,Traits>& out, thread_id id);
friend class thread;
public:
inline thread_id() noexcept : m_handle{thread_uninitialized} { }
inline thread_id(kernel_pid_t handle) : m_handle{handle} {}
inline bool operator==(thread_id other) noexcept {
return m_handle == other.m_handle;
}
inline bool operator!=(thread_id other) noexcept {
return !(m_handle == other.m_handle);
}
inline bool operator< (thread_id other) noexcept {
return m_handle < other.m_handle;
}
inline bool operator<=(thread_id other) noexcept {
return !(m_handle > other.m_handle);
}
inline bool operator> (thread_id other) noexcept {
return m_handle > other.m_handle;
}
inline bool operator>=(thread_id other) noexcept {
return !(m_handle < other.m_handle);
}
private:
kernel_pid_t m_handle;
};
template <class T,class Traits>
inline std::basic_ostream<T,Traits>&
operator<<(std::basic_ostream<T,Traits>& out, thread_id id) {
return out << id.m_handle;
}
namespace this_thread {
inline thread_id get_id() noexcept { return thread_getpid(); }
inline void yield() noexcept { thread_yield(); }
void sleep_for(const std::chrono::nanoseconds& ns);
template <class Rep, class Period>
void sleep_for(const std::chrono::duration<Rep, Period>& sleep_duration) {
using namespace std::chrono;
if (sleep_duration > std::chrono::duration<Rep, Period>::zero()) {
constexpr std::chrono::duration<long double> max = nanoseconds::max();
nanoseconds ns;
if (sleep_duration < max) {
ns = duration_cast<nanoseconds>(sleep_duration);
if (ns < sleep_duration) {
++ns;
}
}
else {
ns = nanoseconds::max();
}
sleep_for(ns);
}
}
template <class Clock, class Period>
void sleep_until(const std::chrono::time_point<Clock, Period>& sleep_time) {
using namespace std::chrono;
mutex mtx;
condition_variable cv;
unique_lock<mutex> lk(mtx);
while(Clock::now() < sleep_time) {
cv.wait_until(lk,sleep_time);
}
}
template <class Period>
inline void sleep_until(const std::chrono::time_point<std::chrono::steady_clock,
Period>& sleep_time) {
sleep_for(sleep_time - std::chrono::steady_clock::now());
}
} // namespace this_thread
class thread {
public:
using id = thread_id;
using native_handle_type = kernel_pid_t;
inline thread() noexcept : m_handle{thread_uninitialized} { }
template <class F, class ...Args,
class = typename std::enable_if<
!std::is_same<typename std::decay<F>::type,thread>::value
>::type
>
explicit thread(F&& f, Args&&... args);
~thread();
thread(const thread&) = delete;
inline thread(thread&& t) noexcept : m_handle{t.m_handle} {
t.m_handle = thread_uninitialized;
}
thread& operator=(const thread&) = delete;
thread& operator=(thread&&) noexcept;
void swap(thread& t) noexcept { std::swap(m_handle, t.m_handle); }
inline bool joinable() const noexcept { return false; }
void join();
void detach();
inline id get_id() const noexcept { return m_handle; }
inline native_handle_type native_handle() noexcept { return m_handle; }
static unsigned hardware_concurrency() noexcept;
kernel_pid_t m_handle;
char m_stack[KERNEL_CONF_STACKSIZE_MAIN];
};
void swap(thread& lhs, thread& rhs) noexcept;
template <class F>
void* thread_proxy(void* vp) {
std::unique_ptr<F> p(static_cast<F*>(vp));
auto indices =
detail::get_right_indices<caf::detail::tl_size<F>::value - 1>(*p);
detail::apply_args(std::get<0>(*p), indices, *p);
return nullptr;
}
template <class F, class ...Args,
class
>
thread::thread(F&& f, Args&&... args) {
using namespace std;
using func_and_args = tuple<typename decay<F>::type,
typename decay<Args>::type...>;
std::unique_ptr<func_and_args> p(new func_and_args(decay_copy(forward<F>(f)),
decay_copy(forward<Args>(args))...));
m_handle = thread_create(m_stack, sizeof(m_stack),
PRIORITY_MAIN - 1, 0, // CREATE_WOUT_YIELD
&thread_proxy<func_and_args>,
p.get(), "caf_thread");
if (m_handle >= 0) {
p.release();
} else {
std::__throw_system_error(static_cast<int>(m_handle),
"Failed to create thread.");
}
}
inline thread& thread::operator=(thread&& other) noexcept {
if (m_handle != 0) {
std::terminate();
}
m_handle = other.m_handle;
other.m_handle = 0;
return *this;
}
inline void swap (thread& lhs, thread& rhs) noexcept {
lhs.swap(rhs);
}
} // namespace caf
#else
#include <thread>
namespace caf {
using thread = std::thread;
namespace this_thread {
using std::this_thread::get_id;
// GCC hack
#if !defined(_GLIBCXX_USE_SCHED_YIELD) && !defined(__clang__)
inline void yield() noexcept {
timespec req;
req.tv_sec = 0;
req.tv_nsec = 1;
nanosleep(&req, nullptr);
}
#else
using std::this_thread::yield;
#endif
// another GCC hack
#if !defined(_GLIBCXX_USE_NANOSLEEP) && !defined(__clang__)
template <class Rep, typename Period>
inline void sleep_for(const chrono::duration<Rep, Period>& rt) {
auto sec = chrono::duration_cast<chrono::seconds>(rt);
auto nsec = chrono::duration_cast<chrono::nanoseconds>(rt - sec);
timespec req;
req.tv_sec = sec.count();
req.tv_nsec = nsec.count();
nanosleep(&req, nullptr);
}
#else
using std::this_thread::sleep_for;
#endif
} // namespace this_thread
} // namespace caf
#endif
#endif // CAF_THREAD_HPP
#ifndef CAF_THREAD_UTILS_HPP
#define CAF_THREAD_UTILS_HPP
#include <utility>
// decay copy (from clang type_traits)
template <class T>
inline typename std::decay<T>::type decay_copy(T&& t) {
return std::forward<T>(t);
}
#endif // CAF_THREAD_UTILS_HPP
#include <system_error>
extern "C" {
#include "irq.h"
#include "vtimer.h"
#include "sched.h"
}
#include "caf/condition_variable.hpp"
using namespace std::chrono;
namespace caf {
condition_variable::~condition_variable() {
m_queue.first = NULL;
}
void condition_variable::notify_one() noexcept {
printf("notify_one start\n");
unsigned old_state = disableIRQ();
priority_queue_node_t *head = priority_queue_remove_head(&m_queue);
int other_prio = -1;
if (head != NULL) {
printf("notify_one -> head is not NULL\n");
tcb_t *other_thread = (tcb_t *) sched_threads[head->data];
if (other_thread) {
printf("notify_one -> other thread exists\n");
other_prio = other_thread->priority;
sched_set_status(other_thread, STATUS_PENDING);
}
head->data = -1u;
}
restoreIRQ(old_state);
printf("notify_one -> restored irq\n");
if (other_prio >= 0) {
printf("notify_one -> sched_switch incoming\n");
sched_switch(other_prio);
printf("notify_one -> sched_switch called\n");
}
printf("notify_one end\n");
}
void condition_variable::notify_all() noexcept {
unsigned old_state = disableIRQ();
int other_prio = -1;
while (true) {
priority_queue_node_t *head = priority_queue_remove_head(&m_queue);
if (head == NULL) {
break;
}
tcb_t *other_thread = (tcb_t *) sched_threads[head->data];
if (other_thread) {
auto max_prio = [](int a, int b) {
return (a < 0) ? b : ((a < b) ? a : b);
};
other_prio = max_prio(other_prio, other_thread->priority);
sched_set_status(other_thread, STATUS_PENDING);
}
head->data = -1u;
}
restoreIRQ(old_state);
if (other_prio >= 0) {
sched_switch(other_prio);
}
}
void condition_variable::wait(unique_lock<mutex>& lock) noexcept {
if (!lock.owns_lock()) {
std::__throw_system_error(EPERM,
"condition_variable::wait: mutex not locked");
}
priority_queue_node_t n;
n.priority = sched_active_thread->priority;
n.data = sched_active_pid;
n.next = NULL;
/* the signaling thread may not hold the mutex, the queue is not thread safe */
unsigned old_state = disableIRQ();
priority_queue_add(&m_queue, &n);
restoreIRQ(old_state);
mutex_unlock_and_sleep(lock.mutex()->native_handle());
if (n.data != -1u) {
/* on signaling n.data is set to -1u */
/* if it isn't set, then the wakeup is either spurious or a timer wakeup */
old_state = disableIRQ();
priority_queue_remove(&m_queue, &n);
restoreIRQ(old_state);
}
mutex_lock(lock.mutex()->native_handle());
}
void condition_variable::do_timed_wait(unique_lock<mutex>& lock,
time_point<system_clock,
nanoseconds> tp) noexcept {
if (!lock.owns_lock()) {
std::__throw_system_error(EPERM,
"condition_variable::timed wait: mutex not locked");
}
nanoseconds d = tp.time_since_epoch();
if (d > nanoseconds(0x59682F000000E941)) {
d = nanoseconds(0x59682F000000E941);
}
timespec ts;
seconds s = duration_cast<seconds>(d);
typedef decltype(ts.tv_sec) ts_sec;
constexpr ts_sec ts_sec_max = std::numeric_limits<ts_sec>::max();
if (s.count() < ts_sec_max) {
ts.tv_sec = static_cast<ts_sec>(s.count());
ts.tv_nsec = static_cast<decltype(ts.tv_nsec)>((d - s).count());
} else {
ts.tv_sec = ts_sec_max;
ts.tv_nsec = std::giga::num - 1;
}
// auto rc = pthread_cond_timedwait(&cond, lock.mutex()->native_handle(), &ts);
timex_t now, then, reltime;
vtimer_now(&now);
then.seconds = ts.tv_sec;
then.microseconds = ts.tv_nsec / 1000u;
reltime = timex_sub(then, now);
vtimer_t timer;
vtimer_set_wakeup(&timer, reltime, sched_active_pid);
wait(lock);
// priority_queue_node_t n;
// n.priority = sched_active_thread->priority;
// n.data = sched_active_pid;
// n.next = NULL;
// /* the signaling thread may not hold the mutex, the queue is not thread safe */
// unsigned old_state = disableIRQ();
// priority_queue_add(&m_queue), &n);
// restoreIRQ(old_state);
// mutex_unlock_and_sleep(&m_queue);
// if (n.data != -1u) {
// /* on signaling n.data is set to -1u */
// /* if it isn't set, then the wakeup is either spurious or a timer wakeup */
// old_state = disableIRQ();
// priority_queue_remove(&m_queue, &n);
// restoreIRQ(old_state);
// }
// mutex_lock(mutex);
vtimer_remove(&timer);
}
} // namespace caf
#include "caf/mutex.hpp"
namespace caf {
// const defer_lock_t defer_lock = {};
// const try_to_lock_t try_to_lock = {};
// const adopt_lock_t adopt_lock = {};
mutex::~mutex() {
// nop
}
void mutex::lock() {
mutex_lock(&m_mtx);
}
bool mutex::try_lock() noexcept {
return (1 == mutex_trylock(&m_mtx));
}
void mutex::unlock() noexcept {
mutex_unlock(&m_mtx);
}
} // namespace caf
#include <time.h>
#include "caf/thread.hpp"
namespace caf {
thread::~thread() {
// not needed, as our thread is always detachted
}
void thread::join() {
// you can't join threads
}
void thread::detach() {
// I believe there is no equivalent on RIOT
}
unsigned thread::hardware_concurrency() noexcept {
// embedded systems often do not have more cores
// RIOT does currently not ofter these informations
return 1;
}
namespace this_thread {
void sleep_for(const std::chrono::nanoseconds& ns) {
using namespace std::chrono;
if (ns > nanoseconds::zero()) {
seconds s = duration_cast<seconds>(ns);
timespec ts;
using ts_sec = decltype(ts.tv_sec);
// typedef decltype(ts.tv_sec) ts_sec;
constexpr ts_sec ts_sec_max = std::numeric_limits<ts_sec>::max();
if (s.count() < ts_sec_max) {
ts.tv_sec = static_cast<ts_sec>(s.count());
ts.tv_nsec = static_cast<decltype(ts.tv_nsec)>((ns-s).count());
} else {
ts.tv_sec = ts_sec_max;
ts.tv_nsec = std::giga::num - 1;
}
while (nanosleep(&ts, &ts) == -1 && errno == EINTR) { ; }
}
}
} // namespace this_thread
} // namespace caf
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment