aboutsummaryrefslogtreecommitdiff
path: root/pw_thread_zephyr/public/pw_thread_zephyr/context.h
diff options
context:
space:
mode:
Diffstat (limited to 'pw_thread_zephyr/public/pw_thread_zephyr/context.h')
-rw-r--r--pw_thread_zephyr/public/pw_thread_zephyr/context.h120
1 files changed, 120 insertions, 0 deletions
diff --git a/pw_thread_zephyr/public/pw_thread_zephyr/context.h b/pw_thread_zephyr/public/pw_thread_zephyr/context.h
new file mode 100644
index 000000000..6ac04e520
--- /dev/null
+++ b/pw_thread_zephyr/public/pw_thread_zephyr/context.h
@@ -0,0 +1,120 @@
+// Copyright 2023 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+#pragma once
+
+#include <zephyr/kernel.h>
+#include <zephyr/kernel/thread_stack.h>
+
+#include <cstdint>
+
+#include "pw_span/span.h"
+#include "pw_thread_zephyr/config.h"
+
+namespace pw::thread {
+
+class Thread; // Forward declare Thread which depends on Context.
+
+} // namespace pw::thread
+
+namespace pw::thread::zephyr {
+
+// At the moment, Zephyr RTOS doesn't support dynamic thread stack allocation
+// (due to various alignment and size requirements on different architectures).
+// Still, we separate the context in two parts:
+//
+// 1) Context which just contains the Thread Control Block (k_thread) and
+// additional context pw::thread::Thread requires.
+//
+// 2) StaticContextWithStack which contains the stack.
+//
+// Only StaticContextWithStack can be instantiated directly.
+class Context {
+ public:
+ Context(const Context&) = delete;
+ Context& operator=(const Context&) = delete;
+
+ protected:
+ // We can't use `= default` here, because it allows to create an Context
+ // instance in C++17 with `pw::thread::zephyr::Context{}` syntax.
+ Context(){};
+
+ private:
+ friend Thread;
+
+ k_tid_t task_handle() const { return task_handle_; }
+ void set_task_handle(const k_tid_t task_handle) {
+ task_handle_ = task_handle;
+ }
+
+ k_thread& thread_info() { return thread_info_; }
+
+ using ThreadRoutine = void (*)(void* arg);
+ void set_thread_routine(ThreadRoutine entry, void* arg) {
+ user_thread_entry_function_ = entry;
+ user_thread_entry_arg_ = arg;
+ }
+
+ bool detached() const { return detached_; }
+ void set_detached(bool value = true) { detached_ = value; }
+
+ bool thread_done() const { return thread_done_; }
+ void set_thread_done(bool value = true) { thread_done_ = value; }
+
+ static void ThreadEntryPoint(void* void_context_ptr, void*, void*);
+
+ k_tid_t task_handle_ = nullptr;
+ k_thread thread_info_;
+ ThreadRoutine user_thread_entry_function_ = nullptr;
+ void* user_thread_entry_arg_ = nullptr;
+ bool detached_ = false;
+ bool thread_done_ = false;
+};
+
+// Intermediate class to type-erase kStackSizeBytes parameter of
+// StaticContextWithStack.
+class StaticContext : public Context {
+ protected:
+ explicit StaticContext(z_thread_stack_element* stack,
+ size_t available_stack_size)
+ : stack_(stack), available_stack_size_(available_stack_size) {}
+
+ private:
+ friend Thread;
+
+ z_thread_stack_element* stack() { return stack_; }
+ size_t available_stack_size() { return available_stack_size_; }
+
+ // Zephyr RTOS doesn't specify how Zephyr-owned thread information is
+ // stored in the stack, how much spaces it takes, etc.
+ // All we know is that K_THREAD_STACK(stack, size) macro will allocate
+ // enough memory to hold size bytes of user-owned stack and that
+ // we must pass that stack pointer to k_thread_create.
+ z_thread_stack_element* stack_;
+ size_t available_stack_size_;
+};
+
+// Static thread context allocation including the stack along with the Context.
+//
+// See docs.rst for an usage example.
+template <size_t kStackSizeBytes>
+class StaticContextWithStack final : public StaticContext {
+ public:
+ constexpr StaticContextWithStack()
+ : StaticContext(stack_storage_, kStackSizeBytes) {}
+
+ private:
+ K_THREAD_STACK_MEMBER(stack_storage_, kStackSizeBytes);
+};
+
+} // namespace pw::thread::zephyr