| #include "tlbmc/hal/shared_mem/segment_manager.h" |
| |
| #include <cstddef> |
| #include <filesystem> // NOLINT |
| #include <fstream> |
| #include <memory> |
| #include <new> |
| #include <string> |
| #include <string_view> |
| #include <utility> |
| |
| #include "absl/log/log.h" |
| #include "absl/memory/memory.h" |
| #include "boost/interprocess/exceptions.hpp" // NOLINT |
| #include "boost/interprocess/managed_shared_memory.hpp" // NOLINT |
| #include "tlbmc/hal/shared_mem/metrics.h" |
| #include "tlbmc/hal/shared_mem/sensors.h" |
| |
| namespace milotic_tlbmc { |
| |
| constexpr const char* kSharedMemoryName = "TlbmcSharedMemory"; |
| constexpr const char* kMetricsObjectName = "TlbmcMetrics"; |
| constexpr int kMaximumSensorCount = 1024; |
| |
| std::unique_ptr<SegmentManager> SegmentManager::Create( |
| std::string_view initialized_file_path) { |
| if (std::filesystem::exists(initialized_file_path)) { |
| try { |
| boost::interprocess::managed_shared_memory sensors_memory( |
| boost::interprocess::open_only, kSharedMemoryName); |
| return absl::WrapUnique(new SegmentManager(std::move(sensors_memory))); |
| } catch (const boost::interprocess::interprocess_exception& e) { |
| LOG(ERROR) << "Failed to open shared memory: " << e.what(); |
| return nullptr; |
| } |
| } |
| std::filesystem::path path(initialized_file_path); |
| std::filesystem::path directory = path.parent_path(); |
| if (!std::filesystem::exists(directory) && |
| !std::filesystem::create_directories(directory)) { |
| LOG(ERROR) << "Failed to create directory: " << directory; |
| return nullptr; |
| } |
| LOG(WARNING) |
| << "Creating shared memory; this should only happen once per boot."; |
| try { |
| // Times 2 for accounting for overhead. |
| constexpr std::size_t kSharedMemorySize = |
| (kMaximumSensorCount * sizeof(IpcSensor) + sizeof(TlbmcMetrics)) * 2; |
| // Creates the segment. |
| boost::interprocess::managed_shared_memory memory( |
| boost::interprocess::create_only, kSharedMemoryName, kSharedMemorySize); |
| std::ofstream file(std::string{initialized_file_path}); |
| if (!file.is_open()) { |
| LOG(ERROR) << "Failed to open file: " << initialized_file_path; |
| return nullptr; |
| } |
| file << 1; |
| file.flush(); |
| return absl::WrapUnique(new SegmentManager(std::move(memory))); |
| } catch (const boost::interprocess::interprocess_exception& e) { |
| LOG(ERROR) << "Failed to create shared memory: " << e.what(); |
| return nullptr; |
| } |
| return nullptr; |
| } |
| |
| std::unique_ptr<SegmentManager> SegmentManager::Get( |
| std::string_view initialized_file_path) { |
| if (!std::filesystem::exists(initialized_file_path)) { |
| DLOG(WARNING) << "File " << initialized_file_path |
| << " not found. Shared memory is not initialized yet."; |
| return nullptr; |
| } |
| try { |
| boost::interprocess::managed_shared_memory memory( |
| boost::interprocess::open_only, kSharedMemoryName); |
| return absl::WrapUnique(new SegmentManager(std::move(memory))); |
| } catch (const boost::interprocess::interprocess_exception& e) { |
| DLOG(ERROR) << "Failed to open shared memory: " << e.what(); |
| return nullptr; |
| } |
| } |
| |
| IpcSensor* SegmentManager::GetOrCreateSensor(const char* sensor_name) { |
| return memory_.find_or_construct<IpcSensor>(sensor_name, std::nothrow)(); |
| } |
| |
| TlbmcMetrics* SegmentManager::GetOrCreateMetrics() { |
| return memory_.find_or_construct<TlbmcMetrics>(kMetricsObjectName, |
| std::nothrow)(); |
| } |
| |
| } // namespace milotic_tlbmc |