tin  1.5.9
qnx.h
Go to the documentation of this file.
1 // Copyright (c) 2026 Tinverse LLC. All rights reserved.
2 // SPDX-License-Identifier: LicenseRef-Tinverse-Commercial
3 
12 
13 #pragma once
14 
15 namespace tsm {
16 
18 inline constexpr unsigned qnx_supported_major = 7U;
19 
20 } // namespace tsm
21 
22 #if defined(__QNXNTO__)
23 #include <cstddef>
24 #include <cstdint>
25 #include <sys/neutrino.h>
26 #include <time.h>
27 #include <unistd.h>
28 #include <utility>
29 
30 #include "tsm.h"
31 
32 namespace tsm {
33 
39 struct qnx_tick_source
40 {
41  [[nodiscard]] tsm::tick_rep ticks() const noexcept
42  {
43  return static_cast<tsm::tick_rep>(ClockCycles());
44  }
45 };
46 
52 template<typename... Tasks>
53 class qnx_pulse_task_executor
54 {
55  public:
56  explicit qnx_pulse_task_executor(Tasks&... tasks)
57  : ready_(tasks...)
58  {
59  channel_id_ = ChannelCreate(_NTO_CHF_PRIVATE);
60  if (channel_id_ >= 0) {
61  connection_id_ =
62  ConnectAttach(0, 0, channel_id_, _NTO_SIDE_CHANNEL, 0);
63  }
64  }
65 
66  qnx_pulse_task_executor(qnx_pulse_task_executor const&) = delete;
67  qnx_pulse_task_executor& operator=(qnx_pulse_task_executor const&) = delete;
68 
69  ~qnx_pulse_task_executor()
70  {
71  if (connection_id_ >= 0) {
72  ConnectDetach(connection_id_);
73  }
74  if (channel_id_ >= 0) {
75  ChannelDestroy(channel_id_);
76  }
77  }
78 
79  void start() {}
80  void stop() {}
81 
82  [[nodiscard]] bool valid() const noexcept
83  {
84  return channel_id_ >= 0 && connection_id_ >= 0;
85  }
86 
87  void wake()
88  {
89  if (connection_id_ >= 0) {
90  static_cast<void>(MsgSendPulse(connection_id_, -1, wake_code, 0));
91  }
92  }
93 
94  void wake_from_isr()
95  {
96  wake();
97  }
98 
99  void wait_for_work()
100  {
101  if (channel_id_ < 0) {
102  return;
103  }
104 
105  std::uint64_t timeout_ns = receive_timeout_ns;
106  static_cast<void>(TimerTimeout(CLOCK_MONOTONIC,
107  _NTO_TIMEOUT_RECEIVE,
108  nullptr,
109  &timeout_ns,
110  nullptr));
111 
112  _pulse pulse{};
113  static_cast<void>(
114  MsgReceivePulse(channel_id_, &pulse, sizeof(pulse), nullptr));
115  }
116 
117  [[nodiscard]] bool step()
118  {
119  return ready_.step();
120  }
121 
122  std::size_t run_ready()
123  {
124  const auto ran = ready_.run_ready();
125  if (ran == 0U) {
126  wait_for_work();
127  }
128  return ran;
129  }
130 
131  std::size_t tick(tsm::tick_rep elapsed_ticks = 1U)
132  {
133  const auto resumed = ready_.tick(elapsed_ticks);
134  if (resumed != 0U) {
135  wake();
136  }
137  return resumed;
138  }
139 
140  std::size_t tick(tsm::tick_count elapsed_ticks)
141  {
142  return tick(elapsed_ticks.count());
143  }
144 
145  void start_all()
146  {
147  ready_.start_all();
148  }
149 
150  template<auto Entry, std::size_t Instance = 0U>
151  [[nodiscard]] spawn_result start()
152  {
153  auto result = ready_.template start<Entry, Instance>();
154  if (result == spawn_result::started) {
155  wake();
156  }
157  return result;
158  }
159 
160  template<auto Entry, typename... Args>
161  [[nodiscard]] spawn_result spawn(Args&&... args)
162  {
163  auto result = ready_.template spawn<Entry>(std::forward<Args>(args)...);
164  if (result == spawn_result::started) {
165  wake();
166  }
167  return result;
168  }
169 
170  [[nodiscard]] runtime::task_spawner<qnx_pulse_task_executor> spawner()
171  {
172  return runtime::task_spawner<qnx_pulse_task_executor>{ *this };
173  }
174 
175  template<auto Entry, std::size_t Instance = 0U>
176  [[nodiscard]] task_status task_status() const
177  {
178  return ready_.template task_status<Entry, Instance>();
179  }
180 
181  template<auto Entry, std::size_t Instance = 0U>
182  [[nodiscard]] task_failure_reason task_failure_reason() const
183  {
184  return ready_.template task_failure_reason<Entry, Instance>();
185  }
186 
187  template<auto Entry, std::size_t Instance = 0U>
188  [[nodiscard]] bool cancel() noexcept
189  {
190  const bool cancelled = ready_.template cancel<Entry, Instance>();
191  if (cancelled) {
192  wake();
193  }
194  return cancelled;
195  }
196 
197  void cancel_all() noexcept
198  {
199  ready_.cancel_all();
200  wake();
201  }
202 
203  private:
204  static constexpr int wake_code = _PULSE_CODE_MINAVAIL;
205  static constexpr std::uint64_t receive_timeout_ns = 1'000'000ULL;
206 
207  runtime::cooperative_executor<Tasks...> ready_;
208  int channel_id_{ -1 };
209  int connection_id_{ -1 };
210 };
211 
212 template<typename... Tasks>
213 qnx_pulse_task_executor(Tasks&...) -> qnx_pulse_task_executor<Tasks...>;
214 
215 template<typename... Tasks>
216 using task_executor = qnx_pulse_task_executor<Tasks...>;
217 
218 } // namespace tsm
219 
220 #endif // defined(__QNXNTO__)
task_spawner< Executor > spawner
Definition: executor.h:150
cooperative_executor(Tasks &...) -> cooperative_executor< Tasks... >
Definition: bare_metal.h:20
constexpr unsigned qnx_supported_major
QNX support is intentionally a QNX 7.x target surface.
Definition: qnx.h:18
task_failure_reason
Definition: coroutine.h:170
constexpr tick_count ticks(tick_rep value) noexcept
Definition: ticks.h:85
task_status
Definition: coroutine.h:160
bare_metal_task_executor< Tasks... > task_executor
Definition: bare_metal.h:166
spawn_result
Definition: coroutine.h:181
TSM_TICK_REP tick_rep
Definition: ticks.h:35
Strong value type for semantic scheduler ticks.
Definition: ticks.h:54
constexpr tick_rep count() const noexcept
Definition: ticks.h:73