libxr
Embedded C++ framework for bare-metal, RTOS and Linux
Loading...
Searching...
No Matches
topic.cpp
1#include "topic.hpp"
2
3#include <atomic>
4
5#include "crc.hpp"
6#include "libxr_def.hpp"
7#include "mutex.hpp"
8
9using namespace LibXR;
10
11template class LibXR::RBTree<uint32_t>;
12
13void Topic::EnsureDomainRegistry()
14{
15 if (!domain_)
16 {
17 domain_ = new RBTree<uint32_t>([](const uint32_t& a, const uint32_t& b)
18 { return (a > b) - (a < b); });
19 }
20}
21
22Topic::Domain* Topic::EnsureDefaultDomain()
23{
24 if (!def_domain_)
25 {
26 def_domain_ = new Domain("libxr_def_domain");
27 }
28
29 return def_domain_;
30}
31
33{
34 if (topic->data_.mutex)
35 {
36 topic->data_.mutex->Lock();
37 }
38 else
39 {
40 LockState expected = LockState::UNLOCKED;
41 if (!topic->data_.busy.compare_exchange_strong(expected, LockState::LOCKED))
42 {
43 // 非 mutex topic 禁止并发发布
44 ASSERT(false);
45 return;
46 }
47 }
48}
49
51{
52 if (topic->data_.mutex)
53 {
54 topic->data_.mutex->Unlock();
55 }
56 else
57 {
58 topic->data_.busy.store(LockState::UNLOCKED, std::memory_order_release);
59 }
60}
61
63{
64 if (topic->data_.mutex)
65 {
66 ASSERT(false);
67 }
68 else
69 {
70 LockState expected = LockState::UNLOCKED;
71 if (!topic->data_.busy.compare_exchange_strong(expected, LockState::LOCKED))
72 {
73 // 回调发布路径要求外围先串行化
74 ASSERT(false);
75 return;
76 }
77 }
78}
79
81{
82 if (topic->data_.mutex)
83 {
84 ASSERT(false);
85 }
86 else
87 {
88 topic->data_.busy.store(LockState::UNLOCKED, std::memory_order_release);
89 }
90}
91
92Topic::Domain::Domain(const char* name)
93{
94 ASSERT(name != nullptr);
95
96 EnsureDomainRegistry();
97
98 auto crc32 = CRC32::Calculate(name, strlen(name));
99
100 auto domain = domain_->Search<RBTree<uint32_t>>(crc32);
101
102 if (domain != nullptr)
103 {
104 node_ = domain;
105 return;
106 }
107
109 [](const uint32_t& a, const uint32_t& b) { return (a > b) - (a < b); });
110
111 domain_->Insert(*node_, crc32);
112}
113
115
116Topic::Topic(const char* name, TypeID::ID payload_type_id, size_t payload_size,
117 size_t payload_alignment, Domain* domain, bool multi_publisher)
118{
119 ASSERT(name != nullptr);
120 ASSERT(payload_type_id != nullptr);
121 ASSERT(payload_size != 0);
122 ASSERT(payload_alignment != 0);
123 ASSERT((payload_alignment & (payload_alignment - 1)) == 0);
124
125 if (domain == nullptr)
126 {
127 domain = EnsureDefaultDomain();
128 }
129
130 auto crc32 = CRC32::Calculate(name, strlen(name));
131
132 auto topic = domain->node_->data_.Search<Block>(crc32);
133
134 if (topic)
135 {
136 RequireTypeContract(topic, payload_type_id, payload_size, payload_alignment);
137
138 if (multi_publisher)
139 {
140 RequireMultiPublisher(topic);
141 }
142
143 block_ = topic;
144 }
145 else
146 {
147 block_ = new RBTree<uint32_t>::Node<Block>;
148 block_->data_.payload_type_id = payload_type_id;
149 block_->data_.payload_size = payload_size;
150 block_->data_.payload_alignment = payload_alignment;
151 block_->data_.crc32 = crc32;
152
153 if (multi_publisher)
154 {
155 block_->data_.mutex = new Mutex();
156 block_->data_.busy.store(LockState::USE_MUTEX, std::memory_order_release);
157 }
158 else
159 {
160 block_->data_.mutex = nullptr;
161 block_->data_.busy.store(LockState::UNLOCKED, std::memory_order_release);
162 }
163
164 domain->node_->data_.Insert(*block_, crc32);
165 }
166}
167
168Topic::Topic(TopicHandle topic) : block_(topic) {}
169
170void Topic::RequireTypeContract(TopicHandle topic, TypeID::ID payload_type_id,
171 size_t payload_size, size_t payload_alignment)
172{
173 const auto& data = topic->data_;
174 REQUIRE(data.payload_type_id == payload_type_id && data.payload_size == payload_size &&
175 data.payload_alignment == payload_alignment);
176}
177
178void Topic::RequireCallbackType(TopicHandle topic, TypeID::ID payload_type_id)
179{
180 REQUIRE(topic->data_.payload_type_id == payload_type_id);
181}
182
183void Topic::RequireMultiPublisher(TopicHandle topic)
184{
185 REQUIRE(topic->data_.mutex != nullptr);
186}
187
188Topic::TopicHandle Topic::Find(const char* name, Domain* domain)
189{
190 ASSERT(name != nullptr);
191
192 if (domain == nullptr)
193 {
194 if (def_domain_ == nullptr)
195 {
196 return nullptr;
197 }
198 domain = def_domain_;
199 }
200
201 auto crc32 = CRC32::Calculate(name, strlen(name));
202
203 return domain->node_->data_.Search<Block>(crc32);
204}
205
206Topic::TopicHandle Topic::WaitTopic(const char* name, uint32_t timeout, Domain* domain)
207{
208 const uint32_t start_time = Thread::GetTime();
209 TopicHandle topic = nullptr;
210 do
211 {
212 topic = Find(name, domain);
213 if (topic == nullptr)
214 {
215 if (timeout != UINT32_MAX &&
216 static_cast<uint32_t>(Thread::GetTime() - start_time) >= timeout)
217 {
218 return nullptr;
219 }
220 Thread::Sleep(1);
221 }
222 } while (topic == nullptr);
223
224 return topic;
225}
226
227uint32_t Topic::GetKey() const
228{
229 if (block_)
230 {
231 return block_->key;
232 }
233 else
234 {
235 return 0;
236 }
237}
static uint32_t Calculate(const void *raw, size_t len)
计算数据的 CRC32 校验码 / Computes the CRC32 checksum for the given data
Definition crc_o3.cpp:35
互斥锁类,提供线程同步机制 Mutex class providing thread synchronization mechanisms.
Definition mutex.hpp:18
Key key
节点键值 / Key associated with the node.
Definition rbt.hpp:40
红黑树的泛型数据节点,继承自 BaseNode Generic data node for Red-Black Tree, inheriting from BaseNode.
Definition rbt.hpp:63
Data data_
存储的数据 / Stored data.
Definition rbt.hpp:98
红黑树实现,支持泛型键和值,并提供线程安全操作 Red-Black Tree implementation supporting generic keys and values with thread-...
Definition rbt.hpp:23
Node< Data > * Search(const Key &key)
搜索红黑树中的节点 / Search for a node in the Red-Black Tree.
Definition rbt.hpp:120
void Insert(BaseNode &node, KeyType &&key)
在树中插入新节点 / Insert a new node into the tree.
Definition rbt.hpp:235
static uint32_t GetTime()
获取当前系统时间(毫秒) Gets the current system time in milliseconds
Definition thread.cpp:35
static void Sleep(uint32_t milliseconds)
让线程进入休眠状态 Puts the thread to sleep
Definition thread.cpp:15
topic 所属的命名域 / Naming domain that groups topics
Definition topic.hpp:207
Domain(const char *name)
构造一个 topic 域 / Construct one topic domain
Definition topic.cpp:92
RBTree< uint32_t >::Node< RBTree< uint32_t > > * node_
Definition topic.hpp:216
static void Unlock(TopicHandle topic)
在普通上下文里释放一个 topic 发布路径 / Unlock one topic publish path in normal context
Definition topic.cpp:50
static void Lock(TopicHandle topic)
在普通上下文里锁住一个 topic 发布路径 / Lock one topic publish path in normal context
Definition topic.cpp:32
static void UnlockFromCallback(TopicHandle topic)
在回调或 ISR 路径里释放一个 topic 发布路径 / Unlock one topic publish path from callback or ISR context
Definition topic.cpp:80
static void LockFromCallback(TopicHandle topic)
在回调或 ISR 路径里锁住一个 topic 发布路径 / Lock one topic publish path from callback or ISR context
Definition topic.cpp:62
static TopicHandle WaitTopic(const char *name, uint32_t timeout=UINT32_MAX, Domain *domain=nullptr)
等待指定名称的 topic 出现 / Wait until a topic with the given name exists
Definition topic.cpp:206
uint32_t GetKey() const
读取 topic 键值 / Read the key value of this topic
Definition topic.cpp:227
static TopicHandle Find(const char *name, Domain *domain=nullptr)
按名称查找一个已存在 topic / Find one existing topic by name
Definition topic.cpp:188
Topic()
构造一个空 topic 视图 / Construct one empty topic view
Definition topic.cpp:114
LibXR 命名空间 / LibXR namespace.
Definition ch32_can.hpp:14
topic 运行时状态块 / Runtime state block of one topic
Definition topic.hpp:82