Ensure PSU sensor values are refreshed

A server managed by OpenBMC may have more than a single power
supply. In the event that one or more PSU's have AC removed, or are
removed from the system, the PSU sensors should reflect the loss of
the input power from the PSU. This condition was not being reflected
when using the current PSU sensor code. AC loss from a single PSU
resulted in the output power value remaining greater than zero. This
was due to the use of the ASIO async_read_until function.

The ASIO async_read_until function can only be used on well behaved
interfaces that will not fail. The hwmon files being read do not
conform. Reads can result in an EAGAIN error code. The
async_read_until documentation states EAGAIN is not handled.

The code changes in this commit are lifted from the IPMB bridge
source. The hwmon file containing the sensor reading is opened so that
it is non-blocking. The sensors are read when the kernel indicates a
change has been made. Subsequent reads occur only after a delay time
has expired in order to prevent too many reads from being performed,
and thus consuming CPU time.

Tested:
The SUT is a dual PSU system.
Both PSU's are enabled at the beginning of the test.
Run 'ipmitool sensor list' and inspect the PSU state
  * All input/output voltages/currents are presented
Remove AC from PSU1
Run the ipmitool command again, and see that the values for PSU1
change state, reflecting the power loss.
  * Prior to this change the output power values stalled
Restore AC to PSU1
Run the ipmitool command again, and see that the values for PSU1
are restored.
Remove AC from PSU2
The ipmitool values will reflect the loss of voltage/current/power
  * Prior to this change the output power values stalled
Restore AC to PSU2
The sensor values for PSU2 will be present again.

Change-Id: Id3fea32722044f3e3b106cd0be11f6f43c038011
Signed-off-by: Kuiying Wang <kuiying.wang@intel.com>
Signed-off-by: Johnathan Mantey <johnathanx.mantey@intel.com>
diff --git a/src/PSUSensor.cpp b/src/PSUSensor.cpp
index 942cfc3..077f7ed 100644
--- a/src/PSUSensor.cpp
+++ b/src/PSUSensor.cpp
@@ -61,7 +61,7 @@
                   << "\"\n";
     }
 
-    fd = open(path.c_str(), O_RDONLY);
+    fd = open(path.c_str(), O_RDONLY | O_NONBLOCK);
     if (fd < 0)
     {
         std::cerr << "PSU sensor failed to open file\n";
@@ -131,20 +131,15 @@
 
 void PSUSensor::setupRead(void)
 {
-    std::shared_ptr<boost::asio::streambuf> buffer =
-        std::make_shared<boost::asio::streambuf>();
     std::weak_ptr<PSUSensor> weakRef = weak_from_this();
-    boost::asio::async_read_until(
-        inputDev, *buffer, '\n',
-        [weakRef, buffer](const boost::system::error_code& ec,
-                          std::size_t /*bytes_transfered*/) {
-            std::shared_ptr<PSUSensor> self = weakRef.lock();
-            if (self)
-            {
-                self->readBuf = buffer;
-                self->handleResponse(ec);
-            }
-        });
+    inputDev.async_wait(boost::asio::posix::descriptor_base::wait_read,
+                        [weakRef](const boost::system::error_code& ec) {
+                            std::shared_ptr<PSUSensor> self = weakRef.lock();
+                            if (self)
+                            {
+                                self->handleResponse(ec);
+                            }
+                        });
 }
 
 void PSUSensor::updateMinMaxValues(void)
@@ -160,6 +155,9 @@
     }
 }
 
+// Create a buffer expected to be able to hold more characters than will be
+// present in the input file.
+static constexpr uint32_t psuBufLen = 128;
 void PSUSensor::handleResponse(const boost::system::error_code& err)
 {
     if ((err == boost::system::errc::bad_file_descriptor) ||
@@ -168,19 +166,18 @@
         std::cerr << "Bad file descriptor from\n";
         return;
     }
-    std::istream responseStream(readBuf.get());
-    if (!err)
+
+    std::string buffer;
+    buffer.resize(psuBufLen);
+    lseek(fd, 0, SEEK_SET);
+    int rdLen = read(fd, buffer.data(), psuBufLen);
+
+    if (rdLen > 0)
     {
-        std::string response;
         try
         {
-            std::getline(responseStream, response);
-            rawValue = std::stod(response);
-            responseStream.clear();
-            double nvalue = rawValue / sensorFactor;
-
-            updateValue(nvalue);
-
+            rawValue = std::stod(buffer);
+            updateValue(rawValue / sensorFactor);
             if (minMaxReadCounter++ % 8 == 0)
             {
                 updateMinMaxValues();
@@ -188,13 +185,13 @@
         }
         catch (const std::invalid_argument&)
         {
-            std::cerr << "Could not parse " << response << "\n";
+            std::cerr << "Could not parse  input from " << path << "\n";
             incrementError();
         }
     }
     else
     {
-        std::cerr << "System error " << err << "\n";
+        std::cerr << "System error: " << errno << " line: " << __LINE__ << "\n";
         incrementError();
     }
 
@@ -203,12 +200,12 @@
 
     std::weak_ptr<PSUSensor> weakRef = weak_from_this();
     waitTimer.async_wait([weakRef](const boost::system::error_code& ec) {
-        std::shared_ptr<PSUSensor> self = weakRef.lock();
         if (ec == boost::asio::error::operation_aborted)
         {
             std::cerr << "Failed to reschedule\n";
             return;
         }
+        std::shared_ptr<PSUSensor> self = weakRef.lock();
         if (self)
         {
             self->setupRead();