summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--occ_device.cpp23
-rw-r--r--occ_device.hpp60
-rw-r--r--occ_errors.cpp9
-rw-r--r--occ_errors.hpp19
-rw-r--r--occ_status.hpp5
-rw-r--r--test/Makefile.am3
-rw-r--r--test/error_files_tests.cpp103
-rw-r--r--test/utest.cpp25
8 files changed, 218 insertions, 29 deletions
diff --git a/occ_device.cpp b/occ_device.cpp
index b05dc09..6cd6a1f 100644
--- a/occ_device.cpp
+++ b/occ_device.cpp
@@ -12,10 +12,31 @@ namespace occ
fs::path Device::bindPath = fs::path(OCC_HWMON_PATH) / "bind";
fs::path Device::unBindPath = fs::path(OCC_HWMON_PATH) / "unbind";
+std::string Device::getPathBack(const fs::path& path)
+{
+ if (path.empty())
+ return std::string();
+
+ // Points to the last element in the path
+ auto conf = --path.end();
+
+ // The last element will be '.' if the path ends in '/'
+ // This behavior differs between filesystem and experimental::filesystem
+ // Verify there is an element before too
+ if (!conf->compare(".") && conf != path.begin())
+ {
+ return *(--conf);
+ }
+ else
+ {
+ return *conf;
+ }
+}
+
bool Device::master() const
{
int master;
- auto masterFile = fs::path(DEV_PATH) / config / "occ_master";
+ auto masterFile = devPath / "occ_master";
std::ifstream file(masterFile, std::ios::in);
if (!file)
diff --git a/occ_device.hpp b/occ_device.hpp
index 448253a..937c6dc 100644
--- a/occ_device.hpp
+++ b/occ_device.hpp
@@ -8,6 +8,7 @@
#include <experimental/filesystem>
#include <fstream>
+#include <org/open_power/OCC/Device/error.hpp>
namespace open_power
{
@@ -17,6 +18,7 @@ namespace occ
class Manager;
class Status;
namespace fs = std::experimental::filesystem;
+using namespace sdbusplus::org::open_power::OCC::Device::Error;
/** @class Device
* @brief Binds and unbinds the OCC driver upon request
@@ -34,25 +36,25 @@ class Device
/** @brief Constructs the Device object
*
* @param[in] event - Unique ptr reference to sd_event
- * @param[in] name - OCC instance name
+ * @param[in] path - Path to the OCC instance
* @param[in] manager - OCC manager instance
* @param[in] callback - Optional callback on errors
*/
- Device(EventPtr& event, const std::string& name, const Manager& manager,
+ Device(EventPtr& event, const fs::path& path, const Manager& manager,
Status& status, std::function<void(bool)> callBack = nullptr) :
- config(name),
- errorFile(fs::path(config) / "occ_error"), statusObject(status),
- error(event, errorFile, callBack),
- presence(event, fs::path(config) / "occs_present", manager, callBack),
+ config(getPathBack(path)),
+ devPath(path), statusObject(status),
+ error(event, path / "occ_error", callBack),
+ presence(event, path / "occs_present", manager, callBack),
throttleProcTemp(
- event, fs::path(config) / "occ_dvfs_ot",
+ event, path / "occ_dvfs_overtemp",
std::bind(std::mem_fn(&Device::throttleProcTempCallback), this,
std::placeholders::_1)),
throttleProcPower(
- event, fs::path(config) / "occ_dvfs_power",
+ event, path / "occ_dvfs_power",
std::bind(std::mem_fn(&Device::throttleProcPowerCallback), this,
std::placeholders::_1)),
- throttleMemTemp(event, fs::path(config) / "occ_mem_throttle",
+ throttleMemTemp(event, path / "occ_mem_throttle",
std::bind(std::mem_fn(&Device::throttleMemTempCallback),
this, std::placeholders::_1))
{
@@ -86,13 +88,29 @@ class Device
return fs::exists(OCC_HWMON_PATH + config);
}
- /** @brief Starts to monitor for errors */
- inline void addErrorWatch()
+ /** @brief Starts to monitor for errors
+ *
+ * @param[in] poll - Indicates whether or not the error file should
+ * actually be polled for changes. Disabling polling is
+ * necessary for error files that don't support the poll
+ * file operation.
+ */
+ inline void addErrorWatch(bool poll = true)
{
- throttleProcTemp.addWatch();
- throttleProcPower.addWatch();
- throttleMemTemp.addWatch();
- error.addWatch();
+ try
+ {
+ throttleProcTemp.addWatch(poll);
+ }
+ catch (const OpenFailure& e)
+ {
+ // try the old kernel version
+ throttleProcTemp.setFile(devPath / "occ_dvfs_ot");
+ throttleProcTemp.addWatch(poll);
+ }
+
+ throttleProcPower.addWatch(poll);
+ throttleMemTemp.addWatch(poll);
+ error.addWatch(poll);
}
/** @brief stops monitoring for errors */
@@ -101,7 +119,6 @@ class Device
// we can always safely remove watch even if we don't add it
presence.removeWatch();
error.removeWatch();
- error.removeWatch();
throttleMemTemp.removeWatch();
throttleProcPower.removeWatch();
throttleProcTemp.removeWatch();
@@ -116,12 +133,19 @@ class Device
}
}
+ /** @brief helper function to get the last part of the path
+ *
+ * @param[in] path - Path to parse
+ * @return - Last directory name in the path
+ */
+ static std::string getPathBack(const fs::path& path);
+
private:
/** @brief Config value to be used to do bind and unbind */
const std::string config;
- /** @brief This file contains 0 for success, non-zero for errors */
- const fs::path errorFile;
+ /** @brief This directory contains the error files */
+ const fs::path devPath;
/** @brief To bind the device to the OCC driver, do:
*
diff --git a/occ_errors.cpp b/occ_errors.cpp
index ae66a62..ab7663a 100644
--- a/occ_errors.cpp
+++ b/occ_errors.cpp
@@ -56,15 +56,18 @@ void Error::registerCallBack()
}
// Starts to watch for errors
-void Error::addWatch()
+void Error::addWatch(bool poll)
{
if (!watching)
{
// Open the file
openFile();
- // register the callback handler
- registerCallBack();
+ if (poll)
+ {
+ // register the callback handler
+ registerCallBack();
+ }
// Set we are watching the error
watching = true;
diff --git a/occ_errors.hpp b/occ_errors.hpp
index ebacc8a..f623704 100644
--- a/occ_errors.hpp
+++ b/occ_errors.hpp
@@ -36,7 +36,7 @@ class Error
Error(EventPtr& event, const fs::path& file,
std::function<void(bool)> callBack = nullptr) :
event(event),
- file(fs::path(DEV_PATH) / file), callBack(callBack)
+ file(file), callBack(callBack)
{
// Nothing to do here.
}
@@ -49,12 +49,23 @@ class Error
}
}
- /** @brief Starts to monitor for error conditions */
- void addWatch();
+ /** @brief Starts to monitor for error conditions
+ *
+ * @param[in] poll - Indicates whether or not the error file should
+ * actually be polled for changes. Disabling polling is
+ * necessary for error files that don't support the poll
+ * file operation.
+ */
+ void addWatch(bool poll = true);
/** @brief Removes error watch */
void removeWatch();
+ inline void setFile(const fs::path& f)
+ {
+ file = f;
+ }
+
private:
/** @brief sd_event wrapped in unique_ptr */
EventPtr& event;
@@ -95,7 +106,7 @@ class Error
int fd = -1;
/** Error file */
- const fs::path file;
+ fs::path file;
/** @brief Optional function to call on error scenario */
std::function<void(bool)> callBack;
diff --git a/occ_status.hpp b/occ_status.hpp
index 9e6c687..859b5b0 100644
--- a/occ_status.hpp
+++ b/occ_status.hpp
@@ -65,9 +65,10 @@ class Status : public Interface
instance(((this->path.back() - '0'))),
device(event,
#ifdef I2C_OCC
- i2c_occ::getI2cDeviceName(path),
+ fs::path(DEV_PATH) / i2c_occ::getI2cDeviceName(path),
#else
- sysfsName + "." + std::to_string(instance + 1),
+ fs::path(DEV_PATH) /
+ fs::path(sysfsName + "." + std::to_string(instance + 1)),
#endif
manager, *this,
std::bind(std::mem_fn(&Status::deviceErrorHandler), this,
diff --git a/test/Makefile.am b/test/Makefile.am
index ff56179..0ded744 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -6,7 +6,8 @@ TESTS = $(check_PROGRAMS)
utest_LDADD = $(top_builddir)/libocc_control.la -lstdc++fs
-utest_SOURCES = utest.cpp \
+utest_SOURCES = error_files_tests.cpp \
+ utest.cpp \
TestI2cOcc.cpp
utest_CPPFLAGS = $(GTEST_CPPFLAGS) \
diff --git a/test/error_files_tests.cpp b/test/error_files_tests.cpp
new file mode 100644
index 0000000..532818a
--- /dev/null
+++ b/test/error_files_tests.cpp
@@ -0,0 +1,103 @@
+#include "occ_manager.hpp"
+
+#include <stdlib.h>
+
+#include <filesystem>
+#include <fstream>
+
+#include <gtest/gtest.h>
+
+constexpr auto num_error_files = 8;
+constexpr auto device = "occ-hwmon.1";
+constexpr auto error = "occ_error";
+constexpr auto errorMem = "occ_mem_throttle";
+constexpr auto errorPower = "occ_dvfs_power";
+constexpr auto errorTemp = "occ_dvfs_overtemp";
+constexpr auto legacyDevice = "occ-hwmon.2";
+constexpr auto legacyErrorTemp = "occ_dvfs_ot";
+constexpr auto noError = "0";
+
+namespace fs = std::experimental::filesystem;
+using namespace open_power::occ;
+
+class ErrorFiles : public ::testing::Test
+{
+ public:
+ ErrorFiles() :
+ bus(sdbusplus::bus::new_default()), rc(sd_event_default(&event)),
+ pEvent(event), manager(bus, pEvent),
+ status(bus, pEvent, "/dummy1", manager)
+ {
+ EXPECT_GE(rc, 0);
+ event = nullptr;
+ }
+
+ virtual void SetUp()
+ {
+ fs::path files[num_error_files];
+ char tmpDirTemplate[64];
+
+ strcpy(tmpDirTemplate, "/tmp/occXXXXXX");
+ auto path = mkdtemp(tmpDirTemplate);
+ assert(path != nullptr);
+
+ occPath = path;
+ devicePath = occPath / device;
+ legacyDevicePath = occPath / legacyDevice;
+
+ fs::create_directory(devicePath);
+ fs::create_directory(legacyDevicePath);
+
+ files[0] = devicePath / error;
+ files[1] = devicePath / errorMem;
+ files[2] = devicePath / errorPower;
+ files[3] = devicePath / errorTemp;
+ files[4] = legacyDevicePath / error;
+ files[5] = legacyDevicePath / errorMem;
+ files[6] = legacyDevicePath / errorPower;
+ files[7] = legacyDevicePath / legacyErrorTemp;
+
+ for (const fs::path& f : files)
+ {
+ auto stream = std::ofstream(f.c_str());
+
+ if (stream)
+ {
+ stream << noError;
+ }
+ }
+ }
+
+ virtual void TearDown()
+ {
+ fs::remove_all(occPath);
+ }
+
+ sdbusplus::bus::bus bus;
+ sd_event* event;
+ int rc;
+ open_power::occ::EventPtr pEvent;
+
+ Manager manager;
+ Status status;
+
+ fs::path devicePath;
+ fs::path legacyDevicePath;
+ fs::path occPath;
+};
+
+TEST_F(ErrorFiles, AddDeviceErrorWatch)
+{
+ Device occDevice(pEvent, devicePath, manager, status);
+
+ occDevice.addErrorWatch(false);
+ occDevice.removeErrorWatch();
+}
+
+TEST_F(ErrorFiles, AddLegacyDeviceErrorWatch)
+{
+ Device legacyOccDevice(pEvent, legacyDevicePath, manager, status);
+
+ legacyOccDevice.addErrorWatch(false);
+ legacyOccDevice.removeErrorWatch();
+}
diff --git a/test/utest.cpp b/test/utest.cpp
index eb9ca0b..39e5250 100644
--- a/test/utest.cpp
+++ b/test/utest.cpp
@@ -1,5 +1,6 @@
#include "powercap.hpp"
+#include <experimental/filesystem>
#include <occ_events.hpp>
#include <occ_manager.hpp>
@@ -43,3 +44,27 @@ TEST_F(VerifyOccInput, PcapEnabled)
uint32_t occInput = pcap.getOccInput(100, true);
EXPECT_EQ(occInput, 90);
}
+
+TEST(VerifyPathParsing, EmptyPath)
+{
+ std::experimental::filesystem::path path = "";
+ std::string parsed = Device::getPathBack(path);
+
+ EXPECT_STREQ(parsed.c_str(), "");
+}
+
+TEST(VerifyPathParsing, FilenamePath)
+{
+ std::experimental::filesystem::path path = "/test/foo.bar";
+ std::string parsed = Device::getPathBack(path);
+
+ EXPECT_STREQ(parsed.c_str(), "foo.bar");
+}
+
+TEST(VerifyPathParsing, DirectoryPath)
+{
+ std::experimental::filesystem::path path = "/test/bar/";
+ std::string parsed = Device::getPathBack(path);
+
+ EXPECT_STREQ(parsed.c_str(), "bar");
+}
OpenPOWER on IntegriCloud