Allow EAGAIN failures

Certain devices are known to return EAGAIN failures when read
too frequently, so be tolerant of them.

On startup, the code will retry for up to a second to get a good
first reading, and then in the main loop the code will just stick
with the current value if it fails that way.

Resolves openbmc/openbmc#2038

Change-Id: I7621aa30429c43276239982a03ec3eef02ce9c6e
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
diff --git a/mainloop.cpp b/mainloop.cpp
index 14b570f..a07d558 100644
--- a/mainloop.cpp
+++ b/mainloop.cpp
@@ -156,21 +156,38 @@
     auto& obj = std::get<Object>(info);
     auto& objPath = std::get<std::string>(info);
 
-    int val;
-    try
-    {
-        val = sysfs::readSysfsWithCallout(hwmonRoot,
-                                          instance,
-                                          sensor.first,
-                                          sensor.second,
-                                          hwmon::entry::input);
-    }
-    catch(const std::exception& ioe)
-    {
-        using namespace sdbusplus::xyz::openbmc_project::Sensor::Device::Error;
-        commit<ReadFailure>();
+    int val = 0;
+    bool retry = true;
+    size_t count = 10;
 
-        return static_cast<std::shared_ptr<ValueObject>>(nullptr);
+
+    //Retry for up to a second if device is busy
+
+    while (retry)
+    {
+        try
+        {
+            val = sysfs::readSysfsWithCallout(hwmonRoot,
+                    instance,
+                    sensor.first,
+                    sensor.second,
+                    hwmon::entry::input,
+                    count > 0); //throw DeviceBusy until last attempt
+        }
+        catch (sysfs::DeviceBusyException& e)
+        {
+            count--;
+            std::this_thread::sleep_for(std::chrono::milliseconds{100});
+            continue;
+        }
+        catch(const std::exception& ioe)
+        {
+            using namespace sdbusplus::xyz::openbmc_project::Sensor::Device::Error;
+            commit<ReadFailure>();
+
+            return static_cast<std::shared_ptr<ValueObject>>(nullptr);
+        }
+        retry = false;
     }
 
     auto iface = std::make_shared<ValueObject>(bus, objPath.c_str(), deferSignals);
@@ -341,11 +358,21 @@
                 int value;
                 try
                 {
-                    value = sysfs::readSysfsWithCallout(_hwmonRoot,
-                                                        _instance,
-                                                        i.first.first,
-                                                        i.first.second,
-                                                        hwmon::entry::input);
+                    try
+                    {
+                        value = sysfs::readSysfsWithCallout(_hwmonRoot,
+                                _instance,
+                                i.first.first,
+                                i.first.second,
+                                hwmon::entry::input);
+                    }
+                    catch (sysfs::DeviceBusyException& e)
+                    {
+                        //Just go with the current values and try again later.
+                        //TODO: openbmc/openbmc#2048 could keep an eye on
+                        //how long the device is actually busy.
+                        continue;
+                    }
 
                     auto& objInfo = std::get<ObjectInfo>(i.second);
                     auto& obj = std::get<Object>(objInfo);