Skip to content

Instantly share code, notes, and snippets.

@ciniml
Created July 16, 2017 09:24
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ciniml/e85c08664ee307645321ec3ce3973cc6 to your computer and use it in GitHub Desktop.
Save ciniml/e85c08664ee307645321ec3ce3973cc6 to your computer and use it in GitHub Desktop.
C++11 std::future like class template for FreeRTOS
#ifndef FREERTOS_FUTURE_HPP__
#define FREERTOS_FUTURE_HPP__
#include <type_traits>
#include <utility>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/event_groups.h"
namespace freertos
{
class Mutex
{
private:
StaticSemaphore_t body;
SemaphoreHandle_t handle;
bool is_locked;
public:
Mutex() : handle(nullptr), is_locked(false)
{
this->handle = xSemaphoreCreateMutexStatic(&this->body);
}
void lock()
{
xSemaphoreTake(this->handle, portMAX_DELAY);
this->is_locked = true;
}
void release()
{
this->is_locked = false;
xSemaphoreGive(this->handle);
}
~Mutex()
{
if (this->handle != nullptr) {
if (this->is_locked) {
this->release();
}
vSemaphoreDelete(this->handle);
this->handle = nullptr;
}
}
};
class WaitEvent
{
private:
typedef std::unique_ptr< std::remove_pointer<EventGroupHandle_t>::type, decltype(&vEventGroupDelete)> HandleType;
HandleType handle;
public:
WaitEvent() : handle(nullptr, vEventGroupDelete)
{
this->handle.reset(xEventGroupCreate());
}
WaitEvent(const WaitEvent&) = delete;
WaitEvent(WaitEvent&& source) : handle(std::move(source.handle)) {}
void clear()
{
xEventGroupClearBits(this->handle.get(), 1);
}
void set()
{
xEventGroupSetBits(this->handle.get(), 1);
}
void wait()
{
xEventGroupWaitBits(this->handle.get(), 1, pdFALSE, pdTRUE, portMAX_DELAY);
}
bool is_valid() const { return this->handle.operator bool(); }
};
template<typename TLock>
class LockGuard
{
private:
TLock& lock;
public:
LockGuard(TLock* lock) : lock(*lock)
{
this->lock.lock();
}
LockGuard(TLock& lock) : lock(lock)
{
this->lock.lock();
}
~LockGuard()
{
this->lock.release();
}
};
template<typename TResult> class future;
template<typename TResult>
class promise_base
{
protected:
friend class future<TResult>;
struct SharedState
{
struct Deleter
{
void operator()(TResult* result) { result->~TResult(); }
};
typename std::aligned_storage<sizeof(TResult)>::type storage;
std::unique_ptr<TResult, Deleter> result;
WaitEvent event;
Mutex mutex;
void set_value(const TResult& value)
{
{
LockGuard<Mutex>(this->mutex);
this->result.reset(new(&this->storage) TResult(value));
}
this->event.set();
}
void set_value(TResult&& value) noexcept
{
{
LockGuard<Mutex>(this->mutex);
this->result.reset(new(&this->storage) TResult(std::forward<TResult>(value)));
}
this->event.set();
}
void wait()
{
this->event.wait();
}
TResult get_result()
{
this->wait();
return *this->result;
}
};
std::shared_ptr<SharedState> state;
typedef promise_base<TResult> SelfType;
promise_base() : state(new SharedState()) {}
promise_base(const SelfType& other) = delete;
promise_base(SelfType&& source) noexcept : state(std::move(source)) {}
public:
void set_value(TResult&& result)
{
this->state->set_value(std::forward<TResult>(result));
}
void set_value(const TResult& result)
{
this->state->set_value(result);
}
};
template<typename TResult> class promise;
template<typename TResult>
class future
{
friend class promise<TResult>;
private:
typedef promise_base<TResult> PromiseType;
typedef typename PromiseType::SharedState SharedState;
std::shared_ptr<SharedState> state;
future(const std::shared_ptr<SharedState>& state) : state(state) {}
public:
void wait() {
this->state->wait();
}
TResult get() {
return this->state->get_result();
}
};
template<typename TResult>
class promise : public promise_base<TResult>
{
public:
typedef future<TResult> FutureType;
private:
public:
FutureType get_future()
{
return FutureType(this->state);
}
};
};
#endif //FREERTOS_FUTURE_HPP__
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment