xref: /aosp_15_r20/external/pigweed/pw_thread_freertos/public/pw_thread_freertos/context.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 #pragma once
15 
16 #include <cstdint>
17 
18 #include "FreeRTOS.h"
19 #include "pw_function/function.h"
20 #include "pw_span/span.h"
21 #include "pw_thread_freertos/config.h"
22 #include "task.h"
23 #if PW_THREAD_JOINING_ENABLED
24 #include "event_groups.h"
25 #endif  // PW_THREAD_JOINING_ENABLED
26 
27 namespace pw::thread {
28 
29 class Thread;  // Forward declare Thread which depends on Context.
30 
31 }  // namespace pw::thread
32 
33 namespace pw::thread::freertos {
34 
35 class Options;
36 
37 // FreeRTOS may be used for dynamic thread TCB and stack allocation, but
38 // because we need some additional context beyond that the concept of a
39 // thread's context is split into two halves:
40 //
41 //   1) Context which just contains the additional Context pw::Thread requires.
42 //      This is used for both static and dynamic thread allocations.
43 //
44 //   2) StaticContext which contains the TCB and a span to the stack which is
45 //      used only for static allocations.
46 class Context {
47  public:
48   Context() = default;
49   Context(const Context&) = delete;
50   Context& operator=(const Context&) = delete;
51 
52  private:
53   friend Thread;
54   static void CreateThread(const freertos::Options& options,
55                            Function<void()>&& thread_fn,
56                            Context*& native_type_out);
57   void AddToEventGroup();
58 
task_handle()59   TaskHandle_t task_handle() const { return task_handle_; }
set_task_handle(const TaskHandle_t task_handle)60   void set_task_handle(const TaskHandle_t task_handle) {
61     task_handle_ = task_handle;
62   }
63 
set_thread_routine(Function<void ()> && rvalue)64   void set_thread_routine(Function<void()>&& rvalue) {
65     fn_ = std::move(rvalue);
66   }
67 
detached()68   bool detached() const { return detached_; }
69   void set_detached(bool value = true) { detached_ = value; }
70 
thread_done()71   bool thread_done() const { return thread_done_; }
72   void set_thread_done(bool value = true) { thread_done_ = value; }
73 
74 #if PW_THREAD_FREERTOS_CONFIG_DYNAMIC_ALLOCATION_ENABLED
dynamically_allocated()75   bool dynamically_allocated() const { return dynamically_allocated_; }
set_dynamically_allocated()76   void set_dynamically_allocated() { dynamically_allocated_ = true; }
77 #endif  // PW_THREAD_FREERTOS_CONFIG_DYNAMIC_ALLOCATION_ENABLED
78 
79 #if PW_THREAD_JOINING_ENABLED
join_event_group()80   StaticEventGroup_t& join_event_group() { return event_group_; }
81 #endif  // PW_THREAD_JOINING_ENABLED
82 
83   static void ThreadEntryPoint(void* void_context_ptr);
84   static void TerminateThread(Context& context);
85 
86   TaskHandle_t task_handle_ = nullptr;
87   Function<void()> fn_;
88 #if PW_THREAD_JOINING_ENABLED
89   // Note that the FreeRTOS life cycle of this event group is managed together
90   // with the task life cycle, not this object's life cycle.
91   StaticEventGroup_t event_group_;
92 #endif  // PW_THREAD_JOINING_ENABLED
93   bool detached_ = false;
94   bool dynamically_allocated_ = false;
95   bool thread_done_ = false;
96 };
97 
98 // Static thread context allocation including the TCB, an event group for
99 // joining if enabled, and an external statically allocated stack.
100 //
101 // Example usage:
102 //
103 //   std::array<StackType_t, kFooStackSizeWords> example_thread_stack;
104 //   pw::thread::freertos::Context example_thread_context(example_thread_stack);
105 //   void StartExampleThread() {
106 //      pw::Thread(
107 //        pw::thread::freertos::Options()
108 //            .set_name("static_example_thread")
109 //            .set_priority(kFooPriority)
110 //            .set_static_context(example_thread_context),
111 //        example_thread_function).detach();
112 //   }
113 class StaticContext : public Context {
114  public:
StaticContext(span<StackType_t> stack_span)115   explicit StaticContext(span<StackType_t> stack_span)
116       : tcb_{}, stack_span_(stack_span) {}
117 
118  private:
119   friend Context;
120 
tcb()121   StaticTask_t& tcb() { return tcb_; }
stack()122   span<StackType_t> stack() { return stack_span_; }
123 
124   StaticTask_t tcb_;
125   span<StackType_t> stack_span_;
126 };
127 
128 // Static thread context allocation including the stack along with the Context.
129 //
130 // Example usage:
131 //
132 //   pw::thread::freertos::ContextWithStack<kFooStackSizeWords>
133 //       example_thread_context;
134 //   void StartExampleThread() {
135 //      pw::Thread(
136 //        pw::thread::freertos::Options()
137 //            .set_name("static_example_thread")
138 //            .set_priority(kFooPriority)
139 //            .set_static_context(example_thread_context),
140 //        example_thread_function).detach();
141 //   }
142 template <size_t kStackSizeWords = config::kDefaultStackSizeWords>
143 class StaticContextWithStack final : public StaticContext {
144  public:
StaticContextWithStack()145   constexpr StaticContextWithStack() : StaticContext(stack_storage_) {
146     static_assert(kStackSizeWords >= config::kMinimumStackSizeWords);
147   }
148 
149  private:
150   std::array<StackType_t, kStackSizeWords> stack_storage_;
151 };
152 
153 }  // namespace pw::thread::freertos
154