blob: 462b2b60e3c2e6694c4c0f77e7d5fd241a9d2cc9 [file] [log] [blame]
Austin Schuh20b2b082019-09-11 20:42:56 -07001#ifndef AOS_IPC_LIB_LOCKLESS_QUEUE_H_
2#define AOS_IPC_LIB_LOCKLESS_QUEUE_H_
3
Austin Schuh20b2b082019-09-11 20:42:56 -07004#include <sys/signalfd.h>
5#include <sys/types.h>
Tyler Chatowbf0609c2021-07-31 16:13:27 -07006
7#include <csignal>
Austin Schuhe516ab02020-05-06 21:37:04 -07008#include <optional>
Brian Silverman177567e2020-08-12 19:51:33 -07009#include <vector>
Austin Schuh20b2b082019-09-11 20:42:56 -070010
Brian Silverman0eaa1da2020-08-12 20:03:52 -070011#include "absl/types/span.h"
Philipp Schrader790cb542023-07-05 21:06:52 -070012
Austin Schuh82ea7382023-07-14 15:17:34 -070013#include "aos/events/context.h"
Austin Schuh20b2b082019-09-11 20:42:56 -070014#include "aos/ipc_lib/aos_sync.h"
Brian Silvermana1652f32020-01-29 20:41:44 -080015#include "aos/ipc_lib/data_alignment.h"
Austin Schuh20b2b082019-09-11 20:42:56 -070016#include "aos/ipc_lib/index.h"
Philipp Schraderab2f8432023-09-17 18:58:06 -070017#include "aos/ipc_lib/robust_ownership_tracker.h"
Austin Schuh20b2b082019-09-11 20:42:56 -070018#include "aos/time/time.h"
Austin Schuh8902fa52021-03-14 22:39:24 -070019#include "aos/uuid.h"
Austin Schuh20b2b082019-09-11 20:42:56 -070020
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -080021namespace aos::ipc_lib {
Austin Schuh20b2b082019-09-11 20:42:56 -070022
23// Structure to hold the state required to wake a watcher.
24struct Watcher {
25 // Mutex that the watcher locks. If the futex is 0 (or FUTEX_OWNER_DIED),
26 // then this watcher is invalid. The futex variable will then hold the tid of
27 // the watcher, or FUTEX_OWNER_DIED if the task died.
28 //
Brian Silvermanfafe1fa2019-12-18 21:42:18 -080029 // Note: this is only modified with the queue_setup_lock lock held, but may
30 // always be read.
Austin Schuh20b2b082019-09-11 20:42:56 -070031 // Any state modification should happen before the lock is acquired.
Philipp Schraderab2f8432023-09-17 18:58:06 -070032 RobustOwnershipTracker ownership_tracker;
Austin Schuh20b2b082019-09-11 20:42:56 -070033
34 // PID of the watcher.
Brian Silvermanfafe1fa2019-12-18 21:42:18 -080035 std::atomic<pid_t> pid;
Austin Schuh20b2b082019-09-11 20:42:56 -070036
37 // RT priority of the watcher.
Brian Silvermanfafe1fa2019-12-18 21:42:18 -080038 std::atomic<int> priority;
Austin Schuh20b2b082019-09-11 20:42:56 -070039};
40
41// Structure to hold the state required to send messages.
42struct Sender {
43 // Mutex that the sender locks. If the futex is 0 (or FUTEX_OWNER_DIED), then
44 // this sender is invalid. The futex variable will then hold the tid of the
45 // sender, or FUTEX_OWNER_DIED if the task died.
46 //
Brian Silvermanfafe1fa2019-12-18 21:42:18 -080047 // Note: this is only modified with the queue_setup_lock lock held, but may
48 // always be read.
Philipp Schraderab2f8432023-09-17 18:58:06 -070049 RobustOwnershipTracker ownership_tracker;
Austin Schuh20b2b082019-09-11 20:42:56 -070050
51 // Index of the message we will be filling out.
52 AtomicIndex scratch_index;
53
54 // Index of the element being swapped with scratch_index, or Invalid if there
55 // is nothing to do.
56 AtomicIndex to_replace;
57};
58
Brian Silverman177567e2020-08-12 19:51:33 -070059// Structure to hold the state required to pin messages.
60struct Pinner {
61 // The same as Sender::tid. See there for docs.
Philipp Schraderab2f8432023-09-17 18:58:06 -070062 RobustOwnershipTracker ownership_tracker;
Brian Silverman177567e2020-08-12 19:51:33 -070063
64 // Queue index of the message we have pinned, or Invalid if there isn't one.
65 AtomicQueueIndex pinned;
66
67 // This should always be valid.
68 //
69 // Note that this is fully independent from pinned. It's just a place to stash
70 // a message, to ensure there's always an unpinned one for a writer to grab.
71 AtomicIndex scratch_index;
72};
73
Austin Schuh20b2b082019-09-11 20:42:56 -070074// Structure representing a message.
75struct Message {
76 struct Header {
77 // Index of this message in the queue. Needs to match the index this
78 // message is written into the queue at. The data in this message is only
79 // valid if it matches the index in the queue both before and after all the
80 // data is read.
81 //
82 // Note: a value of 0xffffffff always means that the contents aren't valid.
83 AtomicQueueIndex queue_index;
84
Brian Silvermanfafe1fa2019-12-18 21:42:18 -080085 // Timestamp of the message. Needs to be monotonically incrementing in the
Austin Schuh20b2b082019-09-11 20:42:56 -070086 // queue, which means that time needs to be re-sampled every time a write
87 // fails.
Austin Schuhb5c6f972021-03-14 21:53:07 -070088 monotonic_clock::time_point monotonic_sent_time;
89 realtime_clock::time_point realtime_sent_time;
Austin Schuhad154822019-12-27 15:45:13 -080090 // Timestamps of the message from the remote node. These are transparently
91 // passed through.
Austin Schuhb5c6f972021-03-14 21:53:07 -070092 monotonic_clock::time_point monotonic_remote_time;
93 realtime_clock::time_point realtime_remote_time;
Austin Schuhac6d89e2024-03-27 14:56:09 -070094 monotonic_clock::time_point monotonic_remote_transmit_time;
Austin Schuhad154822019-12-27 15:45:13 -080095
96 // Queue index from the remote node.
97 uint32_t remote_queue_index;
Austin Schuh20b2b082019-09-11 20:42:56 -070098
Austin Schuh8902fa52021-03-14 22:39:24 -070099 // Remote boot UUID for this message.
Austin Schuha9012be2021-07-21 15:19:11 -0700100 UUID source_boot_uuid;
Austin Schuh8902fa52021-03-14 22:39:24 -0700101
Austin Schuh20b2b082019-09-11 20:42:56 -0700102 size_t length;
103 } header;
104
Brian Silverman0eaa1da2020-08-12 20:03:52 -0700105 // Returns the start of the data buffer, given that message_data_size is
106 // the same one used to allocate this message's memory.
107 char *data(size_t message_data_size) {
108 return RoundedData(message_data_size);
109 }
110 const char *data(size_t message_data_size) const {
111 return RoundedData(message_data_size);
112 }
113
114 // Returns the pre-buffer redzone, given that message_data_size is the same
115 // one used to allocate this message's memory.
116 absl::Span<char> PreRedzone(size_t message_data_size) {
117 char *const end = data(message_data_size);
118 const auto result =
119 absl::Span<char>(&data_pointer[0], end - &data_pointer[0]);
120 DCHECK_LT(result.size(), kChannelDataRedzone + kChannelDataAlignment);
121 return result;
122 }
123 absl::Span<const char> PreRedzone(size_t message_data_size) const {
124 const char *const end = data(message_data_size);
125 const auto result =
126 absl::Span<const char>(&data_pointer[0], end - &data_pointer[0]);
127 DCHECK_LT(result.size(), kChannelDataRedzone + kChannelDataAlignment);
128 return result;
129 }
130
131 // Returns the post-buffer redzone, given that message_data_size is the same
132 // one used to allocate this message's memory.
133 absl::Span<char> PostRedzone(size_t message_data_size, size_t message_size) {
134 DCHECK_LT(message_data_size, message_size);
135 char *const redzone_end = reinterpret_cast<char *>(this) + message_size;
136 char *const data_end = data(message_data_size) + message_data_size;
137 DCHECK_GT(static_cast<void *>(redzone_end), static_cast<void *>(data_end));
138 const auto result = absl::Span<char>(data_end, redzone_end - data_end);
139 DCHECK_LT(result.size(), kChannelDataRedzone + kChannelDataAlignment * 2);
140 return result;
141 }
142 absl::Span<const char> PostRedzone(size_t message_data_size,
143 size_t message_size) const {
144 DCHECK_LT(message_data_size, message_size);
145 const char *const redzone_end =
146 reinterpret_cast<const char *>(this) + message_size;
147 const char *const data_end = data(message_data_size) + message_data_size;
148 DCHECK_GT(static_cast<const void *>(redzone_end),
149 static_cast<const void *>(data_end));
150 const auto result =
151 absl::Span<const char>(data_end, redzone_end - data_end);
152 DCHECK_LT(result.size(), kChannelDataRedzone + kChannelDataAlignment * 2);
153 return result;
Brian Silvermana1652f32020-01-29 20:41:44 -0800154 }
155
156 private:
Brian Silverman0eaa1da2020-08-12 20:03:52 -0700157 // This returns a non-const pointer into a const object. Be very careful
158 // about const correctness in publicly accessible APIs using it.
159 char *RoundedData(size_t message_data_size) const {
160 return RoundChannelData(
161 const_cast<char *>(&data_pointer[0] + kChannelDataRedzone),
162 message_data_size);
Brian Silvermana1652f32020-01-29 20:41:44 -0800163 }
164
165 char data_pointer[];
Austin Schuh20b2b082019-09-11 20:42:56 -0700166};
167
168struct LocklessQueueConfiguration {
169 // Size of the watchers list.
170 size_t num_watchers;
171 // Size of the sender list.
172 size_t num_senders;
Brian Silverman177567e2020-08-12 19:51:33 -0700173 // Size of the pinner list.
174 size_t num_pinners;
Austin Schuh20b2b082019-09-11 20:42:56 -0700175
176 // Size of the list of pointers into the messages list.
177 size_t queue_size;
178 // Size in bytes of the data stored in each Message.
179 size_t message_data_size;
180
Austin Schuh4bc4f902019-12-23 18:04:51 -0800181 size_t message_size() const;
Austin Schuh20b2b082019-09-11 20:42:56 -0700182
Brian Silverman177567e2020-08-12 19:51:33 -0700183 size_t num_messages() const { return num_senders + num_pinners + queue_size; }
Austin Schuh20b2b082019-09-11 20:42:56 -0700184};
185
186// Structure to hold the state of the queue.
187//
188// Reads and writes are lockless and constant time.
189//
190// Adding a new watcher doesn't need to be constant time for the watcher (this
191// is done before the watcher goes RT), but needs to be RT for the sender.
192struct LocklessQueueMemory;
193
Brian Silvermanfc0d2e82020-08-12 19:58:35 -0700194// Returns the size of the LocklessQueueMemory.
195size_t LocklessQueueMemorySize(LocklessQueueConfiguration config);
196
Austin Schuh20b2b082019-09-11 20:42:56 -0700197// Initializes the queue memory. memory must be either a valid pointer to the
198// queue datastructure, or must be zero initialized.
199LocklessQueueMemory *InitializeLocklessQueueMemory(
200 LocklessQueueMemory *memory, LocklessQueueConfiguration config);
201
Alex Perrycb7da4b2019-08-28 19:35:56 -0700202const static unsigned int kWakeupSignal = SIGRTMIN + 2;
Austin Schuh20b2b082019-09-11 20:42:56 -0700203
Philipp Schraderab2f8432023-09-17 18:58:06 -0700204// Sets FUTEX_OWNER_DIED if the owner was tid. This fakes what the kernel does
205// with a robust mutex.
206bool PretendThatOwnerIsDeadForTesting(aos_mutex *mutex, pid_t tid);
207
Brian Silvermanfc0d2e82020-08-12 19:58:35 -0700208// A convenient wrapper for accessing a lockless queue.
Austin Schuh20b2b082019-09-11 20:42:56 -0700209class LocklessQueue {
210 public:
Brian Silvermanfc0d2e82020-08-12 19:58:35 -0700211 LocklessQueue(const LocklessQueueMemory *const_memory,
212 LocklessQueueMemory *memory, LocklessQueueConfiguration config)
213 : const_memory_(const_memory), memory_(memory), config_(config) {}
Austin Schuh20b2b082019-09-11 20:42:56 -0700214
Brian Silvermanfc0d2e82020-08-12 19:58:35 -0700215 void Initialize();
Austin Schuh20b2b082019-09-11 20:42:56 -0700216
Brian Silvermanfc0d2e82020-08-12 19:58:35 -0700217 LocklessQueueConfiguration config() const { return config_; }
Austin Schuh20b2b082019-09-11 20:42:56 -0700218
Brian Silvermanfc0d2e82020-08-12 19:58:35 -0700219 const LocklessQueueMemory *const_memory() { return const_memory_; }
220 LocklessQueueMemory *memory() { return memory_; }
Alex Perrycb7da4b2019-08-28 19:35:56 -0700221
Brian Silvermanfc0d2e82020-08-12 19:58:35 -0700222 private:
223 const LocklessQueueMemory *const_memory_;
224 LocklessQueueMemory *memory_;
225 LocklessQueueConfiguration config_;
226};
227
228class LocklessQueueWatcher {
229 public:
230 LocklessQueueWatcher(const LocklessQueueWatcher &) = delete;
231 LocklessQueueWatcher &operator=(const LocklessQueueWatcher &) = delete;
232 LocklessQueueWatcher(LocklessQueueWatcher &&other)
233 : memory_(other.memory_), watcher_index_(other.watcher_index_) {
234 other.watcher_index_ = -1;
235 }
236 LocklessQueueWatcher &operator=(LocklessQueueWatcher &&other) {
237 std::swap(memory_, other.memory_);
238 std::swap(watcher_index_, other.watcher_index_);
239 return *this;
240 }
241
242 ~LocklessQueueWatcher();
243
244 // Registers this thread to receive the kWakeupSignal signal when
245 // LocklessQueueWakeUpper::Wakeup is called. Returns nullopt if there was an
246 // error in registration.
247 // TODO(austin): Change the API if we find ourselves with more errors.
248 static std::optional<LocklessQueueWatcher> Make(LocklessQueue queue,
249 int priority);
250
251 private:
252 LocklessQueueWatcher(LocklessQueueMemory *memory, int priority);
253
254 LocklessQueueMemory *memory_ = nullptr;
255
256 // Index in the watcher list that our entry is, or -1 if no watcher is
257 // registered.
258 int watcher_index_ = -1;
259};
260
261class LocklessQueueWakeUpper {
262 public:
263 LocklessQueueWakeUpper(LocklessQueue queue);
Austin Schuh20b2b082019-09-11 20:42:56 -0700264
265 // Sends the kWakeupSignal to all threads which have called RegisterWakeup.
266 //
267 // priority of 0 means nonrt. nonrt could have issues, so we don't PI boost
268 // if nonrt.
269 int Wakeup(int current_priority);
270
Austin Schuh20b2b082019-09-11 20:42:56 -0700271 private:
Austin Schuh20b2b082019-09-11 20:42:56 -0700272 // Memory and datastructure used to sort a list of watchers to wake
273 // up. This isn't a copy of Watcher since tid is simpler to work with here
274 // than the futex above.
275 struct WatcherCopy {
Philipp Schraderab2f8432023-09-17 18:58:06 -0700276 ThreadOwnerStatusSnapshot ownership_snapshot;
Austin Schuh20b2b082019-09-11 20:42:56 -0700277 pid_t pid;
278 int priority;
279 };
Austin Schuh20b2b082019-09-11 20:42:56 -0700280
Brian Silvermanfc0d2e82020-08-12 19:58:35 -0700281 const LocklessQueueMemory *const memory_;
Austin Schuh20b2b082019-09-11 20:42:56 -0700282 const int pid_;
283 const uid_t uid_;
Brian Silvermanfc0d2e82020-08-12 19:58:35 -0700284
285 ::std::vector<WatcherCopy> watcher_copy_;
Austin Schuh20b2b082019-09-11 20:42:56 -0700286};
287
Brian Silvermanfc0d2e82020-08-12 19:58:35 -0700288// Sender for blocks of data. The resources associated with a sender are
289// scoped to this object's lifetime.
290class LocklessQueueSender {
291 public:
Eric Schmiedebergef44b8a2022-02-28 17:30:38 -0700292 // Enum of possible sending errors
293 // Send returns GOOD if the messages was sent successfully, INVALID_REDZONE if
294 // one of a message's redzones has invalid data, or MESSAGES_SENT_TOO_FAST if
295 // more than queue_size messages were going to be sent in a
296 // channel_storage_duration_.
297 enum class Result { GOOD, INVALID_REDZONE, MESSAGES_SENT_TOO_FAST };
298
Brian Silvermanfc0d2e82020-08-12 19:58:35 -0700299 LocklessQueueSender(const LocklessQueueSender &) = delete;
300 LocklessQueueSender &operator=(const LocklessQueueSender &) = delete;
301 LocklessQueueSender(LocklessQueueSender &&other)
Eric Schmiedebergef44b8a2022-02-28 17:30:38 -0700302 : memory_(other.memory_),
303 sender_index_(other.sender_index_),
304 channel_storage_duration_(other.channel_storage_duration_) {
Brian Silvermanfc0d2e82020-08-12 19:58:35 -0700305 other.memory_ = nullptr;
306 other.sender_index_ = -1;
307 }
308 LocklessQueueSender &operator=(LocklessQueueSender &&other) {
309 std::swap(memory_, other.memory_);
310 std::swap(sender_index_, other.sender_index_);
311 return *this;
312 }
313
314 ~LocklessQueueSender();
315
316 // Creates a sender. If we couldn't allocate a sender, returns nullopt.
317 // TODO(austin): Change the API if we find ourselves with more errors.
Eric Schmiedebergef44b8a2022-02-28 17:30:38 -0700318 static std::optional<LocklessQueueSender> Make(
319 LocklessQueue queue, monotonic_clock::duration channel_storage_duration);
Brian Silvermanfc0d2e82020-08-12 19:58:35 -0700320
321 // Sends a message without copying the data.
322 // Copy at most size() bytes of data into the memory pointed to by Data(),
323 // and then call Send().
324 // Note: calls to Data() are expensive enough that you should cache it.
325 size_t size() const;
326 void *Data();
Eric Schmiedebergef44b8a2022-02-28 17:30:38 -0700327 LocklessQueueSender::Result Send(
328 size_t length, monotonic_clock::time_point monotonic_remote_time,
329 realtime_clock::time_point realtime_remote_time,
Austin Schuhac6d89e2024-03-27 14:56:09 -0700330 monotonic_clock::time_point monotonic_remote_transmit_time,
Eric Schmiedebergef44b8a2022-02-28 17:30:38 -0700331 uint32_t remote_queue_index, const UUID &source_boot_uuid,
332 monotonic_clock::time_point *monotonic_sent_time = nullptr,
333 realtime_clock::time_point *realtime_sent_time = nullptr,
334 uint32_t *queue_index = nullptr);
Brian Silvermanfc0d2e82020-08-12 19:58:35 -0700335
336 // Sends up to length data. Does not wakeup the target.
Eric Schmiedebergef44b8a2022-02-28 17:30:38 -0700337 LocklessQueueSender::Result Send(
338 const char *data, size_t length,
339 monotonic_clock::time_point monotonic_remote_time,
340 realtime_clock::time_point realtime_remote_time,
Austin Schuhac6d89e2024-03-27 14:56:09 -0700341 monotonic_clock::time_point monotonic_remote_transmit_time,
Eric Schmiedebergef44b8a2022-02-28 17:30:38 -0700342 uint32_t remote_queue_index, const UUID &source_boot_uuid,
343 monotonic_clock::time_point *monotonic_sent_time = nullptr,
344 realtime_clock::time_point *realtime_sent_time = nullptr,
345 uint32_t *queue_index = nullptr);
Brian Silvermanfc0d2e82020-08-12 19:58:35 -0700346
347 int buffer_index() const;
348
349 private:
Eric Schmiedebergef44b8a2022-02-28 17:30:38 -0700350 LocklessQueueSender(LocklessQueueMemory *memory,
351 monotonic_clock::duration channel_storage_duration);
Brian Silvermanfc0d2e82020-08-12 19:58:35 -0700352
353 // Pointer to the backing memory.
354 LocklessQueueMemory *memory_ = nullptr;
355
356 // Index into the sender list.
357 int sender_index_ = -1;
Eric Schmiedebergef44b8a2022-02-28 17:30:38 -0700358
359 // Storage duration of the channel used to check if messages were sent too
360 // fast
361 const monotonic_clock::duration channel_storage_duration_;
Brian Silvermanfc0d2e82020-08-12 19:58:35 -0700362};
363
Eric Schmiedebergef44b8a2022-02-28 17:30:38 -0700364std::ostream &operator<<(std::ostream &os, const LocklessQueueSender::Result r);
365
Brian Silvermanfc0d2e82020-08-12 19:58:35 -0700366// Pinner for blocks of data. The resources associated with a pinner are
367// scoped to this object's lifetime.
368class LocklessQueuePinner {
369 public:
370 LocklessQueuePinner(const LocklessQueuePinner &) = delete;
371 LocklessQueuePinner &operator=(const LocklessQueuePinner &) = delete;
372 LocklessQueuePinner(LocklessQueuePinner &&other)
373 : memory_(other.memory_),
374 const_memory_(other.const_memory_),
375 pinner_index_(other.pinner_index_) {
376 other.pinner_index_ = -1;
377 }
378 LocklessQueuePinner &operator=(LocklessQueuePinner &&other) {
379 std::swap(memory_, other.memory_);
380 std::swap(const_memory_, other.const_memory_);
381 std::swap(pinner_index_, other.pinner_index_);
382 return *this;
383 }
384
385 ~LocklessQueuePinner();
386
387 // Creates a pinner. If we couldn't allocate a pinner, returns nullopt.
388 // TODO(austin): Change the API if we find ourselves with more errors.
389 static std::optional<LocklessQueuePinner> Make(LocklessQueue queue);
390
391 // Attempts to pin the message at queue_index.
392 // Un-pins the previous message.
393 // Returns the buffer index (non-negative) if it succeeds.
394 // Returns -1 if that message is no longer in the queue.
395 int PinIndex(uint32_t queue_index);
396
397 // Read at most size() bytes of data into the memory pointed to by Data().
398 // Note: calls to Data() are expensive enough that you should cache it.
399 // Don't call Data() before a successful PinIndex call.
400 size_t size() const;
401 const void *Data() const;
402
403 private:
404 LocklessQueuePinner(LocklessQueueMemory *memory,
405 const LocklessQueueMemory *const_memory);
406
407 // Pointer to the backing memory.
408 LocklessQueueMemory *memory_ = nullptr;
409 const LocklessQueueMemory *const_memory_ = nullptr;
410
411 // Index into the pinner list.
412 int pinner_index_ = -1;
413};
414
415class LocklessQueueReader {
416 public:
Austin Schuh82ea7382023-07-14 15:17:34 -0700417 enum class Result {
418 // Message we read was too old and no longer is in the queue.
419 TOO_OLD,
420 // Success!
421 GOOD,
422 // The message is in the future and we haven't written it yet.
423 NOTHING_NEW,
Austin Schuhfaec51a2023-09-08 17:43:32 -0700424 // There is a message, but should_read_callback() returned false so we
425 // didn't fetch it.
Austin Schuh82ea7382023-07-14 15:17:34 -0700426 FILTERED,
427 // The message got overwritten while we were reading it.
428 OVERWROTE,
429 };
Brian Silvermanfc0d2e82020-08-12 19:58:35 -0700430
Austin Schuhfaec51a2023-09-08 17:43:32 -0700431 LocklessQueueReader(LocklessQueue queue)
432 : memory_(queue.memory()), const_memory_(queue.const_memory()) {
Brian Silvermanfc0d2e82020-08-12 19:58:35 -0700433 queue.Initialize();
434 }
435
436 // If you ask for a queue index 2 past the newest, you will still get
437 // NOTHING_NEW until that gets overwritten with new data. If you ask for an
438 // element newer than QueueSize() from the current message, we consider it
439 // behind by a large amount and return TOO_OLD. If the message is modified
Austin Schuh82ea7382023-07-14 15:17:34 -0700440 // out from underneath us as we read it, return OVERWROTE. If we found a new
441 // message, but the filter function returned false, return FILTERED.
Brian Silvermanfc0d2e82020-08-12 19:58:35 -0700442 //
443 // data may be nullptr to indicate the data should not be copied.
Austin Schuhfaec51a2023-09-08 17:43:32 -0700444 Result Read(
445 uint32_t queue_index, monotonic_clock::time_point *monotonic_sent_time,
446 realtime_clock::time_point *realtime_sent_time,
447 monotonic_clock::time_point *monotonic_remote_time,
Austin Schuhac6d89e2024-03-27 14:56:09 -0700448 monotonic_clock::time_point *monotonic_remote_transmit_time,
Austin Schuhfaec51a2023-09-08 17:43:32 -0700449 realtime_clock::time_point *realtime_remote_time,
450 uint32_t *remote_queue_index, UUID *source_boot_uuid, size_t *length,
451 char *data,
452 std::function<bool(const Context &context)> should_read_callback) const;
Brian Silvermanfc0d2e82020-08-12 19:58:35 -0700453
454 // Returns the index to the latest queue message. Returns empty_queue_index()
455 // if there are no messages in the queue. Do note that this index wraps if
456 // more than 2^32 messages are sent.
457 QueueIndex LatestIndex() const;
458
459 private:
Austin Schuhfaec51a2023-09-08 17:43:32 -0700460 LocklessQueueMemory *const memory_;
461 const LocklessQueueMemory *const_memory_;
Brian Silvermanfc0d2e82020-08-12 19:58:35 -0700462};
463
464// Returns the number of messages which are logically in the queue at a time.
465size_t LocklessQueueSize(const LocklessQueueMemory *memory);
466
467// Returns the number of bytes queue users are allowed to read/write within each
468// message.
469size_t LocklessQueueMessageDataSize(const LocklessQueueMemory *memory);
470
471// TODO(austin): Return the oldest queue index. This lets us catch up nicely
472// if we got behind.
473// The easiest way to implement this is likely going to be to reserve the
474// first modulo of values for the initial time around, and never reuse them.
475// That lets us do a simple atomic read of the next index and deduce what has
476// happened. It will involve the simplest atomic operations.
477
478// TODO(austin): Make it so we can find the indices which were sent just
479// before and after a time with a binary search.
480
481// Prints to stdout the data inside the queue for debugging.
Austin Schuh83cbb1e2023-06-23 12:59:02 -0700482void PrintLocklessQueueMemory(const LocklessQueueMemory *memory);
Brian Silvermanfc0d2e82020-08-12 19:58:35 -0700483
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -0800484} // namespace aos::ipc_lib
Austin Schuh20b2b082019-09-11 20:42:56 -0700485
486#endif // AOS_IPC_LIB_LOCKLESS_QUEUE_H_