aboutsummaryrefslogtreecommitdiff
path: root/pw_thread_embos/public/pw_thread_embos/context.h
blob: 932f107404667583b151a3690f01ff67f4929fe9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// Copyright 2021 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 <cstring>

#include "RTOS.h"
#include "pw_span/span.h"
#include "pw_string/util.h"
#include "pw_thread_embos/config.h"

namespace pw::thread {

class Thread;  // Forward declare Thread which depends on Context.

}  // namespace pw::thread

namespace pw::thread::embos {

// Static thread context allocation including the TCB, an event group for
// joining if enabled, and an external statically allocated stack.
//
// Example usage:
//
//   std::array<ULONG, kFooStackSizeWords> example_thread_stack;
//   pw::thread::embos::Context example_thread_context(example_thread_stack);
//   void StartExampleThread() {
//      pw::thread::DetachedThread(
//        pw::thread::embos::Options()
//            .set_name("static_example_thread")
//            .set_priority(kFooPriority)
//            .set_context(example_thread_context),
//        example_thread_function);
//   }
class Context {
 public:
  explicit Context(span<OS_UINT> stack_span)
      : tcb_{}, stack_span_(stack_span) {}
  Context(const Context&) = delete;
  Context& operator=(const Context&) = delete;

  // Intended for unit test & Thread use only.
  OS_TASK& tcb() { return tcb_; }

 private:
  friend Thread;

  span<OS_UINT> stack() { return stack_span_; }

  bool in_use() const { return in_use_; }
  void set_in_use(bool in_use = true) { in_use_ = in_use; }

  const char* name() const { return name_.data(); }
  void set_name(const char* name) { string::Copy(name, name_); }

  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; }

#if PW_THREAD_JOINING_ENABLED
  OS_EVENT& join_event_object() { return event_object_; }
#endif  // PW_THREAD_JOINING_ENABLED

  static void ThreadEntryPoint(void* void_context_ptr);
  static void TerminateThread(Context& context);

  OS_TASK tcb_;
  span<OS_UINT> stack_span_;

  ThreadRoutine user_thread_entry_function_ = nullptr;
  void* user_thread_entry_arg_ = nullptr;
#if PW_THREAD_JOINING_ENABLED
  // Note that the embOS life cycle of this event object is managed together
  // with the thread life cycle, not this object's life cycle.
  OS_EVENT event_object_;
#endif  // PW_THREAD_JOINING_ENABLED
  bool in_use_ = false;
  bool detached_ = false;
  bool thread_done_ = false;

  // The TCB does not have storage for the name, ergo we provide storage for
  // the thread's name which can be truncated down to just a null delimiter.
  std::array<char, config::kMaximumNameLength + 1> name_;
};

// Static thread context allocation including the stack along with the Context.
//
// Example usage:
//
//   pw::thread::embos::ContextWithStack<kFooStackSizeWords>
//       example_thread_context;
//   void StartExampleThread() {
//      pw::thread::DetachedThread(
//        pw::thread::embos::Options()
//            .set_name("static_example_thread")
//            .set_priority(kFooPriority)
//            .set_context(example_thread_context),
//        example_thread_function);
//   }
template <size_t kStackSizeWords = config::kDefaultStackSizeWords>
class ContextWithStack final : public Context {
 public:
  constexpr ContextWithStack() : Context(stack_storage_) {
    static_assert(kStackSizeWords >= config::kMinimumStackSizeWords);
  }

 private:
  std::array<OS_UINT, kStackSizeWords> stack_storage_;
};

}  // namespace pw::thread::embos