nvidia-gpu: Fix a number of object lifetime issues

Moves all subsensors and objects treated as shared_ptrs
to be using shared_from_this. This way, if there's an object lifetime
issue we don't segfault.

Also separates construction and asio init for NvidiaSmaDevice
so that when we bind to this, its valid after we leave the ctor

Change-Id: I8e3115bc276d2e0eaac0b1dc9a9d2c46e6751d4b
Signed-off-by: Marc Olberding <molberding@nvidia.com>
diff --git a/src/nvidia-gpu/Inventory.cpp b/src/nvidia-gpu/Inventory.cpp
index 6796a32..e41802a 100644
--- a/src/nvidia-gpu/Inventory.cpp
+++ b/src/nvidia-gpu/Inventory.cpp
@@ -152,9 +152,15 @@
 
     mctpRequester.sendRecvMsg(
         eid, requestBuffer,
-        [this, propertyId](const std::error_code& result,
-                           std::span<const uint8_t> buffer) {
-            this->handleInventoryPropertyResponse(propertyId, result, buffer);
+        [weak{weak_from_this()}, propertyId](const std::error_code& ec,
+                                             std::span<const uint8_t> buffer) {
+            std::shared_ptr<Inventory> self = weak.lock();
+            if (!self)
+            {
+                lg2::error("Invalid Inventory reference");
+                return;
+            }
+            self->handleInventoryPropertyResponse(propertyId, ec, buffer);
         });
 }
 
@@ -277,15 +283,22 @@
         else
         {
             retryTimer.expires_after(retryDelay);
-            retryTimer.async_wait([this](const boost::system::error_code& ec) {
-                if (ec)
-                {
-                    lg2::error("Retry timer error for {NAME}: {ERROR}", "NAME",
-                               name, "ERROR", ec.message());
-                    return;
-                }
-                this->processNextProperty();
-            });
+            retryTimer.async_wait(
+                [weak{weak_from_this()}](const boost::system::error_code& ec) {
+                    std::shared_ptr<Inventory> self = weak.lock();
+                    if (!self)
+                    {
+                        lg2::error("Invalid reference to Inventory");
+                        return;
+                    }
+                    if (ec)
+                    {
+                        lg2::error("Retry timer error for {NAME}: {ERROR}",
+                                   "NAME", self->name, "ERROR", ec.message());
+                        return;
+                    }
+                    self->processNextProperty();
+                });
             return;
         }
     }
diff --git a/src/nvidia-gpu/NvidiaDeviceDiscovery.cpp b/src/nvidia-gpu/NvidiaDeviceDiscovery.cpp
index 9afb000..07b81f1 100644
--- a/src/nvidia-gpu/NvidiaDeviceDiscovery.cpp
+++ b/src/nvidia-gpu/NvidiaDeviceDiscovery.cpp
@@ -106,9 +106,13 @@
             auto smaName = configs.name + "_SMA_" +
                            std::to_string(responseInstanceId);
 
-            smaDevices[smaName] =
-                std::make_shared<SmaDevice>(configs, smaName, path, conn, eid,
-                                            io, mctpRequester, objectServer);
+            auto sma = smaDevices
+                           .insert(std::make_pair(
+                               smaName, std::make_shared<SmaDevice>(
+                                            configs, smaName, path, conn, eid,
+                                            io, mctpRequester, objectServer)))
+                           .first;
+            (*sma).second->init();
             break;
         }
     }
diff --git a/src/nvidia-gpu/NvidiaGpuDevice.cpp b/src/nvidia-gpu/NvidiaGpuDevice.cpp
index 7ec47ff..727c408 100644
--- a/src/nvidia-gpu/NvidiaGpuDevice.cpp
+++ b/src/nvidia-gpu/NvidiaGpuDevice.cpp
@@ -213,11 +213,18 @@
     voltageSensor->update();
 
     waitTimer.expires_after(std::chrono::milliseconds(sensorPollMs));
-    waitTimer.async_wait([this](const boost::system::error_code& ec) {
-        if (ec)
-        {
-            return;
-        }
-        read();
-    });
-};
+    waitTimer.async_wait(
+        [weak{weak_from_this()}](const boost::system::error_code& ec) {
+            std::shared_ptr<GpuDevice> self = weak.lock();
+            if (!self)
+            {
+                lg2::error("Invalid reference to GpuDevice");
+                return;
+            }
+            if (ec)
+            {
+                return;
+            }
+            self->read();
+        });
+}
diff --git a/src/nvidia-gpu/NvidiaGpuEnergySensor.cpp b/src/nvidia-gpu/NvidiaGpuEnergySensor.cpp
index 5d2b9af..a9e309f 100644
--- a/src/nvidia-gpu/NvidiaGpuEnergySensor.cpp
+++ b/src/nvidia-gpu/NvidiaGpuEnergySensor.cpp
@@ -128,7 +128,14 @@
 
     mctpRequester.sendRecvMsg(
         eid, request,
-        [this](const std::error_code& ec, std::span<const uint8_t> buffer) {
-            processResponse(ec, buffer);
+        [weak{weak_from_this()}](const std::error_code& ec,
+                                 std::span<const uint8_t> buffer) {
+            std::shared_ptr<NvidiaGpuEnergySensor> self = weak.lock();
+            if (!self)
+            {
+                lg2::error("invalid reference to NvidiaGpuEnergySensor");
+                return;
+            }
+            self->processResponse(ec, buffer);
         });
 }
diff --git a/src/nvidia-gpu/NvidiaGpuEnergySensor.hpp b/src/nvidia-gpu/NvidiaGpuEnergySensor.hpp
index 1d9d1f5..740f843 100644
--- a/src/nvidia-gpu/NvidiaGpuEnergySensor.hpp
+++ b/src/nvidia-gpu/NvidiaGpuEnergySensor.hpp
@@ -22,7 +22,9 @@
 
 constexpr uint8_t gpuEnergySensorId{0};
 
-struct NvidiaGpuEnergySensor : public Sensor
+struct NvidiaGpuEnergySensor :
+    public Sensor,
+    public std::enable_shared_from_this<NvidiaGpuEnergySensor>
 {
   public:
     NvidiaGpuEnergySensor(
diff --git a/src/nvidia-gpu/NvidiaGpuPowerSensor.cpp b/src/nvidia-gpu/NvidiaGpuPowerSensor.cpp
index b21ce0e..394a370 100644
--- a/src/nvidia-gpu/NvidiaGpuPowerSensor.cpp
+++ b/src/nvidia-gpu/NvidiaGpuPowerSensor.cpp
@@ -131,7 +131,14 @@
 
     mctpRequester.sendRecvMsg(
         eid, request,
-        [this](const std::error_code& ec, std::span<const uint8_t> buffer) {
-            processResponse(ec, buffer);
+        [weak{weak_from_this()}](const std::error_code& ec,
+                                 std::span<const uint8_t> buffer) {
+            std::shared_ptr<NvidiaGpuPowerSensor> self = weak.lock();
+            if (!self)
+            {
+                lg2::error("Invalid reference to NvidiaGpuPowerSensor");
+                return;
+            }
+            self->processResponse(ec, buffer);
         });
 }
diff --git a/src/nvidia-gpu/NvidiaGpuPowerSensor.hpp b/src/nvidia-gpu/NvidiaGpuPowerSensor.hpp
index 8fa967a..555418f 100644
--- a/src/nvidia-gpu/NvidiaGpuPowerSensor.hpp
+++ b/src/nvidia-gpu/NvidiaGpuPowerSensor.hpp
@@ -24,7 +24,9 @@
 
 constexpr uint8_t gpuPowerSensorId{0};
 
-struct NvidiaGpuPowerSensor : public Sensor
+struct NvidiaGpuPowerSensor :
+    public Sensor,
+    public std::enable_shared_from_this<NvidiaGpuPowerSensor>
 {
   public:
     NvidiaGpuPowerSensor(
diff --git a/src/nvidia-gpu/NvidiaGpuSensor.cpp b/src/nvidia-gpu/NvidiaGpuSensor.cpp
index 26fb1c4..7cc1fe0 100644
--- a/src/nvidia-gpu/NvidiaGpuSensor.cpp
+++ b/src/nvidia-gpu/NvidiaGpuSensor.cpp
@@ -126,7 +126,14 @@
 
     mctpRequester.sendRecvMsg(
         eid, getTemperatureReadingRequest,
-        [this](const std::error_code& ec, std::span<const uint8_t> buffer) {
-            processResponse(ec, buffer);
+        [weak{weak_from_this()}](const std::error_code& ec,
+                                 std::span<const uint8_t> buffer) {
+            std::shared_ptr<NvidiaGpuTempSensor> self = weak.lock();
+            if (!self)
+            {
+                lg2::error("Invalid reference to NvidiaGpuTempSensor");
+                return;
+            }
+            self->processResponse(ec, buffer);
         });
 }
diff --git a/src/nvidia-gpu/NvidiaGpuVoltageSensor.cpp b/src/nvidia-gpu/NvidiaGpuVoltageSensor.cpp
index d32f6b2..382a881 100644
--- a/src/nvidia-gpu/NvidiaGpuVoltageSensor.cpp
+++ b/src/nvidia-gpu/NvidiaGpuVoltageSensor.cpp
@@ -126,7 +126,14 @@
 
     mctpRequester.sendRecvMsg(
         eid, request,
-        [this](const std::error_code& ec, std::span<const uint8_t> buffer) {
-            processResponse(ec, buffer);
+        [weak{weak_from_this()}](const std::error_code& ec,
+                                 std::span<const uint8_t> buffer) {
+            std::shared_ptr<NvidiaGpuVoltageSensor> self = weak.lock();
+            if (!self)
+            {
+                lg2::error("invalid reference to NvidiaGpuVoltageSensor");
+                return;
+            }
+            self->processResponse(ec, buffer);
         });
 }
diff --git a/src/nvidia-gpu/NvidiaGpuVoltageSensor.hpp b/src/nvidia-gpu/NvidiaGpuVoltageSensor.hpp
index e5e187a..3aeb1c8 100644
--- a/src/nvidia-gpu/NvidiaGpuVoltageSensor.hpp
+++ b/src/nvidia-gpu/NvidiaGpuVoltageSensor.hpp
@@ -24,7 +24,9 @@
 
 constexpr uint8_t gpuVoltageSensorId{0};
 
-struct NvidiaGpuVoltageSensor : public Sensor
+struct NvidiaGpuVoltageSensor :
+    public Sensor,
+    public std::enable_shared_from_this<NvidiaGpuVoltageSensor>
 {
   public:
     NvidiaGpuVoltageSensor(
diff --git a/src/nvidia-gpu/NvidiaSmaDevice.cpp b/src/nvidia-gpu/NvidiaSmaDevice.cpp
index 755e1f8..71d0f69 100644
--- a/src/nvidia-gpu/NvidiaSmaDevice.cpp
+++ b/src/nvidia-gpu/NvidiaSmaDevice.cpp
@@ -35,6 +35,9 @@
     waitTimer(io, std::chrono::steady_clock::duration(0)),
     mctpRequester(mctpRequester), conn(conn), objectServer(objectServer),
     configs(configs), name(escapeName(name)), path(path)
+{}
+
+void SmaDevice::init()
 {
     makeSensors();
 }
@@ -56,11 +59,18 @@
     tempSensor->update();
 
     waitTimer.expires_after(std::chrono::milliseconds(sensorPollMs));
-    waitTimer.async_wait([this](const boost::system::error_code& ec) {
-        if (ec)
-        {
-            return;
-        }
-        read();
-    });
+    waitTimer.async_wait(
+        [weak{weak_from_this()}](const boost::system::error_code& ec) {
+            std::shared_ptr<SmaDevice> self = weak.lock();
+            if (!self)
+            {
+                lg2::error("Invalid SmaDevice reference");
+                return;
+            }
+            if (ec)
+            {
+                return;
+            }
+            self->read();
+        });
 }
diff --git a/src/nvidia-gpu/NvidiaSmaDevice.hpp b/src/nvidia-gpu/NvidiaSmaDevice.hpp
index fc78de2..2c74892 100644
--- a/src/nvidia-gpu/NvidiaSmaDevice.hpp
+++ b/src/nvidia-gpu/NvidiaSmaDevice.hpp
@@ -20,7 +20,7 @@
 #include <memory>
 #include <string>
 
-class SmaDevice
+class SmaDevice : public std::enable_shared_from_this<SmaDevice>
 {
   public:
     SmaDevice(const SensorConfigs& configs, const std::string& name,
@@ -35,6 +35,8 @@
         return path;
     }
 
+    void init();
+
   private:
     void makeSensors();