Added barrier pattern, thread yield and updated event API

This commit is contained in:
dario 2024-03-19 14:11:10 +01:00
parent 4ce4653f71
commit 1a8f8c5dff
6 changed files with 141 additions and 8 deletions

View File

@ -9,6 +9,10 @@
#include <cmsis_os2.h>
#include <sta/event.hpp>
#define STA_EVENT_FLAGS_ALL 0xFFFFFFFFU
namespace sta
{
/**
@ -25,12 +29,12 @@ namespace sta
/**
* @brief Set given flags for the event.
*/
void set(uint32_t flags) override;
void set(uint32_t flags = STA_EVENT_FLAGS_ALL) override;
/**
* @brief Clear given flags for the event.
*/
void clear(uint32_t flags) override;
void clear(uint32_t flags = STA_EVENT_FLAGS_ALL) override;
/**
* @brief Get current flags for the event.
@ -46,11 +50,11 @@ namespace sta
* @param timeout Timeout in milliseconds.
* @return Event flags before clearing or error code if highest bit set.
*/
uint32_t wait(uint32_t flags, uint32_t timeout = osWaitForever) override;
uint32_t wait(uint32_t flags = STA_EVENT_FLAGS_ALL, uint32_t timeout = osWaitForever) override;
private:
osEventFlagsId_t event_id; /**< CMSIS RTOS2 Event Flag */
};
} // namespace sta
#endif // STA_RTOS_EVENT_HPP
#endif // STA_RTOS_EVENT_HPP

View File

@ -0,0 +1,31 @@
/*
* barrier.hpp
*
* Created on: Mar 16, 2024
* Author: Dario
*/
#ifndef RTOS2_UTILS_STA_PATTERNS_BARRIER_HPP
#define RTOS2_UTILS_STA_PATTERNS_BARRIER_HPP
#include <sta/rtos/mutex.hpp>
#include <sta/rtos/event.hpp>
namespace sta
{
class Barrier {
public:
Barrier(const char* name, uint8_t n_threads);
void wait();
private:
RtosMutex mutex_;
RtosEvent flag_;
const uint8_t n_threads_;
uint8_t n_entered_;
uint8_t n_left_;
};
} // namespace sta
#endif /* RTOS2_UTILS_STA_PATTERNS_BARRIER_HPP_ */

View File

@ -107,6 +107,12 @@ namespace sta
*/
void sleep(uint32_t ticks);
/**
* @brief Makes the currently running thread pass control to the next thread.
*
*/
void yield();
/**
* @brief Send user notification flags to thread.
*

View File

@ -10,11 +10,11 @@ namespace sta {
osEventFlagsDelete(event_id);
}
void RtosEvent::set(uint32_t flags) {
void RtosEvent::set(uint32_t flags /* = STA_EVENT_FLAGS_ALL */) {
osEventFlagsSet(event_id, flags);
}
void RtosEvent::clear(uint32_t flags) {
void RtosEvent::clear(uint32_t flags /* = STA_EVENT_FLAGS_ALL */) {
osEventFlagsClear(event_id, flags);
}
@ -22,8 +22,8 @@ namespace sta {
return osEventFlagsGet(event_id);
}
uint32_t RtosEvent::wait(uint32_t flags, uint32_t timeout) {
uint32_t RtosEvent::wait(uint32_t flags /* = STA_EVENT_FLAGS_ALL */, uint32_t timeout /* = osWaitForever */) {
return osEventFlagsWait(event_id, flags, osFlagsWaitAny, timeout);
}
} // namespace sta
} // namespace sta

83
src/patterns/barrier.cpp Normal file
View File

@ -0,0 +1,83 @@
/*
* barrier.cpp
*
* Created on: Mar 16, 2024
* Author: Dario
*/
#include <sta/rtos/patterns/barrier.hpp>
#include <sta/debug/assert.hpp>
namespace sta
{
Barrier::Barrier(const char* name, uint8_t n_threads)
: mutex_{name},
flag_{},
n_threads_{n_threads},
n_entered_{0},
n_left_{n_threads}
{
STA_ASSERT(name != nullptr);
STA_ASSERT(n_threads >= 1);
}
void Barrier::wait()
{
/**
* Taken from: https://en.wikipedia.org/wiki/Barrier_(computer_science)#Implementation
*/
mutex_.acquire();
if (n_entered_ == 0)
{
if (n_left_ == n_threads_)
{
// First thread to arrive clears the flag.
flag_.clear();
}
else
{
// This branch covers the case where a thread enters this barrier while others are still leaving.
// This can happen when a thread is much faster than the others.
mutex_.release();
// Busy waiting until the last thread leaves.
while (n_left_ != n_threads_)
{
osThreadYield();
}
mutex_.acquire();
// Clear the flag to make sure that entering threads cannot pass.
flag_.clear();
}
}
// Register this thread entering the barrier.
++n_entered_;
mutex_.release();
if (n_entered_ == n_threads_)
{
// If all threads are waiting in the barrier, set the flag allowing threads to leave.
n_entered_ = 0;
n_left_ = 1;
flag_.set();
}
else
{
// Wait in the barrier until the flag is set.
flag_.wait();
// Register this thread leaving the barrier.
mutex_.acquire();
n_left_++;
mutex_.release();
}
}
} // namespace sta

View File

@ -51,6 +51,15 @@ namespace sta
osDelay(ticks);
}
void RtosThread::yield()
{
// Make sure that the calling thread is this thread. If not, the
// developer very likely has made a mistake.
STA_ASSERT(osThreadGetId() == instance_);
osThreadYield();
}
void RtosThread::notify(uint32_t flags)
{
STA_ASSERT(instance_ != NULL);