182 lines
3.8 KiB
C++
182 lines
3.8 KiB
C++
/*
|
|
* threads_signal.hpp
|
|
*
|
|
* Created on: Jun 11, 2021
|
|
* Author: erki
|
|
*/
|
|
|
|
#ifndef SKULLC_THREADS_EXCLUSIVESIGNAL_HPP_
|
|
#define SKULLC_THREADS_EXCLUSIVESIGNAL_HPP_
|
|
|
|
#include <array>
|
|
#include <atomic>
|
|
#include <optional>
|
|
#include <type_traits>
|
|
|
|
#include "threads_primitivethread.hpp"
|
|
#include "threads_signal.hpp"
|
|
|
|
namespace Threads
|
|
{
|
|
|
|
template<typename T>
|
|
class ExclusiveSignal : public Signallable<T>
|
|
, public Awaitable<std::optional<T>>
|
|
{
|
|
public:
|
|
using value_type = T;
|
|
using result_type = std::optional<T>;
|
|
|
|
static_assert(
|
|
std::is_trivially_copyable_v<value_type>, "Signal's value must be trivially copyable.");
|
|
|
|
ExclusiveSignal()
|
|
: current_value_(std::nullopt), waiting_thread_(std::nullopt)
|
|
{}
|
|
|
|
ExclusiveSignal(const ExclusiveSignal&) = delete;
|
|
ExclusiveSignal(ExclusiveSignal&&) = delete;
|
|
ExclusiveSignal& operator=(const ExclusiveSignal&) = delete;
|
|
ExclusiveSignal& operator=(ExclusiveSignal&&) = delete;
|
|
|
|
#ifdef INCLUDE_xTaskGetCurrentTaskHandle
|
|
result_type await() override
|
|
{
|
|
return await(PrimitiveThread::getCurrentThread());
|
|
}
|
|
|
|
result_type await(const long timeout) override
|
|
{
|
|
return await(PrimitiveThread::getCurrentThread(), timeout);
|
|
}
|
|
#endif
|
|
|
|
result_type await(const PrimitiveThread& currentThread) override
|
|
{
|
|
return await(currentThread, portMAX_DELAY);
|
|
}
|
|
|
|
result_type await(const PrimitiveThread& currentThread, const long timeout) override
|
|
{
|
|
waiting_thread_ = currentThread;
|
|
|
|
const bool notified = currentThread.notifyWait(timeout);
|
|
|
|
if (!notified)
|
|
{
|
|
return std::nullopt;
|
|
}
|
|
else
|
|
{
|
|
return current_value_;
|
|
}
|
|
}
|
|
|
|
bool emit(const value_type& v) override
|
|
{
|
|
current_value_ = v;
|
|
|
|
if (!waiting_thread_)
|
|
{
|
|
return false;
|
|
}
|
|
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> : 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;
|
|
ExclusiveSignal& operator=(const ExclusiveSignal&) = delete;
|
|
ExclusiveSignal& operator=(ExclusiveSignal&&) = delete;
|
|
|
|
#ifdef INCLUDE_xTaskGetCurrentTaskHandle
|
|
result_type await() override
|
|
{
|
|
return await(PrimitiveThread::getCurrentThread());
|
|
}
|
|
|
|
result_type await(const long timeout) override
|
|
{
|
|
return await(PrimitiveThread::getCurrentThread(), timeout);
|
|
}
|
|
#endif
|
|
|
|
result_type await(const PrimitiveThread& currentThread) override
|
|
{
|
|
return await(currentThread, portMAX_DELAY);
|
|
}
|
|
|
|
result_type await(const PrimitiveThread& currentThread, const long timeout) override
|
|
{
|
|
waiting_thread_ = currentThread;
|
|
return currentThread.notifyWait(timeout);
|
|
}
|
|
|
|
void emit() override
|
|
{
|
|
if (waiting_thread_)
|
|
{
|
|
auto const _ = waiting_thread_->notify(0, eNoAction);
|
|
(void) _;
|
|
}
|
|
}
|
|
|
|
BaseType_t emitFromIsr() override
|
|
{
|
|
if (!waiting_thread_)
|
|
{
|
|
return pdFALSE;
|
|
}
|
|
else
|
|
{
|
|
auto const [discard, was_notified] = waiting_thread_->notifyFromIsr(0, eNoAction);
|
|
(void) discard;
|
|
|
|
return was_notified;
|
|
}
|
|
}
|
|
|
|
private:
|
|
std::optional<PrimitiveThread> waiting_thread_;
|
|
};
|
|
|
|
}// namespace Threads
|
|
|
|
|
|
#endif /* SKULLC_THREADS_EXCLUSIVESIGNAL_HPP_ */
|