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/CMakeLists.txt b/CMakeLists.txt
index 7c73b4c..b578ed2 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -38,7 +38,7 @@
ExternalProject_Add(boost-dbus
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/boost-dbus
GIT_REPOSITORY ssh://git-amr-2.devtools.intel.com:29418/openbmc-boost-dbus
- GIT_TAG e7dae9ce93226e6a7bf3d9101f457d29afac40c2
+ GIT_TAG 216455021500e013a8d95a2d412ade31177353b7
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${EXTERNAL_INSTALL_LOCATION} -DBOOST_ROOT=${BOOST_ROOT}
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
diff --git a/src/EntityManager.cpp b/src/EntityManager.cpp
index 19a370b..45d18e9 100644
--- a/src/EntityManager.cpp
+++ b/src/EntityManager.cpp
@@ -36,7 +36,7 @@
constexpr const char *TEMPLATE_CHAR = "$";
constexpr const size_t PROPERTIES_CHANGED_UNTIL_FLUSH_COUNT = 20;
constexpr const size_t MAX_MAPPER_DEPTH = 99;
-constexpr const size_t SLEEP_AFTER_PROPERTIES_CHANGE_SECONDS = 3;
+constexpr const size_t SLEEP_AFTER_PROPERTIES_CHANGE_SECONDS = 5;
namespace fs = std::experimental::filesystem;
struct cmp_str
@@ -87,8 +87,7 @@
void registerCallbacks(
std::vector<std::pair<std::unique_ptr<dbus::match>,
std::shared_ptr<dbus::filter>>> &dbusMatches,
- std::atomic_bool &threadRunning, nlohmann::json &systemConfiguration,
- dbus::DbusObjectServer &objServer);
+ nlohmann::json &systemConfiguration, dbus::DbusObjectServer &objServer);
// calls the mapper to find all exposed objects of an interface type
// and creates a vector<flat_map> that contains all the key value pairs
@@ -867,46 +866,57 @@
void propertiesChangedCallback(
std::vector<std::pair<std::unique_ptr<dbus::match>,
std::shared_ptr<dbus::filter>>> &dbusMatches,
- std::atomic_bool &threadRunning, nlohmann::json &systemConfiguration,
- dbus::DbusObjectServer &objServer, std::shared_ptr<dbus::filter> dbusFilter)
+ nlohmann::json &systemConfiguration, dbus::DbusObjectServer &objServer,
+ std::shared_ptr<dbus::filter> dbusFilter)
{
static std::future<void> future;
+ static std::atomic_bool threadRunning(false);
+ static std::atomic_bool pendingCallback(false);
bool notRunning = false;
if (threadRunning.compare_exchange_strong(notRunning, true))
{
future = std::async(std::launch::async, [&] {
- std::this_thread::sleep_for(
- std::chrono::seconds(SLEEP_AFTER_PROPERTIES_CHANGE_SECONDS));
- auto oldConfiguration = systemConfiguration;
- DBUS_PROBE_OBJECTS.clear();
- rescan(systemConfiguration);
- auto newConfiguration = systemConfiguration;
- for (auto it = newConfiguration.begin();
- it != newConfiguration.end();)
- {
- auto findKey = oldConfiguration.find(it.key());
- if (findKey != oldConfiguration.end())
- {
- it = newConfiguration.erase(it);
- }
- else
- {
- it++;
- }
- }
- // todo: for now, only add new configurations, unload to come later
- // unloadOverlays();
- loadOverlays(newConfiguration);
- // this line to be removed in future
- writeJsonFiles(systemConfiguration);
- // only post new items to bus for now
- postToDbus(newConfiguration, objServer);
- registerCallbacks(dbusMatches, threadRunning, systemConfiguration,
- objServer);
+ do
+ {
+ std::this_thread::sleep_for(std::chrono::seconds(
+ SLEEP_AFTER_PROPERTIES_CHANGE_SECONDS));
+ auto oldConfiguration = systemConfiguration;
+ DBUS_PROBE_OBJECTS.clear();
+ pendingCallback = false;
+ rescan(systemConfiguration);
+ auto newConfiguration = systemConfiguration;
+ for (auto it = newConfiguration.begin();
+ it != newConfiguration.end();)
+ {
+ auto findKey = oldConfiguration.find(it.key());
+ if (findKey != oldConfiguration.end())
+ {
+ it = newConfiguration.erase(it);
+ }
+ else
+ {
+ it++;
+ }
+ }
+
+ registerCallbacks(dbusMatches, systemConfiguration, objServer);
+ // todo: for now, only add new configurations, unload to come
+ // later
+ // unloadOverlays();
+ loadOverlays(newConfiguration);
+ // this line to be removed in future
+ writeJsonFiles(systemConfiguration);
+ // only post new items to bus for now
+ postToDbus(newConfiguration, objServer);
+ } while (pendingCallback);
threadRunning = false;
});
}
+ else
+ {
+ pendingCallback = true;
+ }
if (dbusFilter != nullptr)
{
dbusFilter->async_dispatch([&, dbusFilter](boost::system::error_code ec,
@@ -915,9 +925,8 @@
{
std::cerr << "properties changed callback error " << ec << "\n";
}
- propertiesChangedCallback(dbusMatches, threadRunning,
- systemConfiguration, objServer,
- dbusFilter);
+ propertiesChangedCallback(dbusMatches, systemConfiguration,
+ objServer, dbusFilter);
});
}
}
@@ -925,8 +934,7 @@
void registerCallbacks(
std::vector<std::pair<std::unique_ptr<dbus::match>,
std::shared_ptr<dbus::filter>>> &dbusMatches,
- std::atomic_bool &threadRunning, nlohmann::json &systemConfiguration,
- dbus::DbusObjectServer &objServer)
+ nlohmann::json &systemConfiguration, dbus::DbusObjectServer &objServer)
{
static boost::container::flat_set<std::string> watchedObjects;
@@ -954,8 +962,8 @@
{
std::cerr << "register callbacks callback error " << ec << "\n";
}
- propertiesChangedCallback(dbusMatches, threadRunning,
- systemConfiguration, objServer, filter);
+ propertiesChangedCallback(dbusMatches, systemConfiguration,
+ objServer, filter);
});
dbusMatches.emplace_back(std::move(propertyChange), filter);
}
@@ -966,38 +974,37 @@
// setup connection to dbus
boost::asio::io_service io;
SYSTEM_BUS = std::make_shared<dbus::connection>(io, dbus::bus::system);
+
dbus::DbusObjectServer objServer(SYSTEM_BUS);
SYSTEM_BUS->request_name("xyz.openbmc_project.EntityManager");
-
- nlohmann::json systemConfiguration = nlohmann::json::object();
- rescan(systemConfiguration);
- // this line to be removed in future
- writeJsonFiles(systemConfiguration);
- unloadAllOverlays();
- loadOverlays(systemConfiguration);
- postToDbus(systemConfiguration, objServer);
-
- auto object = std::make_shared<dbus::DbusObject>(
- SYSTEM_BUS, "/xyz/openbmc_project/EntityManager");
- objServer.register_object(object);
- auto iface = std::make_shared<dbus::DbusInterface>(
- "xyz.openbmc_project.EntityManager", SYSTEM_BUS);
- object->register_interface(iface);
-
- std::atomic_bool threadRunning(false);
- // to keep reference to the match / filter objects so they don't get
- // destroyed
std::vector<
std::pair<std::unique_ptr<dbus::match>, std::shared_ptr<dbus::filter>>>
dbusMatches;
+
+ nlohmann::json systemConfiguration = nlohmann::json::object();
+ auto iface = std::make_shared<dbus::DbusInterface>(
+ "xyz.openbmc_project.EntityManager", SYSTEM_BUS);
+ io.post([&]() {
+ unloadAllOverlays();
+ propertiesChangedCallback(dbusMatches, systemConfiguration, objServer,
+ nullptr);
+ auto object = std::make_shared<dbus::DbusObject>(
+ SYSTEM_BUS, "/xyz/openbmc_project/EntityManager");
+ objServer.register_object(object);
+
+ object->register_interface(iface);
+
+ });
+
+ // to keep reference to the match / filter objects so they don't get
+ // destroyed
+
iface->register_method("ReScan", [&]() {
- propertiesChangedCallback(dbusMatches, threadRunning,
- systemConfiguration, objServer, nullptr);
+ propertiesChangedCallback(dbusMatches, systemConfiguration, objServer,
+ nullptr);
return std::tuple<>(); // this is a bug in boost-dbus, needs some sort
// of return
});
- registerCallbacks(dbusMatches, threadRunning, systemConfiguration,
- objServer);
io.run();
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;