Add Inoitfy for device changes
Watch for i2c device changes and trigger a rescan
if we see any. Also reorder start dependencies in
entity manager to start faster.
Change-Id: I49facfc725c182ae5d75af2b29e6665f2c8ac0e1
Signed-off-by: James Feist <james.feist@linux.intel.com>
diff --git a/src/FruDevice.cpp b/src/FruDevice.cpp
index 4eea9a5..cb268a9 100644
--- a/src/FruDevice.cpp
+++ b/src/FruDevice.cpp
@@ -28,6 +28,7 @@
#include <iostream>
#include <sys/ioctl.h>
#include <regex>
+#include <sys/inotify.h>
namespace fs = std::experimental::filesystem;
static constexpr bool DEBUG = false;
@@ -36,6 +37,8 @@
const static constexpr char *BASEBOARD_FRU_LOCATION =
"/etc/fru/baseboard.fru.bin";
+const static constexpr char *I2C_DEV_LOCATION = "/dev";
+
static constexpr std::array<const char *, 5> FRU_AREAS = {
"INTERNAL", "CHASSIS", "BOARD", "PRODUCT", "MULTIRECORD"};
const static constexpr char *POWER_OBJECT_NAME = "/org/openbmc/control/power0";
@@ -436,45 +439,52 @@
std::shared_ptr<dbus::DbusObject>>
&dbusObjectMap,
std::shared_ptr<dbus::connection> systemBus,
- dbus::DbusObjectServer &objServer)
+ dbus::DbusObjectServer &objServer,
+ std::atomic_bool &pendingCallback)
{
- auto devDir = fs::path("/dev/");
- auto matchString = std::string("i2c*");
- std::vector<fs::path> i2cBuses;
- if (!find_files(devDir, matchString, i2cBuses, 0))
+ do
{
- std::cerr << "unable to find i2c devices\n";
- return;
- }
- // scanning muxes in reverse order seems to have adverse effects
- // sorting this list seems to be a fix for that
- std::sort(i2cBuses.begin(), i2cBuses.end());
- BusMap busMap = FindI2CDevices(i2cBuses);
+ auto devDir = fs::path("/dev/");
+ auto matchString = std::string("i2c*");
+ std::vector<fs::path> i2cBuses;
+ pendingCallback = false;
- for (auto &busObj : dbusObjectMap)
- {
- objServer.remove_object(busObj.second);
- }
-
- dbusObjectMap.clear();
- UNKNOWN_BUS_OBJECT_COUNT = 0;
-
- for (auto &devicemap : busMap)
- {
- for (auto &device : *devicemap.second)
+ if (!find_files(devDir, matchString, i2cBuses, 0))
{
- AddFruObjectToDbus(systemBus, device.second, objServer,
- dbusObjectMap, devicemap.first, device.first);
+ std::cerr << "unable to find i2c devices\n";
+ return;
}
- }
- // todo, get this from a more sensable place
- std::vector<char> baseboardFru;
- if (readBaseboardFru(baseboardFru))
- {
- AddFruObjectToDbus(systemBus, baseboardFru, objServer, dbusObjectMap,
- -1, -1);
- }
+ // scanning muxes in reverse order seems to have adverse effects
+ // sorting this list seems to be a fix for that
+ std::sort(i2cBuses.begin(), i2cBuses.end());
+ BusMap busMap = FindI2CDevices(i2cBuses);
+
+ for (auto &busObj : dbusObjectMap)
+ {
+ objServer.remove_object(busObj.second);
+ }
+
+ dbusObjectMap.clear();
+ UNKNOWN_BUS_OBJECT_COUNT = 0;
+
+ for (auto &devicemap : busMap)
+ {
+ for (auto &device : *devicemap.second)
+ {
+ AddFruObjectToDbus(systemBus, device.second, objServer,
+ dbusObjectMap, devicemap.first,
+ device.first);
+ }
+ }
+ // todo, get this from a more sensable place
+ std::vector<char> baseboardFru;
+ if (readBaseboardFru(baseboardFru))
+ {
+ AddFruObjectToDbus(systemBus, baseboardFru, objServer,
+ dbusObjectMap, -1, -1);
+ }
+ } while (pendingCallback);
}
int main(int argc, char **argv)
@@ -500,27 +510,27 @@
std::shared_ptr<dbus::DbusObject>>
dbusObjectMap;
- rescanBusses(dbusObjectMap, systemBus, objServer);
-
- auto object = std::make_shared<dbus::DbusObject>(
- systemBus, "/xyz/openbmc_project/FruDevice");
- objServer.register_object(object);
auto iface = std::make_shared<dbus::DbusInterface>(
"xyz.openbmc_project.FruDeviceManager", systemBus);
- object->register_interface(iface);
std::atomic_bool threadRunning(false);
+ std::atomic_bool pendingCallback(false);
std::future<void> future;
iface->register_method("ReScan", [&]() {
- if (!threadRunning)
+ bool notRunning = false;
+ if (threadRunning.compare_exchange_strong(notRunning, true))
{
- threadRunning = true;
future = std::async(std::launch::async, [&] {
- rescanBusses(dbusObjectMap, systemBus, objServer);
+ rescanBusses(dbusObjectMap, systemBus, objServer,
+ pendingCallback);
threadRunning = false;
});
}
+ else
+ {
+ pendingCallback = true;
+ }
return std::tuple<>(); // this is a bug in boost-dbus, needs some sort
// of return
});
@@ -541,19 +551,87 @@
auto findPgood = values.find("pgood");
if (findPgood != values.end())
{
- if (!threadRunning)
+ bool notRunning = false;
+ if (threadRunning.compare_exchange_strong(notRunning, true))
{
- threadRunning = true;
future = std::async(std::launch::async, [&] {
- rescanBusses(dbusObjectMap, systemBus, objServer);
+ rescanBusses(dbusObjectMap, systemBus, objServer,
+ pendingCallback);
threadRunning = false;
});
}
+ else
+ {
+ pendingCallback = true;
+ }
}
filter.async_dispatch(eventHandler);
};
filter.async_dispatch(eventHandler);
+ int fd = inotify_init();
+ int wd = inotify_add_watch(fd, I2C_DEV_LOCATION,
+ IN_CREATE | IN_MOVED_TO | IN_DELETE);
+ std::array<char, 4096> readBuffer;
+ std::string pendingBuffer;
+ // monitor for new i2c devices
+ boost::asio::posix::stream_descriptor dirWatch(io, fd);
+ std::function<void(const boost::system::error_code, std::size_t)>
+ watchI2cBusses = [&](const boost::system::error_code &ec,
+ std::size_t bytes_transferred) {
+ if (ec)
+ {
+ std::cout << "Callback Error " << ec << "\n";
+ return;
+ }
+ pendingBuffer += std::string(readBuffer.data(), bytes_transferred);
+ bool devChange = false;
+ while (pendingBuffer.size() > sizeof(inotify_event))
+ {
+ const inotify_event *iEvent =
+ reinterpret_cast<const inotify_event *>(
+ pendingBuffer.data());
+ switch (iEvent->mask)
+ {
+ case IN_CREATE:
+ case IN_MOVED_TO:
+ case IN_DELETE:
+ if (boost::starts_with(std::string(iEvent->name), "i2c"))
+ {
+ devChange = true;
+ }
+ }
+
+ pendingBuffer.erase(0, sizeof(inotify_event) + iEvent->len);
+ }
+ bool notRunning = false;
+ if (devChange &&
+ threadRunning.compare_exchange_strong(notRunning, true))
+ {
+ future = std::async(std::launch::async, [&] {
+ std::this_thread::sleep_for(std::chrono::seconds(2));
+ rescanBusses(dbusObjectMap, systemBus, objServer,
+ pendingCallback);
+ threadRunning = false;
+ });
+ }
+ else if (devChange)
+ {
+ pendingCallback = true;
+ }
+ dirWatch.async_read_some(boost::asio::buffer(readBuffer),
+ watchI2cBusses);
+ };
+
+ dirWatch.async_read_some(boost::asio::buffer(readBuffer), watchI2cBusses);
+
+ // run the intial scan
+ rescanBusses(dbusObjectMap, systemBus, objServer, pendingCallback);
+
+ auto object = std::make_shared<dbus::DbusObject>(
+ systemBus, "/xyz/openbmc_project/FruDevice");
+ objServer.register_object(object);
+ object->register_interface(iface);
io.run();
return 0;