1 // Copyright 2021 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 <cstring> 17 18 #include "RTOS.h" 19 #include "pw_span/span.h" 20 #include "pw_string/util.h" 21 #include "pw_thread_embos/config.h" 22 23 namespace pw::thread { 24 25 class Thread; // Forward declare Thread which depends on Context. 26 27 } // namespace pw::thread 28 29 namespace pw::thread::embos { 30 31 // Static thread context allocation including the TCB, an event group for 32 // joining if enabled, and an external statically allocated stack. 33 // 34 // Example usage: 35 // 36 // std::array<ULONG, kFooStackSizeWords> example_thread_stack; 37 // pw::thread::embos::Context example_thread_context(example_thread_stack); 38 // void StartExampleThread() { 39 // pw::thread::DetachedThread( 40 // pw::thread::embos::Options() 41 // .set_name("static_example_thread") 42 // .set_priority(kFooPriority) 43 // .set_context(example_thread_context), 44 // example_thread_function); 45 // } 46 class Context { 47 public: Context(span<OS_UINT> stack_span)48 explicit Context(span<OS_UINT> stack_span) 49 : tcb_{}, stack_span_(stack_span) {} 50 Context(const Context&) = delete; 51 Context& operator=(const Context&) = delete; 52 53 // Intended for unit test & Thread use only. tcb()54 OS_TASK& tcb() { return tcb_; } 55 56 private: 57 friend Thread; 58 stack()59 span<OS_UINT> stack() { return stack_span_; } 60 in_use()61 bool in_use() const { return in_use_; } 62 void set_in_use(bool in_use = true) { in_use_ = in_use; } 63 name()64 const char* name() const { return name_.data(); } set_name(const char * name)65 void set_name(const char* name) { string::Copy(name, name_); } 66 67 using ThreadRoutine = void (*)(void* arg); set_thread_routine(ThreadRoutine entry,void * arg)68 void set_thread_routine(ThreadRoutine entry, void* arg) { 69 user_thread_entry_function_ = entry; 70 user_thread_entry_arg_ = arg; 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 #if PW_THREAD_JOINING_ENABLED join_event_object()80 OS_EVENT& join_event_object() { return event_object_; } 81 #endif // PW_THREAD_JOINING_ENABLED 82 83 static void ThreadEntryPoint(void* void_context_ptr); 84 static void TerminateThread(Context& context); 85 86 OS_TASK tcb_; 87 span<OS_UINT> stack_span_; 88 89 ThreadRoutine user_thread_entry_function_ = nullptr; 90 void* user_thread_entry_arg_ = nullptr; 91 #if PW_THREAD_JOINING_ENABLED 92 // Note that the embOS life cycle of this event object is managed together 93 // with the thread life cycle, not this object's life cycle. 94 OS_EVENT event_object_; 95 #endif // PW_THREAD_JOINING_ENABLED 96 bool in_use_ = false; 97 bool detached_ = false; 98 bool thread_done_ = false; 99 100 // The TCB does not have storage for the name, ergo we provide storage for 101 // the thread's name which can be truncated down to just a null delimiter. 102 std::array<char, config::kMaximumNameLength + 1> name_; 103 }; 104 105 // Static thread context allocation including the stack along with the Context. 106 // 107 // Example usage: 108 // 109 // pw::thread::embos::ContextWithStack<kFooStackSizeWords> 110 // example_thread_context; 111 // void StartExampleThread() { 112 // pw::thread::DetachedThread( 113 // pw::thread::embos::Options() 114 // .set_name("static_example_thread") 115 // .set_priority(kFooPriority) 116 // .set_context(example_thread_context), 117 // example_thread_function); 118 // } 119 template <size_t kStackSizeWords = config::kDefaultStackSizeWords> 120 class ContextWithStack final : public Context { 121 public: ContextWithStack()122 constexpr ContextWithStack() : Context(stack_storage_) { 123 static_assert(kStackSizeWords >= config::kMinimumStackSizeWords); 124 } 125 126 private: 127 std::array<OS_UINT, kStackSizeWords> stack_storage_; 128 }; 129 130 } // namespace pw::thread::embos 131