1 #pragma once 2 3 #include "NVMeSensor.hpp" 4 5 #include <boost/asio/io_context.hpp> 6 #include <boost/asio/steady_timer.hpp> 7 #include <boost/container/flat_map.hpp> 8 9 #include <algorithm> 10 #include <cstddef> 11 #include <list> 12 #include <memory> 13 #include <optional> 14 #include <stdexcept> 15 #include <string> 16 17 class NVMeContext : public std::enable_shared_from_this<NVMeContext> 18 { 19 public: NVMeContext(boost::asio::io_context & io,int rootBus)20 NVMeContext(boost::asio::io_context& io, int rootBus) : 21 scanTimer(io), rootBus(rootBus), pollCursor(sensors.end()) 22 { 23 if (rootBus < 0) 24 { 25 throw std::invalid_argument( 26 "Invalid root bus: Bus ID must not be negative"); 27 } 28 } 29 ~NVMeContext()30 virtual ~NVMeContext() 31 { 32 scanTimer.cancel(); 33 } 34 addSensor(const std::shared_ptr<NVMeSensor> & sensor)35 void addSensor(const std::shared_ptr<NVMeSensor>& sensor) 36 { 37 sensors.emplace_back(sensor); 38 } 39 getSensorAtPath(const std::string & path)40 std::optional<std::shared_ptr<NVMeSensor>> getSensorAtPath( 41 const std::string& path) 42 { 43 for (auto& sensor : sensors) 44 { 45 if (sensor->configurationPath == path) 46 { 47 return sensor; 48 } 49 } 50 51 return std::nullopt; 52 } 53 54 // Post-condition: The sensor list does not contain the provided sensor 55 // Post-condition: pollCursor is a valid iterator for the sensor list removeSensor(const std::shared_ptr<NVMeSensor> & sensor)56 void removeSensor(const std::shared_ptr<NVMeSensor>& sensor) 57 { 58 // Locate the sensor that we're removing in the sensor list 59 auto found = std::find(sensors.begin(), sensors.end(), sensor); 60 61 // If we failed to find the sensor in the list the post-condition is 62 // already satisfied 63 if (found == sensors.end()) 64 { 65 return; 66 } 67 68 // We've found the sensor in the list 69 70 // If we're not actively polling the sensor list, then remove the sensor 71 if (pollCursor == sensors.end()) 72 { 73 sensors.erase(found); 74 return; 75 } 76 77 // We're actively polling the sensor list 78 79 // If we're not polling the specific sensor that has been removed, then 80 // remove the sensor 81 if (*pollCursor != *found) 82 { 83 sensors.erase(found); 84 return; 85 } 86 87 // We're polling the sensor that is being removed 88 89 // Remove the sensor and update the poll cursor so the cursor remains 90 // valid 91 pollCursor = sensors.erase(found); 92 } 93 close()94 virtual void close() 95 { 96 scanTimer.cancel(); 97 } 98 99 virtual void pollNVMeDevices() = 0; 100 101 virtual void readAndProcessNVMeSensor() = 0; 102 103 virtual void processResponse(std::shared_ptr<NVMeSensor>& sensor, void* msg, 104 size_t len) = 0; 105 106 protected: 107 boost::asio::steady_timer scanTimer; 108 int rootBus; // Root bus for this drive 109 std::list<std::shared_ptr<NVMeSensor>> sensors; 110 std::list<std::shared_ptr<NVMeSensor>>::iterator pollCursor; 111 }; 112 113 using NVMEMap = boost::container::flat_map<int, std::shared_ptr<NVMeContext>>; 114 115 NVMEMap& getNVMEMap(); 116