idfxx 1.0.0
Modern C++23 components for ESP-IDF
Loading...
Searching...
No Matches
task.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 Chris Leishman
3
4#pragma once
5
20#include <idfxx/chrono>
21#include <idfxx/cpu>
22#include <idfxx/error>
23#include <idfxx/memory>
24
25#include <chrono>
26#include <freertos/FreeRTOS.h>
27#include <freertos/task.h>
28#include <functional>
29#include <memory>
30#include <optional>
31#include <string>
32#include <string_view>
33
34namespace idfxx {
35
47class task {
48 struct context;
49
50public:
57 class self {
58 friend class task;
59 explicit self(context* ctx) noexcept
60 : _context(ctx) {}
61
62 public:
63 self(const self&) = delete;
64 self& operator=(const self&) = delete;
65
74 [[nodiscard]] bool is_detached() const noexcept;
75
81 [[nodiscard]] bool stop_requested() const noexcept;
82
90 void suspend() noexcept;
91
100 void wait() noexcept;
101
116 template<typename Rep, typename Period>
117 [[nodiscard]] bool wait_for(const std::chrono::duration<Rep, Period>& timeout) noexcept {
118 return _take(chrono::ticks(timeout)) != 0;
119 }
120
135 template<typename Clock, typename Duration>
136 [[nodiscard]] bool wait_until(const std::chrono::time_point<Clock, Duration>& deadline) noexcept {
137 auto remaining = deadline - Clock::now();
138 if (remaining <= decltype(remaining)::zero()) {
139 return _take(0) != 0;
140 }
141 return _take(chrono::ticks(remaining)) != 0;
142 }
143
155 uint32_t take() noexcept;
156
172 template<typename Rep, typename Period>
173 [[nodiscard]] uint32_t take_for(const std::chrono::duration<Rep, Period>& timeout) noexcept {
174 return _take(chrono::ticks(timeout));
175 }
176
192 template<typename Clock, typename Duration>
193 [[nodiscard]] uint32_t take_until(const std::chrono::time_point<Clock, Duration>& deadline) noexcept {
194 auto remaining = deadline - Clock::now();
195 if (remaining <= decltype(remaining)::zero()) {
196 return _take(0);
197 }
198 return _take(chrono::ticks(remaining));
199 }
200
206 [[nodiscard]] unsigned int priority() const noexcept;
207
213 void set_priority(unsigned int new_priority) noexcept;
214
223 [[nodiscard]] size_t stack_high_water_mark() const noexcept;
224
230 [[nodiscard]] std::string name() const;
231
237 [[nodiscard]] TaskHandle_t idf_handle() const noexcept;
238
239 private:
240 uint32_t _take(TickType_t ticks) noexcept;
241
242 context* _context;
243 };
244
249 struct config {
250 std::string_view name = "task";
251 size_t stack_size = 4096;
252 unsigned int priority = 5;
253 std::optional<core_id> core_affinity = std::nullopt;
255 };
256
257#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
269 [[nodiscard]] explicit task(const config& cfg, std::move_only_function<void(self&)> task_func);
270
283 [[nodiscard]] explicit task(const config& cfg, void (*task_func)(self&, void*), void* arg);
284#endif
285
297 [[nodiscard]] static result<std::unique_ptr<task>> make(config cfg, std::move_only_function<void(self&)> task_func);
298
311 [[nodiscard]] static result<std::unique_ptr<task>> make(config cfg, void (*task_func)(self&, void*), void* arg);
312
313#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
325 static void spawn(config cfg, std::move_only_function<void(self&)> task_func) {
326 unwrap(try_spawn(std::move(cfg), std::move(task_func)));
327 }
328
341 static void spawn(config cfg, void (*task_func)(self&, void*), void* arg) {
342 unwrap(try_spawn(std::move(cfg), task_func, arg));
343 }
344#endif
345
357 [[nodiscard]] static result<void> try_spawn(config cfg, std::move_only_function<void(self&)> task_func);
358
371 [[nodiscard]] static result<void> try_spawn(config cfg, void (*task_func)(self&, void*), void* arg);
372
388
389 // Non-copyable and non-movable
390 task(const task&) = delete;
391 task& operator=(const task&) = delete;
392 task(task&&) = delete;
393 task& operator=(task&&) = delete;
394
402 [[nodiscard]] TaskHandle_t idf_handle() const noexcept { return _handle; }
403
409 [[nodiscard]] const std::string& name() const noexcept { return _name; }
410
416 [[nodiscard]] unsigned int priority() const noexcept;
417
427 [[nodiscard]] size_t stack_high_water_mark() const noexcept;
428
434 [[nodiscard]] bool is_completed() const noexcept;
435
443 [[nodiscard]] bool joinable() const noexcept { return _handle != nullptr; }
444
455 bool request_stop() noexcept;
456
462 [[nodiscard]] bool stop_requested() const noexcept;
463
464#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
474
481 void resume() { unwrap(try_resume()); }
482#endif
483
493
501
518 [[nodiscard]] bool resume_from_isr() noexcept;
519
520#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
533 void notify() { unwrap(try_notify()); }
534#endif
535
549
571 [[nodiscard]] bool notify_from_isr() noexcept;
572
573#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
581 void set_priority(unsigned int new_priority) { unwrap(try_set_priority(new_priority)); }
582#endif
583
591 [[nodiscard]] result<void> try_set_priority(unsigned int new_priority);
592
593#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
604 void detach() { unwrap(try_detach()); }
605#endif
606
621
622#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
646 void kill() { unwrap(try_kill()); }
647#endif
648
673
674#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
687 void join() { unwrap(try_join()); }
688
701 template<typename Rep, typename Period>
702 void join(const std::chrono::duration<Rep, Period>& timeout) {
704 }
705
718 template<typename Clock, typename Duration>
719 void join_until(const std::chrono::time_point<Clock, Duration>& deadline) {
720 unwrap(try_join_until(deadline));
721 }
722#endif
723
735 [[nodiscard]] result<void> try_join();
736
751 template<typename Rep, typename Period>
752 [[nodiscard]] result<void> try_join(const std::chrono::duration<Rep, Period>& timeout) {
753 return _try_join(chrono::ticks(timeout));
754 }
755
770 template<typename Clock, typename Duration>
771 [[nodiscard]] result<void> try_join_until(const std::chrono::time_point<Clock, Duration>& deadline) {
772 auto remaining = deadline - Clock::now();
773 if (remaining <= decltype(remaining)::zero()) {
774 return _try_join(0);
775 }
776 return _try_join(chrono::ticks(remaining));
777 }
778
779 // =========================================================================
780 // Static utility methods for current task operations
781 // =========================================================================
782
788 [[nodiscard]] static TaskHandle_t current_handle() noexcept { return xTaskGetCurrentTaskHandle(); }
789
795 [[nodiscard]] static std::string current_name() { return pcTaskGetName(nullptr); }
796
797private:
798 static void trampoline(void* arg);
799
800 [[nodiscard]] static result<TaskHandle_t> _create(context* ctx, const config& cfg);
801 [[nodiscard]] result<void> _try_join(TickType_t ticks);
802
803 explicit task(TaskHandle_t handle, std::string name, context* ctx);
804
805 TaskHandle_t _handle;
806 std::string _name;
807 context* _context;
808};
809
// end of idfxx_task
811
812} // namespace idfxx
Handle for task self-interaction.
Definition task.hpp:57
friend class task
Definition task.hpp:58
bool wait_for(const std::chrono::duration< Rep, Period > &timeout) noexcept
Waits for a notification with a timeout (binary semaphore pattern).
Definition task.hpp:117
unsigned int priority() const noexcept
Returns the current task priority.
bool wait_until(const std::chrono::time_point< Clock, Duration > &deadline) noexcept
Waits for a notification until a deadline (binary semaphore pattern).
Definition task.hpp:136
bool stop_requested() const noexcept
Checks if a stop has been requested for this task.
uint32_t take_for(const std::chrono::duration< Rep, Period > &timeout) noexcept
Takes accumulated notifications with a timeout (counting semaphore pattern).
Definition task.hpp:173
uint32_t take_until(const std::chrono::time_point< Clock, Duration > &deadline) noexcept
Takes accumulated notifications until a deadline (counting semaphore pattern).
Definition task.hpp:193
self(const self &)=delete
TaskHandle_t idf_handle() const noexcept
Returns the FreeRTOS handle of the current task.
bool is_detached() const noexcept
Checks if the current task has been detached.
self & operator=(const self &)=delete
uint32_t take() noexcept
Takes accumulated notifications (counting semaphore pattern).
void wait() noexcept
Waits for a notification (binary semaphore pattern).
size_t stack_high_water_mark() const noexcept
Returns the minimum free stack space (in bytes) since the task started.
void set_priority(unsigned int new_priority) noexcept
Changes the current task priority.
std::string name() const
Returns the current task name.
void suspend() noexcept
Suspends the current task.
Task lifecycle management.
Definition task.hpp:47
result< void > try_resume()
Resumes a suspended task.
void join(const std::chrono::duration< Rep, Period > &timeout)
Blocks until the task function completes or the timeout expires.
Definition task.hpp:702
task(const config &cfg, void(*task_func)(self &, void *), void *arg)
Creates a task with a raw function pointer callback.
static TaskHandle_t current_handle() noexcept
Returns the handle of the currently executing task.
Definition task.hpp:788
void join()
Blocks until the task function completes.
Definition task.hpp:687
result< void > try_detach()
Releases ownership of the task.
void notify()
Sends a notification to the task.
Definition task.hpp:533
const std::string & name() const noexcept
Returns the task name.
Definition task.hpp:409
static result< void > try_spawn(config cfg, void(*task_func)(self &, void *), void *arg)
Creates a fire-and-forget task with a raw function pointer callback.
bool notify_from_isr() noexcept
Sends a notification to the task from ISR context.
result< void > try_set_priority(unsigned int new_priority)
Changes the task priority.
void resume()
Resumes a suspended task.
Definition task.hpp:481
result< void > try_join()
Blocks until the task function completes.
static result< void > try_spawn(config cfg, std::move_only_function< void(self &)> task_func)
Creates a fire-and-forget task with a std::move_only_function callback.
task & operator=(const task &)=delete
void detach()
Releases ownership of the task.
Definition task.hpp:604
void suspend()
Suspends the task.
Definition task.hpp:473
static void spawn(config cfg, void(*task_func)(self &, void *), void *arg)
Creates a fire-and-forget task with a raw function pointer callback.
Definition task.hpp:341
result< void > try_kill()
Immediately terminates the task without waiting for completion.
result< void > try_join_until(const std::chrono::time_point< Clock, Duration > &deadline)
Blocks until the task function completes or the deadline is reached.
Definition task.hpp:771
static void spawn(config cfg, std::move_only_function< void(self &)> task_func)
Creates a fire-and-forget task with a std::move_only_function callback.
Definition task.hpp:325
task(task &&)=delete
task(const task &)=delete
void kill()
Immediately terminates the task without waiting for completion.
Definition task.hpp:646
static result< std::unique_ptr< task > > make(config cfg, std::move_only_function< void(self &)> task_func)
Creates a task with a std::move_only_function callback.
result< void > try_notify()
Sends a notification to the task.
static std::string current_name()
Returns the name of the currently executing task.
Definition task.hpp:795
result< void > try_join(const std::chrono::duration< Rep, Period > &timeout)
Blocks until the task function completes or the timeout expires.
Definition task.hpp:752
bool is_completed() const noexcept
Checks if the task function has returned.
bool joinable() const noexcept
Checks if this task object owns the task.
Definition task.hpp:443
~task()
Destroys the task, requesting stop and blocking until the task function completes.
bool request_stop() noexcept
Requests the task to stop.
bool resume_from_isr() noexcept
Resumes a suspended task from ISR context.
result< void > try_suspend()
Suspends the task.
static result< std::unique_ptr< task > > make(config cfg, void(*task_func)(self &, void *), void *arg)
Creates a task with a raw function pointer callback.
task & operator=(task &&)=delete
TaskHandle_t idf_handle() const noexcept
Returns the underlying FreeRTOS task handle.
Definition task.hpp:402
void set_priority(unsigned int new_priority)
Changes the task priority.
Definition task.hpp:581
unsigned int priority() const noexcept
Returns the current task priority.
task(const config &cfg, std::move_only_function< void(self &)> task_func)
Creates a task with a std::move_only_function callback.
void join_until(const std::chrono::time_point< Clock, Duration > &deadline)
Blocks until the task function completes or the deadline is reached.
Definition task.hpp:719
constexpr TickType_t ticks(const std::chrono::duration< Rep, Period > &d)
Converts a std::chrono duration to TickType_t ticks.
Definition chrono.hpp:33
memory_type
Memory region type for heap allocations.
Definition memory.hpp:42
@ internal
Internal DRAM (default)
T unwrap(result< T > result)
Throws a std::system_error if the result is an error.
Definition error.hpp:237
@ timeout
Operation timed out.
std::expected< T, std::error_code > result
result type wrapping a value or error code.
Definition error.hpp:118
Task configuration parameters.
Definition task.hpp:249