Align the shared memory data better
No more reinterpret_cast, and it's actually guaranteed to end up aligned
the way we want.
Change-Id: Id92f11a3ee85ee023cfa4f19a8847a94ef24f5ef
diff --git a/aos/ipc_lib/lockless_queue_memory.h b/aos/ipc_lib/lockless_queue_memory.h
index 162403a..7cb90e5 100644
--- a/aos/ipc_lib/lockless_queue_memory.h
+++ b/aos/ipc_lib/lockless_queue_memory.h
@@ -55,59 +55,60 @@
// Watcher watchers[config.num_watchers];
// Sender senders[config.num_senders];
+ static constexpr size_t kDataAlignment = alignof(std::max_align_t);
+
// Aligned pointer to where the data starts.
- // Use a 64 bit type to require 64 bit alignment of the data inside.
- uint64_t data[];
+ // Make sure it's of a type which can safely alias with the actual datatype,
+ // and is aligned enough for any of the structs we will access this memory as.
+ alignas(kDataAlignment) char data[];
// Memory size functions for all 4 lists.
size_t SizeOfQueue() { return SizeOfQueue(config); }
static size_t SizeOfQueue(LocklessQueueConfiguration config) {
- return sizeof(AtomicIndex) * config.queue_size;
+ return AlignmentRoundUp(sizeof(AtomicIndex) * config.queue_size);
}
size_t SizeOfMessages() { return SizeOfMessages(config); }
static size_t SizeOfMessages(LocklessQueueConfiguration config) {
- return config.message_size() * config.num_messages();
+ return AlignmentRoundUp(config.message_size() * config.num_messages());
}
size_t SizeOfWatchers() { return SizeOfWatchers(config); }
static size_t SizeOfWatchers(LocklessQueueConfiguration config) {
- return sizeof(Watcher) * config.num_watchers;
+ return AlignmentRoundUp(sizeof(Watcher) * config.num_watchers);
}
size_t SizeOfSenders() { return SizeOfSenders(config); }
static size_t SizeOfSenders(LocklessQueueConfiguration config) {
- return sizeof(Sender) * config.num_senders;
+ return AlignmentRoundUp(sizeof(Sender) * config.num_senders);
}
// Getters for each of the 4 lists.
Sender *GetSender(size_t sender_index) {
- return reinterpret_cast<Sender *>(
- reinterpret_cast<uintptr_t>(&data[0]) + SizeOfQueue() +
- SizeOfMessages() + SizeOfWatchers() + sender_index * sizeof(Sender));
+ return reinterpret_cast<Sender *>(&data[0] + SizeOfQueue() +
+ SizeOfMessages() + SizeOfWatchers() +
+ sender_index * sizeof(Sender));
}
Watcher *GetWatcher(size_t watcher_index) {
- return reinterpret_cast<Watcher *>(reinterpret_cast<uintptr_t>(&data[0]) +
- SizeOfQueue() + SizeOfMessages() +
+ return reinterpret_cast<Watcher *>(&data[0] + SizeOfQueue() +
+ SizeOfMessages() +
watcher_index * sizeof(Watcher));
}
AtomicIndex *GetQueue(uint32_t index) {
- return reinterpret_cast<AtomicIndex *>(
- reinterpret_cast<uintptr_t>(&data[0]) + sizeof(AtomicIndex) * index);
+ return reinterpret_cast<AtomicIndex *>(&data[0] +
+ sizeof(AtomicIndex) * index);
}
// There are num_senders + queue_size messages. The free list is really the
// sender list, since those are messages available to be filled in and sent.
// This removes the need to find lost messages when a sender dies.
Message *GetMessage(Index index) {
- return reinterpret_cast<Message *>(reinterpret_cast<uintptr_t>(&data[0]) +
- SizeOfQueue() +
+ return reinterpret_cast<Message *>(&data[0] + SizeOfQueue() +
index.message_index() * message_size());
}
-
// Helpers to fetch messages from the queue.
Index LoadIndex(QueueIndex index) {
return GetQueue(index.Wrapped())->Load();
@@ -115,6 +116,10 @@
Message *GetMessage(QueueIndex index) {
return GetMessage(LoadIndex(index));
}
+
+ static constexpr size_t AlignmentRoundUp(size_t in) {
+ return (in + kDataAlignment - 1) / kDataAlignment * kDataAlignment;
+ }
};
} // namespace ipc_lib