Threads: Add initial Actor implementation, rework primitivethread a bit.
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
6f7756e1cb
commit
ea474dd915
102
Threads/Inc/threads_actor.hpp
Normal file
102
Threads/Inc/threads_actor.hpp
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* threads_actor.hpp
|
||||
*
|
||||
* Created on: Jun 11, 2021
|
||||
* Author: erki
|
||||
*/
|
||||
|
||||
#ifndef SKULLC_THREADS_ACTOR_HPP_
|
||||
#define SKULLC_THREADS_ACTOR_HPP_
|
||||
|
||||
#include <queue.h>
|
||||
#include <type_traits>
|
||||
|
||||
#include "threads_primitivethread.hpp"
|
||||
#include "threads_signal.hpp"
|
||||
|
||||
namespace Threads
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
class Actor
|
||||
{
|
||||
public:
|
||||
using value_type = T;
|
||||
|
||||
static_assert(std::is_trivially_constructible_v<value_type>, "T must be trivially constructible.");
|
||||
static_assert(std::is_trivially_copyable_v<value_type>, "T must be trivially copyable.");
|
||||
|
||||
Actor(const std::uint32_t queue_size, const char* name, const osPriority_t priority, const std::uint32_t stack_size)
|
||||
: thread_([](void* d) {
|
||||
auto* dd = static_cast<Actor<T>*>(d);
|
||||
(*dd)();
|
||||
},
|
||||
this, name, priority, stack_size),
|
||||
msg_queue_(xQueueCreate(queue_size, sizeof(value_type))), signal_(*this)
|
||||
{
|
||||
assert(msg_queue_);
|
||||
}
|
||||
|
||||
Signallable<T>* getSignal()
|
||||
{
|
||||
return &signal_;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void init() = 0;
|
||||
virtual void onSignal(const T& data) = 0;
|
||||
|
||||
private:
|
||||
PrimitiveThread thread_;
|
||||
QueueHandle_t msg_queue_;
|
||||
|
||||
void operator()()
|
||||
{
|
||||
init();
|
||||
|
||||
value_type data;
|
||||
|
||||
while (true)
|
||||
{
|
||||
const BaseType_t got = xQueueReceive(msg_queue_, &data, portMAX_DELAY);
|
||||
|
||||
if (got)
|
||||
{
|
||||
onSignal(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
friend struct Signal_;
|
||||
|
||||
struct Signal_ : Signallable<value_type>
|
||||
{
|
||||
using parent = Actor<T>;
|
||||
parent& q;
|
||||
|
||||
explicit Signal_(parent& q)
|
||||
: q(q)
|
||||
{}
|
||||
|
||||
bool emit(const value_type& data) override
|
||||
{
|
||||
const BaseType_t success = xQueueSend(q.msg_queue_, &data, 0);
|
||||
return success == pdTRUE;
|
||||
}
|
||||
|
||||
std::pair<bool, BaseType_t> emitFromIsr(const value_type& data) override
|
||||
{
|
||||
BaseType_t was_awoken = pdFALSE;
|
||||
const BaseType_t success = xQueueSendFromISR(q.msg_queue_, &data, &was_awoken);
|
||||
|
||||
return {success == pdTRUE, was_awoken};
|
||||
}
|
||||
};
|
||||
|
||||
Signal_ signal_;
|
||||
};
|
||||
|
||||
}// namespace Threads
|
||||
|
||||
|
||||
#endif /* SKULLC_THREADS_ACTOR_HPP_ */
|
||||
@ -14,12 +14,14 @@
|
||||
#include <type_traits>
|
||||
|
||||
#include "threads_primitivethread.hpp"
|
||||
#include "threads_signal.hpp"
|
||||
|
||||
namespace Threads
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
class ExclusiveSignal
|
||||
class ExclusiveSignal : public Signallable<T>
|
||||
, public Awaitable<std::optional<T>>
|
||||
{
|
||||
public:
|
||||
using value_type = T;
|
||||
@ -29,9 +31,8 @@ public:
|
||||
std::is_trivially_copyable_v<value_type>, "Signal's value must be trivially copyable.");
|
||||
|
||||
ExclusiveSignal()
|
||||
: current_value_(std::nullopt)
|
||||
, waiting_thread_(std::nullopt)
|
||||
{ }
|
||||
: current_value_(std::nullopt), waiting_thread_(std::nullopt)
|
||||
{}
|
||||
|
||||
ExclusiveSignal(const ExclusiveSignal&) = delete;
|
||||
ExclusiveSignal(ExclusiveSignal&&) = delete;
|
||||
@ -39,23 +40,23 @@ public:
|
||||
ExclusiveSignal& operator=(ExclusiveSignal&&) = delete;
|
||||
|
||||
#ifdef INCLUDE_xTaskGetCurrentTaskHandle
|
||||
result_type wait()
|
||||
result_type await() override
|
||||
{
|
||||
return wait(PrimitiveThread::getCurrentThread());
|
||||
return await(PrimitiveThread::getCurrentThread());
|
||||
}
|
||||
|
||||
result_type wait(const long timeout)
|
||||
result_type await(const long timeout) override
|
||||
{
|
||||
return wait(PrimitiveThread::getCurrentThread(), timeout);
|
||||
return await(PrimitiveThread::getCurrentThread(), timeout);
|
||||
}
|
||||
#endif
|
||||
|
||||
result_type wait(const PrimitiveThread& currentThread)
|
||||
result_type await(const PrimitiveThread& currentThread) override
|
||||
{
|
||||
return wait(currentThread, portMAX_DELAY);
|
||||
return await(currentThread, portMAX_DELAY);
|
||||
}
|
||||
|
||||
result_type wait(const PrimitiveThread& currentThread, const long timeout)
|
||||
result_type await(const PrimitiveThread& currentThread, const long timeout) override
|
||||
{
|
||||
waiting_thread_ = currentThread;
|
||||
|
||||
@ -64,41 +65,56 @@ public:
|
||||
if (!notified)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
else
|
||||
} else
|
||||
{
|
||||
return current_value_;
|
||||
}
|
||||
}
|
||||
|
||||
bool emit(const result_type& v)
|
||||
bool emit(const value_type& v) override
|
||||
{
|
||||
current_value_ = v;
|
||||
|
||||
if (!waiting_thread_)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
} else
|
||||
{
|
||||
return waiting_thread_->notify(0, eNoAction);
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<bool, BaseType_t> emitFromIsr(const value_type& v) override
|
||||
{
|
||||
current_value_ = v;
|
||||
|
||||
if (!waiting_thread_)
|
||||
{
|
||||
return {false, pdFALSE};
|
||||
} else
|
||||
{
|
||||
auto const [discard, was_notified] = waiting_thread_->notifyFromIsr(0, eNoAction);
|
||||
(void) discard;
|
||||
|
||||
return {true, was_notified};
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
result_type current_value_;
|
||||
std::optional<PrimitiveThread> waiting_thread_;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ExclusiveSignal<void>
|
||||
struct ExclusiveSignal<void> : public Signallable<void>
|
||||
, public Awaitable<bool>
|
||||
{
|
||||
using value_type = void;
|
||||
using result_type = bool;
|
||||
|
||||
ExclusiveSignal()
|
||||
: waiting_thread_(std::nullopt)
|
||||
{ }
|
||||
{}
|
||||
|
||||
ExclusiveSignal(const ExclusiveSignal&) = delete;
|
||||
ExclusiveSignal(ExclusiveSignal&&) = delete;
|
||||
@ -106,45 +122,58 @@ struct ExclusiveSignal<void>
|
||||
ExclusiveSignal& operator=(ExclusiveSignal&&) = delete;
|
||||
|
||||
#ifdef INCLUDE_xTaskGetCurrentTaskHandle
|
||||
result_type wait()
|
||||
result_type await() override
|
||||
{
|
||||
return wait(PrimitiveThread::getCurrentThread());
|
||||
return await(PrimitiveThread::getCurrentThread());
|
||||
}
|
||||
|
||||
result_type wait(const long timeout)
|
||||
result_type await(const long timeout) override
|
||||
{
|
||||
return wait(PrimitiveThread::getCurrentThread(), timeout);
|
||||
return await(PrimitiveThread::getCurrentThread(), timeout);
|
||||
}
|
||||
#endif
|
||||
|
||||
result_type wait(PrimitiveThread currentThread)
|
||||
result_type await(const PrimitiveThread& currentThread) override
|
||||
{
|
||||
return wait(currentThread, portMAX_DELAY);
|
||||
return await(currentThread, portMAX_DELAY);
|
||||
}
|
||||
|
||||
result_type wait(PrimitiveThread currentThread, const long timeout)
|
||||
result_type await(const PrimitiveThread& currentThread, const long timeout) override
|
||||
{
|
||||
waiting_thread_ = currentThread;
|
||||
return currentThread.notifyWait(timeout);
|
||||
}
|
||||
|
||||
bool emit()
|
||||
bool emit() override
|
||||
{
|
||||
if (!waiting_thread_)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
} else
|
||||
{
|
||||
return waiting_thread_->notify(0, eNoAction);
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<bool, BaseType_t> emitFromIsr() override
|
||||
{
|
||||
if (!waiting_thread_)
|
||||
{
|
||||
return {false, pdFALSE};
|
||||
} else
|
||||
{
|
||||
auto const [discard, was_notified] = waiting_thread_->notifyFromIsr(0, eNoAction);
|
||||
(void) discard;
|
||||
|
||||
return {true, was_notified};
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::optional<PrimitiveThread> waiting_thread_;
|
||||
};
|
||||
|
||||
}
|
||||
}// namespace Threads
|
||||
|
||||
|
||||
#endif /* SKULLC_THREADS_EXCLUSIVESIGNAL_HPP_ */
|
||||
|
||||
@ -11,8 +11,8 @@
|
||||
#include <cmsis_os.h>
|
||||
#include <freertos_os2.h>
|
||||
|
||||
#include <type_traits>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
namespace Threads
|
||||
{
|
||||
@ -26,6 +26,15 @@ public:
|
||||
PrimitiveThread& operator=(const PrimitiveThread&) = default;
|
||||
PrimitiveThread& operator=(PrimitiveThread&&) = default;
|
||||
|
||||
explicit PrimitiveThread(osThreadFunc_t function, void* runner_data, const osThreadAttr_t& attrs);
|
||||
|
||||
template<typename F>
|
||||
PrimitiveThread(F runner, void* runner_data, const char* name, const osPriority_t priority, const std::uint32_t stack_size)
|
||||
: PrimitiveThread(runner, runner_data, constructThreadAttrs_(name, priority, stack_size))
|
||||
{
|
||||
static_assert(std::is_convertible_v<F, osThreadFunc_t>, "Run function F is not convertible to osThreadFunc_t (void (void*)).");
|
||||
}
|
||||
|
||||
osThreadId_t thread_id;
|
||||
osThreadAttr_t attributes;
|
||||
|
||||
@ -55,17 +64,9 @@ public:
|
||||
[[nodiscard]] bool notifyWait(const TickType_t delay) const;
|
||||
[[nodiscard]] std::pair<bool, unsigned long> notifyWait(const TickType_t delay, const unsigned long set_on_entry, const unsigned long set_on_exit) const;
|
||||
|
||||
protected:
|
||||
explicit PrimitiveThread(osThreadFunc_t function, const osThreadAttr_t& attrs);
|
||||
|
||||
template<typename F>
|
||||
PrimitiveThread(F runner, const char* name, const osPriority_t priority, const std::uint32_t stack_size)
|
||||
: PrimitiveThread(runner, constructThreadAttrs_(name, priority, stack_size))
|
||||
{
|
||||
static_assert(std::is_convertible_v<F, osThreadFunc_t>, "Run function F is not convertible to osThreadFunc_t (void (void*)).");
|
||||
}
|
||||
|
||||
private:
|
||||
void* runner_data_ = nullptr;
|
||||
|
||||
explicit PrimitiveThread(TaskHandle_t threadHandle);
|
||||
osThreadAttr_t constructThreadAttrs_(const char* name, const osPriority_t priority, const std::uint32_t stack_size);
|
||||
};
|
||||
@ -78,7 +79,7 @@ inline bool operator==(const PrimitiveThread& lhs, const PrimitiveThread& rhs)
|
||||
return lhs.thread_id == rhs.thread_id;
|
||||
}
|
||||
|
||||
}
|
||||
}// namespace Threads
|
||||
|
||||
|
||||
#endif /* SKULLC_THREADS_PRIMITIVETHREAD_HPP_ */
|
||||
|
||||
54
Threads/Inc/threads_signal.hpp
Normal file
54
Threads/Inc/threads_signal.hpp
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* threads_signal.hpp
|
||||
*
|
||||
* Created on: Jun 20, 2021
|
||||
* Author: erki
|
||||
*/
|
||||
|
||||
#ifndef THREADS_INC_THREADS_SIGNAL_HPP_
|
||||
#define THREADS_INC_THREADS_SIGNAL_HPP_
|
||||
|
||||
#include <FreeRTOSConfig.h>
|
||||
|
||||
namespace Threads
|
||||
{
|
||||
|
||||
class PrimitiveThread;
|
||||
|
||||
template<typename T>
|
||||
struct Signallable
|
||||
{
|
||||
using value_type = T;
|
||||
|
||||
static_assert(std::is_trivially_constructible_v<value_type>, "T must be trivially constructible.");
|
||||
|
||||
virtual bool emit(const T& t) = 0;
|
||||
virtual std::pair<bool, BaseType_t> emitFromIsr(const T& t) = 0;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Signallable<void>
|
||||
{
|
||||
using value_type = void;
|
||||
|
||||
virtual bool emit() = 0;
|
||||
virtual std::pair<bool, BaseType_t> emitFromIsr() = 0;
|
||||
};
|
||||
|
||||
template<typename R>
|
||||
struct Awaitable
|
||||
{
|
||||
using result_type = R;
|
||||
|
||||
#ifdef INCLUDE_xTaskGetCurrentTaskHandle
|
||||
virtual result_type await() = 0;
|
||||
virtual result_type await(const long timeout) = 0;
|
||||
#endif
|
||||
|
||||
virtual result_type await(const PrimitiveThread& currentThread) = 0;
|
||||
virtual result_type await(const PrimitiveThread& currentThread, const long timeout) = 0;
|
||||
};
|
||||
|
||||
}// namespace Threads
|
||||
|
||||
#endif /* THREADS_INC_THREADS_SIGNAL_HPP_ */
|
||||
@ -21,7 +21,8 @@ public:
|
||||
: PrimitiveThread([](void* d) {
|
||||
CRTP* dd = static_cast<CRTP*>(d);
|
||||
(*dd)();
|
||||
}, name, priority, stack_size)
|
||||
},
|
||||
this, name, priority, stack_size)
|
||||
{}
|
||||
|
||||
Thread() = delete;
|
||||
|
||||
@ -10,17 +10,17 @@
|
||||
#include "peripherals_utility.hpp"
|
||||
|
||||
#ifdef INCLUDE_xTaskGetCurrentTaskHandle
|
||||
# define ASSERT_IS_CURRENT() \
|
||||
#define ASSERT_IS_CURRENT() \
|
||||
assert(Threads::PrimitiveThread::getCurrentThread().taskHandle() == this->taskHandle())
|
||||
#else
|
||||
# define ASSERT_IS_CURRENT()
|
||||
#define ASSERT_IS_CURRENT()
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_xTaskGetCurrentTaskHandle
|
||||
# define ASSERT_IS_NOT_CURRENT() \
|
||||
#define ASSERT_IS_NOT_CURRENT() \
|
||||
assert(Threads::PrimitiveThread::getCurrentThread().taskHandle() != this->taskHandle())
|
||||
#else
|
||||
# define ASSERT_IS_NOT_CURRENT()
|
||||
#define ASSERT_IS_NOT_CURRENT()
|
||||
#endif
|
||||
|
||||
namespace Threads
|
||||
@ -88,20 +88,18 @@ void PrimitiveThread::sleepUntil(const unsigned long deadline)
|
||||
}
|
||||
|
||||
|
||||
PrimitiveThread::PrimitiveThread(osThreadFunc_t function, const osThreadAttr_t& attrs)
|
||||
: thread_id(nullptr)
|
||||
, attributes(attrs)
|
||||
PrimitiveThread::PrimitiveThread(osThreadFunc_t function, void* runner_data, const osThreadAttr_t& attrs)
|
||||
: thread_id(nullptr), attributes(attrs), runner_data_(runner_data)
|
||||
{
|
||||
assert(function);
|
||||
|
||||
thread_id = osThreadNew(function, this, &attributes);
|
||||
thread_id = osThreadNew(function, runner_data_, &attributes);
|
||||
assert(thread_id != nullptr);
|
||||
}
|
||||
|
||||
|
||||
PrimitiveThread::PrimitiveThread(TaskHandle_t threadHandle)
|
||||
: thread_id(static_cast<osThreadId_t>(threadHandle))
|
||||
, attributes(Peripherals::zeroInitialized<osThreadAttr_t>())
|
||||
: thread_id(static_cast<osThreadId_t>(threadHandle)), attributes(Peripherals::zeroInitialized<osThreadAttr_t>())
|
||||
{
|
||||
assert(thread_id != nullptr);
|
||||
}
|
||||
@ -117,4 +115,4 @@ osThreadAttr_t PrimitiveThread::constructThreadAttrs_(const char* name, const os
|
||||
return attrs;
|
||||
}
|
||||
|
||||
}
|
||||
}// namespace Threads
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user