diff options
author | Patrick Venture <venture@google.com> | 2018-04-20 18:10:15 -0700 |
---|---|---|
committer | Patrick Venture <venture@google.com> | 2018-04-24 20:46:07 +0000 |
commit | 75e56c67a10e9f4c617f9c72a87deb695322e212 (patch) | |
tree | 1cdef89f2efa1fc89c7dc737e00d39b51d92317a | |
parent | 609fe98205fe8f4bd0dc6b9fca66877e2edf186d (diff) | |
download | phosphor-hwmon-75e56c67a10e9f4c617f9c72a87deb695322e212.tar.gz phosphor-hwmon-75e56c67a10e9f4c617f9c72a87deb695322e212.zip |
hwmonio: split IoAccess object out
Split out the hwmon io access object from the sysfs namespace
into its own.
Change-Id: I8d1a45630117d1d503d0d5fa6061163911b695e8
Signed-off-by: Patrick Venture <venture@google.com>
-rw-r--r-- | Makefile.am | 3 | ||||
-rw-r--r-- | fan_pwm.cpp | 5 | ||||
-rw-r--r-- | fan_pwm.hpp | 3 | ||||
-rw-r--r-- | fan_speed.cpp | 9 | ||||
-rw-r--r-- | fan_speed.hpp | 3 | ||||
-rw-r--r-- | hwmonio.cpp | 228 | ||||
-rw-r--r-- | hwmonio.hpp | 99 | ||||
-rw-r--r-- | mainloop.cpp | 9 | ||||
-rw-r--r-- | mainloop.hpp | 3 | ||||
-rw-r--r-- | sysfs.cpp | 209 | ||||
-rw-r--r-- | sysfs.hpp | 92 | ||||
-rw-r--r-- | targets.hpp | 7 |
12 files changed, 353 insertions, 317 deletions
diff --git a/Makefile.am b/Makefile.am index d2b7989..0c26a6f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -25,6 +25,7 @@ libhwmon_la_SOURCES = \ fan_speed.cpp \ fan_pwm.cpp \ timer.cpp \ - hwmon.cpp + hwmon.cpp \ + hwmonio.cpp SUBDIRS = . msl test tools diff --git a/fan_pwm.cpp b/fan_pwm.cpp index 04cb1b5..cf89552 100644 --- a/fan_pwm.cpp +++ b/fan_pwm.cpp @@ -1,6 +1,7 @@ #include "env.hpp" #include "fan_pwm.hpp" #include "hwmon.hpp" +#include "hwmonio.hpp" #include "sensorset.hpp" #include "sysfs.hpp" @@ -30,8 +31,8 @@ uint64_t FanPwm::target(uint64_t value) type, id, empty, - sysfs::hwmonio::retries, - sysfs::hwmonio::delay); + hwmonio::retries, + hwmonio::delay); } catch (const std::system_error& e) { diff --git a/fan_pwm.hpp b/fan_pwm.hpp index 1541779..20baf38 100644 --- a/fan_pwm.hpp +++ b/fan_pwm.hpp @@ -1,5 +1,6 @@ #pragma once +#include "hwmonio.hpp" #include "interface.hpp" #include "sysfs.hpp" @@ -54,7 +55,7 @@ class FanPwm : public FanPwmObject /** @brief hwmon id */ std::string id; /** @brief Hwmon sysfs access. */ - sysfs::hwmonio::HwmonIO ioAccess; + hwmonio::HwmonIO ioAccess; /** @brief Physical device path. */ std::string devPath; }; diff --git a/fan_speed.cpp b/fan_speed.cpp index 15ce946..f1afd55 100644 --- a/fan_speed.cpp +++ b/fan_speed.cpp @@ -4,6 +4,7 @@ #include "env.hpp" #include "fan_speed.hpp" #include "hwmon.hpp" +#include "hwmonio.hpp" #include "sysfs.hpp" using namespace phosphor::logging; @@ -25,8 +26,8 @@ uint64_t FanSpeed::target(uint64_t value) type, id, entry::target, - sysfs::hwmonio::retries, - sysfs::hwmonio::delay); + hwmonio::retries, + hwmonio::delay); } catch (const std::system_error& e) @@ -70,8 +71,8 @@ void FanSpeed::enable() type::pwm, id, entry::enable, - sysfs::hwmonio::retries, - sysfs::hwmonio::delay); + hwmonio::retries, + hwmonio::delay); } catch (const std::system_error& e) { diff --git a/fan_speed.hpp b/fan_speed.hpp index 7fc303a..fb97303 100644 --- a/fan_speed.hpp +++ b/fan_speed.hpp @@ -1,5 +1,6 @@ #pragma once +#include "hwmonio.hpp" #include "interface.hpp" #include "sysfs.hpp" @@ -61,7 +62,7 @@ class FanSpeed : public FanSpeedObject /** @brief hwmon id */ std::string id; /** @brief Hwmon sysfs access. */ - sysfs::hwmonio::HwmonIO ioAccess; + hwmonio::HwmonIO ioAccess; /** @brief Physical device path. */ std::string devPath; diff --git a/hwmonio.cpp b/hwmonio.cpp new file mode 100644 index 0000000..fe167f5 --- /dev/null +++ b/hwmonio.cpp @@ -0,0 +1,228 @@ +/** + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <algorithm> +#include <exception> +#include <fstream> +#include <thread> + +#include "config.h" +#include "hwmonio.hpp" +#include "sysfs.hpp" + +namespace hwmonio { + +static constexpr auto retryableErrors = { + /* + * Retry on bus or device errors or timeouts in case + * they are transient. + */ + EIO, + ETIMEDOUT, + + /* + * Retry CRC errors. + */ + EBADMSG, + + /* + * Some hwmon drivers do this when they aren't ready + * instead of blocking. Retry. + */ + EAGAIN, + /* + * We'll see this when for example i2c devices are + * unplugged but the driver is still bound. Retry + * rather than exit on the off chance the device is + * plugged back in and the driver doesn't do a + * remove/probe. If a remove does occur, we'll + * eventually get ENOENT. + */ + ENXIO, + + /* + * Some devices return this when they are busy doing + * something else. Even if being busy isn't the cause, + * a retry still gives this app a shot at getting data + * as opposed to failing out on the first try. + */ + ENODATA, +}; + +HwmonIO::HwmonIO(const std::string& path) : p(path) +{ +} + +int64_t HwmonIO::read( + const std::string& type, + const std::string& id, + const std::string& sensor, + size_t retries, + std::chrono::milliseconds delay, + bool isOCC) const +{ + int64_t val; + std::ifstream ifs; + auto fullPath = sysfs::make_sysfs_path( + p, type, id, sensor); + + ifs.exceptions( + std::ifstream::failbit | + std::ifstream::badbit | + std::ifstream::eofbit); + + while (true) + { + try + { + errno = 0; + if (!ifs.is_open()) + ifs.open(fullPath); + ifs.clear(); + ifs.seekg(0); + ifs >> val; + } + catch (const std::exception& e) + { + auto rc = errno; + + if (!rc) + { + throw; + } + + if (rc == ENOENT || rc == ENODEV) + { + // If the directory or device disappeared then this application + // should gracefully exit. There are race conditions between the + // unloading of a hwmon driver and the stopping of this service + // by systemd. To prevent this application from falsely failing + // in these scenarios, it will simply exit if the directory or + // file can not be found. It is up to the user(s) of this + // provided hwmon object to log the appropriate errors if the + // object disappears when it should not. + exit(0); + } + + if (isOCC) + { + if (rc == EREMOTEIO) + { + // For the OCCs, when an EREMOTEIO is return, set the + // value to 255*1000 + // (0xFF = sensor is failed, 1000 = sensor factor) + val = 255000; + break; + } + } + + if (0 == std::count( + retryableErrors.begin(), + retryableErrors.end(), + rc) || + !retries) + { + // Not a retryable error or out of retries. +#ifdef NEGATIVE_ERRNO_ON_FAIL + return -rc; +#endif + + // Work around GCC bugs 53984 and 66145 for callers by + // explicitly raising system_error here. + throw std::system_error(rc, std::generic_category()); + } + + --retries; + std::this_thread::sleep_for(delay); + continue; + } + break; + } + + return val; +} + +void HwmonIO::write( + uint32_t val, + const std::string& type, + const std::string& id, + const std::string& sensor, + size_t retries, + std::chrono::milliseconds delay) const + +{ + std::ofstream ofs; + auto fullPath = sysfs::make_sysfs_path( + p, type, id, sensor); + + ofs.exceptions( + std::ofstream::failbit | + std::ofstream::badbit | + std::ofstream::eofbit); + + // See comments in the read method for an explanation of the odd exception + // handling behavior here. + + while (true) + { + try + { + errno = 0; + if (!ofs.is_open()) + ofs.open(fullPath); + ofs.clear(); + ofs.seekp(0); + ofs << val; + ofs.flush(); + } + catch (const std::exception& e) + { + auto rc = errno; + + if (!rc) + { + throw; + } + + if (rc == ENOENT) + { + exit(0); + } + + if (0 == std::count( + retryableErrors.begin(), + retryableErrors.end(), + rc) || + !retries) + { + // Not a retryable error or out of retries. + + // Work around GCC bugs 53984 and 66145 for callers by + // explicitly raising system_error here. + throw std::system_error(rc, std::generic_category()); + } + + --retries; + std::this_thread::sleep_for(delay); + continue; + } + break; + } +} + +std::string HwmonIO::path() const +{ + return p; +} + +} // hwmonio diff --git a/hwmonio.hpp b/hwmonio.hpp new file mode 100644 index 0000000..b254b0f --- /dev/null +++ b/hwmonio.hpp @@ -0,0 +1,99 @@ +#pragma once + +#include <chrono> +#include <string> + +namespace hwmonio { + +static constexpr auto retries = 10; +static constexpr auto delay = std::chrono::milliseconds{100}; + +/** @class HwmonIO + * @brief Convenience wrappers for HWMON sysfs attribute IO. + * + * Unburden the rest of the application from having to check + * ENOENT after every hwmon attribute io operation. Hwmon + * device drivers can be unbound at any time; the program + * cannot always be terminated externally before we try to + * do an io. + */ +class HwmonIO +{ + public: + HwmonIO() = delete; + HwmonIO(const HwmonIO&) = default; + HwmonIO(HwmonIO&&) = default; + HwmonIO& operator=(const HwmonIO&) = default; + HwmonIO& operator=(HwmonIO&&) = default; + ~HwmonIO() = default; + + /** @brief Constructor + * + * @param[in] path - hwmon instance root - eg: + * /sys/class/hwmon/hwmon<N> + */ + explicit HwmonIO(const std::string& path); + + /** @brief Perform formatted hwmon sysfs read. + * + * Propagates any exceptions other than ENOENT. + * ENOENT will result in a call to exit(0) in case + * the underlying hwmon driver is unbound and + * the program is inadvertently left running. + * + * For possibly transient errors will retry up to + * the specified number of times. + * + * @param[in] type - The hwmon type (ex. temp). + * @param[in] id - The hwmon id (ex. 1). + * @param[in] sensor - The hwmon sensor (ex. input). + * @param[in] retries - The number of times to retry. + * @param[in] delay - The time to sleep between retry attempts. + * + * @return val - The read value. + */ + int64_t read( + const std::string& type, + const std::string& id, + const std::string& sensor, + size_t retries, + std::chrono::milliseconds delay, + bool isOCC = false) const; + + /** @brief Perform formatted hwmon sysfs write. + * + * Propagates any exceptions other than ENOENT. + * ENOENT will result in a call to exit(0) in case + * the underlying hwmon driver is unbound and + * the program is inadvertently left running. + * + * For possibly transient errors will retry up to + * the specified number of times. + * + * @param[in] val - The value to be written. + * @param[in] type - The hwmon type (ex. fan). + * @param[in] id - The hwmon id (ex. 1). + * @param[in] retries - The number of times to retry. + * @param[in] delay - The time to sleep between retry attempts. + */ + void write( + uint32_t val, + const std::string& type, + const std::string& id, + const std::string& sensor, + size_t retries, + std::chrono::milliseconds delay) const; + + + /** @brief Hwmon instance path access. + * + * @return path - The hwmon instance path. + */ + std::string path() const; + + private: + std::string p; +}; +} // namespace hwmonio + +// vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/mainloop.cpp b/mainloop.cpp index 4c74f53..5324fcd 100644 --- a/mainloop.cpp +++ b/mainloop.cpp @@ -27,6 +27,7 @@ #include "fan_pwm.hpp" #include "fan_speed.hpp" #include "hwmon.hpp" +#include "hwmonio.hpp" #include "sensorset.hpp" #include "sysfs.hpp" #include "mainloop.hpp" @@ -132,7 +133,7 @@ int64_t adjustValue(const SensorSet::key_type& sensor, int64_t value) auto addValue(const SensorSet::key_type& sensor, const RetryIO& retryIO, - sysfs::hwmonio::HwmonIO& ioAccess, + hwmonio::HwmonIO& ioAccess, ObjectInfo& info, bool isOCC = false) { @@ -278,7 +279,7 @@ void MainLoop::getObject(SensorSet::container_t::const_reference sensor) objectPath.append(std::get<sensorLabel>(properties)); ObjectInfo info(&_bus, std::move(objectPath), Object()); - RetryIO retryIO(sysfs::hwmonio::retries, sysfs::hwmonio::delay); + RetryIO retryIO(hwmonio::retries, hwmonio::delay); if (rmSensors.find(sensor.first) != rmSensors.end()) { // When adding a sensor that was purposely removed, @@ -507,8 +508,8 @@ void MainLoop::read() i.first.first, i.first.second, input, - sysfs::hwmonio::retries, - sysfs::hwmonio::delay, + hwmonio::retries, + hwmonio::delay, _isOCC); value = adjustValue(i.first, value); diff --git a/mainloop.hpp b/mainloop.hpp index 0453d8e..d139593 100644 --- a/mainloop.hpp +++ b/mainloop.hpp @@ -5,6 +5,7 @@ #include <experimental/any> #include <memory> #include <sdbusplus/server.hpp> +#include "hwmonio.hpp" #include "sensorset.hpp" #include "sysfs.hpp" #include "interface.hpp" @@ -96,7 +97,7 @@ class MainLoop /** @brief Sleep interval in microseconds. */ uint64_t _interval = default_interval; /** @brief Hwmon sysfs access. */ - sysfs::hwmonio::HwmonIO ioAccess; + hwmonio::HwmonIO ioAccess; /** @brief Timer */ std::unique_ptr<phosphor::hwmon::Timer> timer; /** @brief the sd_event structure */ @@ -29,43 +29,6 @@ namespace fs = std::experimental::filesystem; namespace sysfs { -static constexpr auto retryableErrors = { - /* - * Retry on bus or device errors or timeouts in case - * they are transient. - */ - EIO, - ETIMEDOUT, - - /* - * Retry CRC errors. - */ - EBADMSG, - - /* - * Some hwmon drivers do this when they aren't ready - * instead of blocking. Retry. - */ - EAGAIN, - /* - * We'll see this when for example i2c devices are - * unplugged but the driver is still bound. Retry - * rather than exit on the off chance the device is - * plugged back in and the driver doesn't do a - * remove/probe. If a remove does occur, we'll - * eventually get ENOENT. - */ - ENXIO, - - /* - * Some devices return this when they are busy doing - * something else. Even if being busy isn't the cause, - * a retry still gives this app a shot at getting data - * as opposed to failing out on the first try. - */ - ENODATA, -}; - static const auto emptyString = ""s; static constexpr auto ofRoot = "/sys/firmware/devicetree/base"; @@ -277,176 +240,6 @@ std::string findHwmonFromDevPath(const std::string& devPath) return emptyString; } -namespace hwmonio -{ - -HwmonIO::HwmonIO(const std::string& path) : p(path) -{ - -} - -int64_t HwmonIO::read( - const std::string& type, - const std::string& id, - const std::string& sensor, - size_t retries, - std::chrono::milliseconds delay, - bool isOCC) const -{ - int64_t val; - std::ifstream ifs; - auto fullPath = sysfs::make_sysfs_path( - p, type, id, sensor); - - ifs.exceptions( - std::ifstream::failbit | - std::ifstream::badbit | - std::ifstream::eofbit); - - while (true) - { - try - { - errno = 0; - if (!ifs.is_open()) - ifs.open(fullPath); - ifs.clear(); - ifs.seekg(0); - ifs >> val; - } - catch (const std::exception& e) - { - auto rc = errno; - - if (!rc) - { - throw; - } - - if (rc == ENOENT || rc == ENODEV) - { - // If the directory or device disappeared then this application - // should gracefully exit. There are race conditions between the - // unloading of a hwmon driver and the stopping of this service - // by systemd. To prevent this application from falsely failing - // in these scenarios, it will simply exit if the directory or - // file can not be found. It is up to the user(s) of this - // provided hwmon object to log the appropriate errors if the - // object disappears when it should not. - exit(0); - } - - if (isOCC) - { - if (rc == EREMOTEIO) - { - // For the OCCs, when an EREMOTEIO is return, set the - // value to 255*1000 - // (0xFF = sensor is failed, 1000 = sensor factor) - val = 255000; - break; - } - } +} // namespace sysfs - if (0 == std::count( - retryableErrors.begin(), - retryableErrors.end(), - rc) || - !retries) - { - // Not a retryable error or out of retries. -#ifdef NEGATIVE_ERRNO_ON_FAIL - return -rc; -#endif - - // Work around GCC bugs 53984 and 66145 for callers by - // explicitly raising system_error here. - throw std::system_error(rc, std::generic_category()); - } - - --retries; - std::this_thread::sleep_for(delay); - continue; - } - break; - } - - return val; -} - -void HwmonIO::write( - uint32_t val, - const std::string& type, - const std::string& id, - const std::string& sensor, - size_t retries, - std::chrono::milliseconds delay) const - -{ - std::ofstream ofs; - auto fullPath = sysfs::make_sysfs_path( - p, type, id, sensor); - - ofs.exceptions( - std::ofstream::failbit | - std::ofstream::badbit | - std::ofstream::eofbit); - - // See comments in the read method for an explanation of the odd exception - // handling behavior here. - - while (true) - { - try - { - errno = 0; - if (!ofs.is_open()) - ofs.open(fullPath); - ofs.clear(); - ofs.seekp(0); - ofs << val; - ofs.flush(); - } - catch (const std::exception& e) - { - auto rc = errno; - - if (!rc) - { - throw; - } - - if (rc == ENOENT) - { - exit(0); - } - - if (0 == std::count( - retryableErrors.begin(), - retryableErrors.end(), - rc) || - !retries) - { - // Not a retryable error or out of retries. - - // Work around GCC bugs 53984 and 66145 for callers by - // explicitly raising system_error here. - throw std::system_error(rc, std::generic_category()); - } - - --retries; - std::this_thread::sleep_for(delay); - continue; - } - break; - } -} - -std::string HwmonIO::path() const -{ - return p; -} - -} // namespace hwmonio -} // vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 @@ -75,98 +75,6 @@ std::string findHwmonFromDevPath(const std::string& devPath); */ std::string findCalloutPath(const std::string& instancePath); -namespace hwmonio -{ -static constexpr auto retries = 10; -static constexpr auto delay = std::chrono::milliseconds{100}; - -/** @class HwmonIO - * @brief Convenience wrappers for HWMON sysfs attribute IO. - * - * Unburden the rest of the application from having to check - * ENOENT after every hwmon attribute io operation. Hwmon - * device drivers can be unbound at any time; the program - * cannot always be terminated externally before we try to - * do an io. - */ -class HwmonIO -{ - public: - HwmonIO() = delete; - HwmonIO(const HwmonIO&) = default; - HwmonIO(HwmonIO&&) = default; - HwmonIO& operator=(const HwmonIO&) = default; - HwmonIO& operator=(HwmonIO&&) = default; - ~HwmonIO() = default; - - /** @brief Constructor - * - * @param[in] path - hwmon instance root - eg: - * /sys/class/hwmon/hwmon<N> - */ - explicit HwmonIO(const std::string& path); - - /** @brief Perform formatted hwmon sysfs read. - * - * Propagates any exceptions other than ENOENT. - * ENOENT will result in a call to exit(0) in case - * the underlying hwmon driver is unbound and - * the program is inadvertently left running. - * - * For possibly transient errors will retry up to - * the specified number of times. - * - * @param[in] type - The hwmon type (ex. temp). - * @param[in] id - The hwmon id (ex. 1). - * @param[in] sensor - The hwmon sensor (ex. input). - * @param[in] retries - The number of times to retry. - * @param[in] delay - The time to sleep between retry attempts. - * - * @return val - The read value. - */ - int64_t read( - const std::string& type, - const std::string& id, - const std::string& sensor, - size_t retries, - std::chrono::milliseconds delay, - bool isOCC = false) const; - - /** @brief Perform formatted hwmon sysfs write. - * - * Propagates any exceptions other than ENOENT. - * ENOENT will result in a call to exit(0) in case - * the underlying hwmon driver is unbound and - * the program is inadvertently left running. - * - * For possibly transient errors will retry up to - * the specified number of times. - * - * @param[in] val - The value to be written. - * @param[in] type - The hwmon type (ex. fan). - * @param[in] id - The hwmon id (ex. 1). - * @param[in] retries - The number of times to retry. - * @param[in] delay - The time to sleep between retry attempts. - */ - void write( - uint32_t val, - const std::string& type, - const std::string& id, - const std::string& sensor, - size_t retries, - std::chrono::milliseconds delay) const; - - - /** @brief Hwmon instance path access. - * - * @return path - The hwmon instance path. - */ - std::string path() const; - - private: - std::string p; -}; -} // namespace hwmonio } // namespace sysfs // vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 diff --git a/targets.hpp b/targets.hpp index 02bdd4f..7f21c4b 100644 --- a/targets.hpp +++ b/targets.hpp @@ -7,6 +7,7 @@ #include "env.hpp" #include "fan_speed.hpp" #include "fan_pwm.hpp" +#include "hwmonio.hpp" enum class targetType { @@ -61,7 +62,7 @@ struct Targets<hwmon::FanPwm> */ template <typename T> std::shared_ptr<T> addTarget(const SensorSet::key_type& sensor, - const sysfs::hwmonio::HwmonIO& ioAccess, + const hwmonio::HwmonIO& ioAccess, const std::string& devPath, ObjectInfo& info) { @@ -144,8 +145,8 @@ std::shared_ptr<T> addTarget(const SensorSet::key_type& sensor, targetName, targetId, entry, - sysfs::hwmonio::retries, - sysfs::hwmonio::delay); + hwmonio::retries, + hwmonio::delay); } catch (const std::system_error& e) { |