• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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