fru-device: Fix bus lock timeout

When we have a bus that can't get scanned, it locks up
on us for a couple minutes, which is much too long. There
was a thread added, but std::future's destructor blocks,
causing the timeout to still happen. Move the close into
the same scope as the std::future to force stop the blocking
i2c transaction so that we can continue. Also create a bus
blacklist that once a bus locks up on us we stop scanning it
so next scan we avoid the bad bus altogether.

Tested: Added bad bus (i2c9) to wfp and startup time was
near normal.

Change-Id: I22e224a69236a6dfe0a1549ed0e4239e22cdf5d2
Signed-off-by: James Feist <james.feist@linux.intel.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0605dd9..6bc5362 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -78,7 +78,6 @@
 add_definitions (-DBOOST_ALL_NO_LIB)
 add_definitions (-DBOOST_NO_RTTI)
 add_definitions (-DBOOST_NO_TYPEID)
-add_definitions (-DBOOST_ASIO_DISABLE_THREADS)
 
 include_directories (${CMAKE_CURRENT_SOURCE_DIR}/include)
 include_directories (${Boost_INCLUDE_DIRS})
@@ -121,7 +120,8 @@
 )
 
 set (PACKAGE_DIR /usr/share/entity-manager/)
-target_compile_definitions (entity-manager PRIVATE PACKAGE_DIR="${PACKAGE_DIR}")
+target_compile_definitions (entity-manager PRIVATE PACKAGE_DIR="${PACKAGE_DIR}"
+                            -DBOOST_ASIO_DISABLE_THREADS)
 install (TARGETS fru-device entity-manager DESTINATION bin)
 install (DIRECTORY configurations DESTINATION ${PACKAGE_DIR})
 install (DIRECTORY overlay_templates DESTINATION ${PACKAGE_DIR})
diff --git a/src/FruDevice.cpp b/src/FruDevice.cpp
index b98615d..9d0beff 100644
--- a/src/FruDevice.cpp
+++ b/src/FruDevice.cpp
@@ -56,6 +56,7 @@
 using DeviceMap = boost::container::flat_map<int, std::vector<char>>;
 using BusMap = boost::container::flat_map<int, std::shared_ptr<DeviceMap>>;
 
+static std::set<size_t> busBlacklist;
 struct FindDevicesWithCallback;
 
 static bool isMuxBus(size_t bus)
@@ -260,9 +261,12 @@
     if (status == std::future_status::timeout)
     {
         std::cerr << "Error reading bus " << bus << "\n";
+        busBlacklist.insert(bus);
+        close(file);
         return -1;
     }
 
+    close(file);
     return future.get();
 }
 
@@ -280,6 +284,10 @@
             busnum.erase(0, lastDash + 1);
         }
         auto bus = std::stoi(busnum);
+        if (busBlacklist.find(bus) != busBlacklist.end())
+        {
+            continue; // skip previously failed busses
+        }
 
         auto file = open(i2cBus.c_str(), O_RDWR);
         if (file < 0)
@@ -307,23 +315,31 @@
         auto& device = busMap[bus];
         device = std::make_shared<DeviceMap>();
 
+        auto callback = [file, device, bus, context]() {
+            //  i2cdetect by default uses the range 0x03 to 0x77, as
+            //  this is  what we have tested with, use this range. Could be
+            //  changed in future.
+            if (DEBUG)
+            {
+                std::cerr << "Scanning bus " << bus << "\n";
+            }
+
+            // fd is closed in this function in case the bus locks up
+            get_bus_frus(file, 0x03, 0x77, bus, device);
+
+            if (DEBUG)
+            {
+                std::cerr << "Done scanning bus " << bus << "\n";
+            }
+        };
         // don't scan muxed buses async as don't want to confuse the mux
         if (isMuxBus(bus))
         {
-            get_bus_frus(file, 0x03, 0x77, bus, device);
-            close(file);
+            callback();
         }
         else
         {
-            io.post([file, device, bus, context] {
-                //  i2cdetect by default uses the range 0x03 to 0x77, as
-                //  this is
-                //  what we
-                //  have tested with, use this range. Could be changed in
-                //  future.
-                get_bus_frus(file, 0x03, 0x77, bus, device);
-                close(file);
-            });
+            io.post(callback);
         }
     }
 }