1 // Copyright 2024 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 <cstddef> 17 #include <type_traits> 18 19 #include "pw_span/span.h" 20 #include "pw_thread/priority.h" 21 #include "pw_thread/stack.h" 22 23 namespace pw { 24 25 /// Generic attributes of a thread. `ThreadAttrs` is used with a `ThreadContext` 26 /// to create threads. 27 /// 28 /// `ThreadAtts` provides three attributes: name, priority, stack size, and 29 /// stack location. These attributes should be considered only as hints -- the 30 /// pw_thread backend may not support them. 31 class ThreadAttrs { 32 public: 33 /// Initializes attributes to their backend-defined defaults. ThreadAttrs()34 constexpr ThreadAttrs() 35 : name_(""), 36 priority_(), 37 stack_(nullptr), 38 stack_size_(thread::backend::kDefaultStackSizeBytes) {} 39 40 /// Thread attributes can be copied to share properties between threads. 41 constexpr ThreadAttrs(const ThreadAttrs&) = default; 42 constexpr ThreadAttrs& operator=(const ThreadAttrs&) = default; 43 44 /// Name hint as a null-terminated string. Never null. name()45 constexpr const char* name() const { return name_; } 46 set_name(const char * name)47 constexpr ThreadAttrs& set_name(const char* name) { 48 PW_DASSERT(name != nullptr); 49 name_ = name; 50 return *this; 51 } 52 53 constexpr ThreadAttrs& set_name(std::nullptr_t) = delete; 54 priority()55 constexpr ThreadPriority priority() const { return priority_; } 56 57 /// Sets a thread priority hint. set_priority(ThreadPriority priority)58 constexpr ThreadAttrs& set_priority(ThreadPriority priority) { 59 priority_ = priority; 60 return *this; 61 } 62 63 /// Returns a span of the native stack to use for this thread. The stack may 64 /// not be in terms of bytes! Backends that use `void*` for stacks return a 65 /// `std::byte` span. If the backend doesn't support user-specified stacks, 66 /// 67 /// This function is NOT `constexpr` if the backend uses `void*` for stacks. native_stack()68 constexpr auto native_stack() const { 69 PW_ASSERT(has_external_stack()); 70 return internal::ThreadStackSpan(stack_, stack_size_); 71 } 72 73 /// Returns a pointer to the native stack to use for this thread. 74 /// 75 /// @warning This function is NOT portable! native_stack_pointer()76 constexpr auto native_stack_pointer() const { return stack_; } 77 78 /// Returns the size of the stack in native units (not necessarily bytes), 79 /// using the native type (typically an unsigned integer). 80 /// 81 /// @warning This function is NOT portable! native_stack_size()82 constexpr auto native_stack_size() const { 83 PW_ASSERT(has_external_stack()); 84 return stack_size_; 85 } 86 87 /// Returns the size of the stack in bytes. stack_size_bytes()88 constexpr size_t stack_size_bytes() const { 89 if (has_external_stack()) { 90 return internal::NativeStackSizeBytes(stack_size_); 91 } 92 return stack_size_; 93 } 94 95 /// Sets the thread stack size to use for a stack provided by the 96 /// `ThreadContext`. If 0, the thread backend's minimum stack size is used. 97 /// @pre An external stack has not been set with `set_stack()`. set_stack_size_bytes(size_t stack_size_bytes)98 constexpr ThreadAttrs& set_stack_size_bytes(size_t stack_size_bytes) { 99 PW_ASSERT(!has_external_stack()); 100 stack_size_ = stack_size_bytes; 101 return *this; 102 } 103 104 /// Sets the thread to use the provided stack, instead of a stack integrated 105 /// into the `ThreadContext`. 106 template <size_t kStackSizeBytes> set_stack(ThreadStack<kStackSizeBytes> & stack)107 constexpr ThreadAttrs& set_stack(ThreadStack<kStackSizeBytes>& stack) { 108 stack_ = stack.native_pointer(); 109 stack_size_ = stack.native_size(); 110 return *this; 111 } 112 113 /// Clears a previous call to `set_stack`. clear_stack()114 constexpr ThreadAttrs& clear_stack() { 115 stack_ = nullptr; 116 stack_size_ = thread::backend::kDefaultStackSizeBytes; 117 return *this; 118 } 119 120 /// True if the `ThreadAttrs` use an externally allocated stack, rather than 121 /// one integrated with the `ThreadContext`. has_external_stack()122 [[nodiscard]] constexpr bool has_external_stack() const { 123 return stack_ != nullptr; 124 } 125 126 private: 127 const char* name_; 128 ThreadPriority priority_; 129 130 internal::ThreadStackPointer stack_; 131 size_t stack_size_; 132 }; 133 134 } // namespace pw 135