xref: /aosp_15_r20/external/pigweed/pw_thread_zephyr/public/pw_thread_zephyr/context.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2023 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 <zephyr/kernel.h>
17 #include <zephyr/kernel/thread_stack.h>
18 
19 #include <cstdint>
20 
21 #include "pw_function/function.h"
22 #include "pw_span/span.h"
23 #include "pw_thread_zephyr/config.h"
24 
25 namespace pw::thread {
26 
27 class Thread;  // Forward declare Thread which depends on Context.
28 
29 }  // namespace pw::thread
30 
31 namespace pw::thread::zephyr {
32 
33 class Options;
34 
35 // At the moment, Zephyr RTOS doesn't support dynamic thread stack allocation
36 // (due to various alignment and size requirements on different architectures).
37 // Still, we separate the context in two parts:
38 //
39 //   1) Context which just contains the Thread Control Block (k_thread) and
40 //      additional context pw::Thread requires.
41 //
42 //   2) StaticContextWithStack which contains the stack.
43 //
44 // Only StaticContextWithStack can be instantiated directly.
45 class Context {
46  public:
47   Context(const Context&) = delete;
48   Context& operator=(const Context&) = delete;
49 
50  protected:
51   // We can't use `= default` here, because it allows to create an Context
52   // instance in C++17 with `pw::thread::zephyr::Context{}` syntax.
Context()53   Context() {}
54 
55  private:
56   friend Thread;
57 
58   static void CreateThread(const Options& options,
59                            Function<void()>&& thread_fn,
60                            Context*& native_type_out);
61 
task_handle()62   k_tid_t task_handle() const { return task_handle_; }
set_task_handle(const k_tid_t task_handle)63   void set_task_handle(const k_tid_t task_handle) {
64     task_handle_ = task_handle;
65   }
66 
thread_info()67   k_thread& thread_info() { return thread_info_; }
68 
set_thread_routine(Function<void ()> && rvalue)69   void set_thread_routine(Function<void()>&& rvalue) {
70     fn_ = std::move(rvalue);
71   }
72 
detached()73   bool detached() const { return detached_; }
74   void set_detached(bool value = true) { detached_ = value; }
75 
thread_done()76   bool thread_done() const { return thread_done_; }
77   void set_thread_done(bool value = true) { thread_done_ = value; }
78 
79   static void ThreadEntryPoint(void* void_context_ptr, void*, void*);
80 
81   k_tid_t task_handle_ = nullptr;
82   k_thread thread_info_;
83   Function<void()> fn_;
84   bool detached_ = false;
85   bool thread_done_ = false;
86 };
87 
88 // Intermediate class to type-erase kStackSizeBytes parameter of
89 // StaticContextWithStack.
90 class StaticContext : public Context {
91  protected:
StaticContext(z_thread_stack_element * stack,size_t available_stack_size)92   explicit StaticContext(z_thread_stack_element* stack,
93                          size_t available_stack_size)
94       : stack_(stack), available_stack_size_(available_stack_size) {}
95 
96  private:
97   friend Context;
98 
stack()99   z_thread_stack_element* stack() { return stack_; }
available_stack_size()100   size_t available_stack_size() { return available_stack_size_; }
101 
102   // Zephyr RTOS doesn't specify how Zephyr-owned thread information is
103   // stored in the stack, how much spaces it takes, etc.
104   // All we know is that K_THREAD_STACK(stack, size) macro will allocate
105   // enough memory to hold size bytes of user-owned stack and that
106   // we must pass that stack pointer to k_thread_create.
107   z_thread_stack_element* stack_;
108   size_t available_stack_size_;
109 };
110 
111 // Static thread context allocation including the stack along with the Context.
112 //
113 // See docs.rst for an usage example.
114 template <size_t kStackSizeBytes>
115 class StaticContextWithStack final : public StaticContext {
116  public:
StaticContextWithStack()117   constexpr StaticContextWithStack()
118       : StaticContext(stack_storage_, kStackSizeBytes) {}
119 
120  private:
121   K_THREAD_STACK_MEMBER(stack_storage_, kStackSizeBytes);
122 };
123 
124 }  // namespace pw::thread::zephyr
125