skullc-peripherals/Threads/Inc/threads_exclusivesignal.hpp
Erki 9620c2206e Threads: refactor signals to simply return void
this is required for muxing signals together.
2021-06-26 13:10:57 +03:00

178 lines
3.7 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_ */