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