Apollo 11.0
自动驾驶开放平台
arena_address_allocator.cc
浏览该文件的文档.
1/******************************************************************************
2 * Copyright 2024 The Apollo Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *****************************************************************************/
17
18#include <sys/ipc.h>
19#include <sys/shm.h>
20#include <algorithm>
21#include <string>
22
25
26namespace apollo {
27namespace cyber {
28namespace transport {
29
31 : meta_shm_key_(
32 std::hash<std::string>{}("/apollo/__arena__/__address__/__meta__")),
33 node_shm_key_(
34 std::hash<std::string>{}("/apollo/__arena__/__address__/__node__")),
35 meta_(nullptr),
36 nodes_(nullptr),
37 reclaim_stack_(nullptr) {
38 // TODO(all): configurable and address management for shared memory of cyber
39 meta_shm_address_ = nullptr;
40 // use fixed address
41 node_shm_address_ = reinterpret_cast<void*>(0x7f0000000000);
42
43 // ensure the allocator's segment size is larger
44 // than the actual arena's segment size
45 // otherwise the shmat will fail
46 Init(1024, reinterpret_cast<void*>(
47 0x710000000000), 2ULL * 1024 * 1024 * 1024);
48}
49
51 if (meta_ && meta_->struct_.ref_count_.fetch_sub(1) == 0) {
52 shmdt(meta_);
53 shmctl(shmget(meta_shm_key_, 0, 0), IPC_RMID, nullptr);
54 shmdt(nodes_);
55 shmctl(shmget(node_shm_key_, 0, 0), IPC_RMID, nullptr);
56 }
57}
58
59bool ArenaAddressAllocator::Init(uint64_t capacity, void* base_address,
60 uint64_t address_segment_size) {
61 if (!OpenMetaShm(capacity, base_address, address_segment_size)) {
62 return false;
63 }
64 if (!OpenNodeShm(capacity, base_address, address_segment_size)) {
65 return false;
66 }
67 meta_->struct_.occupied_.store(false);
68 return true;
69}
70
71bool ArenaAddressAllocator::Open(uint64_t key, void* base_address,
72 void** shm_address) {
73 auto shmid = shmget(static_cast<key_t>(key), 0, 0);
74
75 shmid = shmget(static_cast<key_t>(key), 0, 0);
76 if (shmid == -1) {
77 // open failed
78 return false;
79 }
80 *shm_address = shmat(shmid, base_address, 0);
81 if (*shm_address == reinterpret_cast<void*>(-1)) {
82 // shmat failed
83 return false;
84 }
85 return true;
86}
87
88bool ArenaAddressAllocator::OpenOrCreate(uint64_t key, uint64_t size,
89 void* base_address, void** shm_address,
90 bool* is_created) {
91 auto shmid =
92 shmget(static_cast<key_t>(key), size, 0644 | IPC_CREAT | IPC_EXCL);
93
94 if (shmid == -1) {
95 if (errno == EINVAL) {
96 // TODO(all): recreate larger shm
97 } else if (errno == EEXIST) {
98 *is_created = false;
99 return Open(key, base_address, shm_address);
100 } else {
101 return false;
102 }
103 }
104 *shm_address = shmat(shmid, base_address, 0);
105 if (*shm_address == reinterpret_cast<void*>(-1)) {
106 // shmat failed
107 return false;
108 }
109 *is_created = true;
110 return true;
111}
112
113bool ArenaAddressAllocator::OpenMetaShm(uint64_t capacity, void* base_address,
114 uint64_t address_segment_size) {
115 bool is_created = false;
116 bool ret = false;
117 for (uint32_t retry = 0; retry < 2 && !ret;
118 ++retry, ret = OpenOrCreate(
119 meta_shm_key_, sizeof(ArenaAddressAllocatorMeta),
120 meta_shm_address_, reinterpret_cast<void**>(&meta_),
121 &is_created)) {
122 }
123 if (!ret) {
124 // create or open failed
125 return false;
126 }
127 if (!is_created) {
128 meta_->struct_.ref_count_.fetch_add(1);
129 } else {
130 meta_->struct_.version_ = 1;
131 meta_->struct_.capacity_ = capacity;
132 meta_->struct_.base_address_ = base_address;
133 meta_->struct_.address_segment_size_ = address_segment_size;
134 meta_->struct_.root_ = nullptr;
135 meta_->struct_.allocated_index_ = 0;
136 meta_->struct_.reclaim_stack_top_ = 0;
137 meta_->struct_.ref_count_.store(1);
138 }
139 return true;
140}
141
142bool ArenaAddressAllocator::OpenNodeShm(uint64_t capacity, void* base_address,
143 uint64_t address_segment_size) {
144 uint64_t size = sizeof(ArenaAddressAllocatorMeta) +
145 sizeof(ArenaAddressNode) * (capacity + 1) +
146 sizeof(uint64_t) * capacity;
147 bool is_created = false;
148 bool ret = false;
149 for (uint32_t retry = 0; retry < 2 && !ret;
150 ++retry, ret = OpenOrCreate(node_shm_key_, size, node_shm_address_,
151 reinterpret_cast<void**>(&nodes_),
152 &is_created)) {
153 }
154 if (!ret) {
155 // create or open failed
156 return false;
157 }
158
159 reclaim_stack_ = reinterpret_cast<uint64_t*>(
160 reinterpret_cast<uint64_t>(nodes_) + sizeof(ArenaAddressNode) * capacity);
161 return true;
162}
163
165 if (meta_->struct_.reclaim_stack_top_ > 0) {
166 uint64_t index = reclaim_stack_[--meta_->struct_.reclaim_stack_top_];
167 nodes_[index].left_ = nullptr;
168 nodes_[index].right_ = nullptr;
169 nodes_[index].key_ = key;
170 return &nodes_[index];
171 }
172 if (meta_->struct_.allocated_index_ >= meta_->struct_.capacity_) {
173 // TODO(all): expand nodes
174 return nullptr;
175 }
176 nodes_[meta_->struct_.allocated_index_].left_ = nullptr;
177 nodes_[meta_->struct_.allocated_index_].right_ = nullptr;
178 nodes_[meta_->struct_.allocated_index_].key_ = key;
179 nodes_[meta_->struct_.allocated_index_].index_ =
181 return &nodes_[meta_->struct_.allocated_index_++];
182}
183
185 nodes_[node->index_].left_ = nullptr;
186 nodes_[node->index_].right_ = nullptr;
187 nodes_[node->index_].parent_ = nullptr;
188 reclaim_stack_[meta_->struct_.reclaim_stack_top_++] = node->index_;
189}
190
192 uint64_t key) {
193 if (node == nullptr) {
194 return nullptr;
195 }
196 if (key < node->key_) {
197 return FindNode(node->left_, key);
198 } else if (key > node->key_) {
199 return FindNode(node->right_, key);
200 }
201 return node;
202}
203
205 ArenaAddressNode* node, ArenaAddressNode** node_p, ArenaAddressNode* parent,
206 uint64_t key) {
207 if (node == nullptr) {
208 auto target = NewNode(key);
209 *node_p = target;
210 target->parent_ = parent;
211 return target;
212 }
213 if (key < node->key_) {
214 auto target = FindOrInsertNode(node->left_, &(node->left_), node, key);
215 TreeRebalance(node->left_, &(node->left_));
216 return target;
217 } else if (key > node->key_) {
218 auto target = FindOrInsertNode(node->right_, &(node->right_), node, key);
219 TreeRebalance(node->right_, &(node->right_));
220 return target;
221 }
222 // key == node->key_
223 return node;
224}
225
227 ArenaAddressNode** node_p,
228 uint64_t key) {
229 if (!node) {
230 return;
231 }
232 if (!FindNode(node, key)) {
233 return;
234 }
235 if (key < node->key_) {
236 RemoveNode(node->left_, &(node->left_), key);
237 if (TreeBalanceFactor(node) < -1) {
238 TreeRebalance(meta_->struct_.root_, &(meta_->struct_.root_));
239 }
240 return;
241 } else if (key > node->key_) {
242 RemoveNode(node->right_, &(node->right_), key);
243 if (TreeBalanceFactor(node) > 1) {
244 TreeRebalance(meta_->struct_.root_, &(meta_->struct_.root_));
245 }
246 return;
247 }
248 // node->key_ == key
249 // left and right both exist
250 if (node->left_ && node->right_) {
251 if (TreeBalanceFactor(node) > 0) {
252 auto max_p = &(node->left_);
253 auto max = TreeMax(node->left_, &max_p);
254 SwapNodePosition(node, node_p, max, max_p);
255 RemoveNode(max->left_, &(max->left_), key);
256 return;
257 } else {
258 auto min_p = &(node->right_);
259 auto min = TreeMin(node->right_, &min_p);
260 SwapNodePosition(node, node_p, min, min_p);
261 RemoveNode(min->right_, &(min->right_), key);
262 return;
263 }
264 }
265 // left or right exist
266 *node_p = node->left_ ? node->left_ : node->right_;
267 ReclaimNode(node);
268}
269
271 ArenaAddressNode** x_p,
273 ArenaAddressNode** y_p) {
274 if (x == nullptr || y == nullptr) {
275 // cannot swap nullptr
276 return;
277 }
278
279 // swap address
280 *x_p = y;
281 *y_p = x;
282 // swap parent
283 auto parent_x = x->parent_;
284 auto parent_y = y->parent_;
285 x->parent_ = parent_y;
286 y->parent_ = parent_x;
287
288 ArenaAddressNode* tmp = nullptr;
289
290 // swap left
291 tmp = x->left_;
292 x->left_ = y->left_;
293 if (x->left_) {
294 x->left_->parent_ = x;
295 }
296 y->left_ = tmp;
297 if (y->left_) {
298 y->left_->parent_ = y;
299 }
300
301 // swap right
302 tmp = x->right_;
303 x->right_ = y->right_;
304 if (x->right_) {
305 x->right_->parent_ = x;
306 }
307 y->right_ = tmp;
308 if (y->right_) {
309 y->right_->parent_ = y;
310 }
311}
312
314 if (node == nullptr) {
315 return 0;
316 }
317 return 1 + std::max(TreeHeight(node->left_), TreeHeight(node->right_));
318}
319
321 ArenaAddressNode*** node_pp) {
322 if (node == nullptr) {
323 return nullptr;
324 }
325 for (; node->right_;) {
326 *node_pp = &(node->right_);
327 node = node->right_;
328 }
329 return node;
330}
331
333 ArenaAddressNode*** node_pp) {
334 if (node == nullptr) {
335 return nullptr;
336 }
337 for (; node->left_;) {
338 *node_pp = &(node->left_);
339 node = node->left_;
340 }
341 return node;
342}
343
345 if (node == nullptr) {
346 return 0;
347 }
348 return TreeHeight(node->left_) - TreeHeight(node->right_);
349}
350
352 ArenaAddressNode* node, ArenaAddressNode** node_p) {
353 auto parent = node->parent_;
354 auto right = node->right_;
355
356 node->right_ = right->left_;
357 right->left_ = node;
358 node->parent_ = right;
359 *node_p = right;
360 right->parent_ = parent;
361
362 return right;
363}
364
366 ArenaAddressNode* node, ArenaAddressNode** node_p) {
367 auto parent = node->parent_;
368 auto left = node->left_;
369
370 node->left_ = left->right_;
371 left->right_ = node;
372 node->parent_ = left;
373 *node_p = left;
374 left->parent_ = parent;
375
376 return left;
377}
378
384
390
392 ArenaAddressNode* node, ArenaAddressNode** node_p) {
393 if (node == nullptr) {
394 return nullptr;
395 }
396 auto balance_factor = TreeBalanceFactor(node);
397 if (balance_factor > 1) {
398 if (TreeBalanceFactor(node->left_) > 0) {
399 return TreeRotateRight(node, node_p);
400 } else {
401 return TreeRotateLeftRight(node, node_p);
402 }
403 } else if (balance_factor < -1) {
404 if (TreeBalanceFactor(node->right_) < 0) {
405 return TreeRotateLeft(node, node_p);
406 } else {
407 return TreeRotateRightLeft(node, node_p);
408 }
409 }
410 return node;
411}
412
414 bool idle_status = false;
415 bool occupied_status = true;
416 while (!meta_->struct_.occupied_.compare_exchange_strong(
417 idle_status, occupied_status)) {
418 // exchange failed, idle_status is set to true.
419 idle_status = false;
420 std::this_thread::sleep_for(std::chrono::microseconds(1000));
421 }
422 auto node = FindOrInsertNode(meta_->struct_.root_, &(meta_->struct_.root_),
423 nullptr, key);
424 meta_->struct_.occupied_.store(false);
425 if (node == nullptr) {
426 return nullptr;
427 }
428
429 node->ref_count_.fetch_add(1);
430
431 return reinterpret_cast<void*>(
432 reinterpret_cast<uint64_t>(meta_->struct_.base_address_) +
433 meta_->struct_.address_segment_size_ * node->index_);
434}
435
437 bool idle_status = false;
438 bool occupied_status = true;
439 while (!meta_->struct_.occupied_.compare_exchange_strong(
440 idle_status, occupied_status)) {
441 // exchange failed, idle_status is set to true.
442 idle_status = false;
443 std::this_thread::sleep_for(std::chrono::microseconds(1000));
444 }
445 auto node = FindNode(meta_->struct_.root_, key);
446 meta_->struct_.occupied_.store(false);
447 if (node == nullptr) {
448 return;
449 }
450
451 if (node->ref_count_.fetch_sub(1) == 0) {
452 RemoveNode(meta_->struct_.root_, &(meta_->struct_.root_), key);
453 }
454}
455
456} // namespace transport
457} // namespace cyber
458} // namespace apollo
ArenaAddressNode * TreeRotateLeftRight(ArenaAddressNode *node, ArenaAddressNode **node_p)
ArenaAddressNode * TreeMax(ArenaAddressNode *node, ArenaAddressNode ***node_pp)
ArenaAddressNode * TreeRebalance(ArenaAddressNode *node, ArenaAddressNode **node_p)
void SwapNodePosition(ArenaAddressNode *x, ArenaAddressNode **x_p, ArenaAddressNode *y, ArenaAddressNode **y_p)
ArenaAddressNode * TreeRotateLeft(ArenaAddressNode *node, ArenaAddressNode **node_p)
ArenaAddressNode * FindNode(ArenaAddressNode *node, uint64_t key)
bool OpenOrCreate(uint64_t key, uint64_t size, void *base_address, void **shm_address, bool *is_created)
bool Open(uint64_t key, void *base_address, void **shm_address)
bool OpenMetaShm(uint64_t capacity, void *base_address, uint64_t address_segment_size)
ArenaAddressNode * TreeRotateRightLeft(ArenaAddressNode *node, ArenaAddressNode **node_p)
ArenaAddressNode * TreeMin(ArenaAddressNode *node, ArenaAddressNode ***node_pp)
ArenaAddressNode * TreeRotateRight(ArenaAddressNode *node, ArenaAddressNode **node_p)
void RemoveNode(ArenaAddressNode *node, ArenaAddressNode **node_addr, uint64_t key)
bool Init(uint64_t capacity, void *base_address, uint64_t address_segment_size)
ArenaAddressNode * FindOrInsertNode(ArenaAddressNode *node, ArenaAddressNode **node_p, ArenaAddressNode *parent, uint64_t key)
bool OpenNodeShm(uint64_t capacity, void *base_address, uint64_t address_segment_size)
bool Init(const char *binary_name, const std::string &dag_info)
Definition init.cc:99
class register implement
Definition arena_queue.h:37
Definition future.h:29
struct apollo::cyber::transport::ArenaAddressAllocatorMeta::@2 struct_