From bcb76886797f6c85c4052a72c07156f398c3e142 Mon Sep 17 00:00:00 2001 From: Vishwanatha Subbanna Date: Wed, 25 Jan 2017 16:29:43 +0530 Subject: Add timer skeleton This patchset creates the timer infrastructure that is then used by soft power off object on user requests. Change-Id: I6f7a5c161999fda89471f453c24725efddac65b9 Signed-off-by: Vishwanatha Subbanna --- softoff/Makefile.am | 1 + softoff/mainapp.cpp | 40 ++++++++++++++++++++++---- softoff/softoff.cpp | 6 +--- softoff/softoff.hpp | 54 +++++++++++++++++++++++++++++------ softoff/timer.cpp | 58 +++++++++++++++++++++++++++++++++++++ softoff/timer.hpp | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 221 insertions(+), 20 deletions(-) create mode 100644 softoff/timer.cpp create mode 100644 softoff/timer.hpp (limited to 'softoff') diff --git a/softoff/Makefile.am b/softoff/Makefile.am index 66501a5..aafce74 100644 --- a/softoff/Makefile.am +++ b/softoff/Makefile.am @@ -4,6 +4,7 @@ sbin_PROGRAMS = phosphor-softpoweroff phosphor_softpoweroff_SOURCES = \ softoff.cpp \ + timer.cpp \ mainapp.cpp \ xyz/openbmc_project/Ipmi/Internal/SoftPowerOff/server.cpp diff --git a/softoff/mainapp.cpp b/softoff/mainapp.cpp index 38b6984..f5fbf18 100644 --- a/softoff/mainapp.cpp +++ b/softoff/mainapp.cpp @@ -13,32 +13,60 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include #include #include "softoff.hpp" #include "config.h" +#include "timer.hpp" using namespace phosphor::logging; int main(int argc, char** argv) { + // systemd event handler + sd_event* events = nullptr; + // Get a handle to system dbus. auto bus = sdbusplus::bus::new_default(); // Add systemd object manager. sdbusplus::server::manager::manager(bus, SOFTOFF_OBJPATH); + // sd_event object + auto r = sd_event_default(&events); + if (r < 0) + { + log("Failure to create sd_event handler", + entry("ERROR=%s", strerror(-r))); + return -1; + } + + // Attach the bus to sd_event to service user requests + bus.attach_event(events, SD_EVENT_PRIORITY_NORMAL); + // Create the SoftPowerOff object. - phosphor::ipmi::SoftPowerOff object(bus, SOFTOFF_OBJPATH); + phosphor::ipmi::SoftPowerOff powerObj(bus, events, SOFTOFF_OBJPATH); /** @brief Claim the bus */ bus.request_name(SOFTOFF_BUSNAME); - /** @brief Wait for client requests */ - while(true) + /** @brief Wait for client requests until this application has processed + * at least one successful SoftPowerOff + */ + while(!powerObj.isCompleted() && !powerObj.isTimerExpired()) { - // Handle dbus message / signals discarding unhandled - bus.process_discard(); - bus.wait(); + // -1 denotes wait for ever + r = sd_event_run(events, (uint64_t)-1); + if (r < 0) + { + log("Failure in processing request", + entry("ERROR=%s", strerror(-r))); + break; + } } + + // Cleanup the event handler + events = sd_event_unref(events); + return 0; } diff --git a/softoff/softoff.cpp b/softoff/softoff.cpp index bd6a72d..11298ab 100644 --- a/softoff/softoff.cpp +++ b/softoff/softoff.cpp @@ -19,11 +19,6 @@ namespace phosphor namespace ipmi { -// Need this to send SMS_ATTN -constexpr auto HOST_IPMI_BUS = "org.openbmc.HostIpmi"; -constexpr auto HOST_IPMI_OBJ = "/org/openbmc/HostIpmi/1"; -constexpr auto HOST_IPMI_INTF = "org.openbmc.HostIpmi"; - /** @brief Send the SMS_ATN to host if value is set */ void SoftPowerOff::sendSMSAttn() { @@ -38,5 +33,6 @@ void SoftPowerOff::sendSMSAttn() return; } + } // namespace ipmi } // namespace phosphor diff --git a/softoff/softoff.hpp b/softoff/softoff.hpp index dcb4b18..06f3861 100644 --- a/softoff/softoff.hpp +++ b/softoff/softoff.hpp @@ -3,6 +3,7 @@ #include #include #include +#include "timer.hpp" namespace phosphor { namespace ipmi @@ -19,15 +20,22 @@ class SoftPowerOff : public sdbusplus::server::object::object< public: /** @brief Constructs SoftPowerOff object. * - * @param[in] bus - system dbus handler - * @param[in] objPath - The Dbus path that hosts SoftPowerOff function + * @param[in] bus - system dbus handler + * @param[in] event - sd_event handler + * @param[in] objPath - The Dbus path hosting SoftPowerOff function */ SoftPowerOff(sdbusplus::bus::bus& bus, + sd_event* event, const char* objPath) : sdbusplus::server::object::object< - Base::SoftPowerOff>(bus, objPath), - bus(bus) + Base::SoftPowerOff>(bus, objPath, false), + bus(bus), + timer(event) { + // Need to announce since we may get the response + // very quickly on SMS_ATN + emit_object_added(); + // The whole purpose of this application is to send SMS_ATTN // and watch for the soft power off to go through. We need the // interface added signal emitted before we send SMS_ATN just to @@ -35,12 +43,43 @@ class SoftPowerOff : public sdbusplus::server::object::object< sendSMSAttn(); } + /** @brief Tells if the objective of this application is completed */ + inline auto isCompleted() + { + return completed; + } + + /** @brief Tells if the referenced timer is expired or not */ + inline auto isTimerExpired() + { + return timer.isExpired(); + } + private: + // Need this to send SMS_ATTN + // TODO : Switch over to using mapper service in a different patch + static constexpr auto HOST_IPMI_BUS = "org.openbmc.HostIpmi"; + static constexpr auto HOST_IPMI_OBJ = "/org/openbmc/HostIpmi/1"; + static constexpr auto HOST_IPMI_INTF = "org.openbmc.HostIpmi"; + + /* @brief sdbusplus handle */ + sdbusplus::bus::bus& bus; + + /** @brief Reference to Timer object */ + Timer timer; + + /** @brief Marks the end of life of this application. + * + * This is set to true if host gives appropriate responses + * for the sequence of commands. + */ + bool completed = false; + /** @brief Sends SMS_ATN to host to initiate soft power off process. * - * After sending the SMS_ATN, starts a watchdog timer for 30 + * After sending the SMS_ATN, starts a timer for 30 * seconds and expects a initial response from the host. - * After receiving the initial response, starts another watchdog + * After receiving the initial response, starts another * timer for 30 minutes to let host do a clean shutdown of * partitions. When the second response is received from the * host, it indicates that BMC can do a power off. @@ -51,9 +90,6 @@ class SoftPowerOff : public sdbusplus::server::object::object< * being thrown */ void sendSMSAttn(); - - /* @brief sdbusplus handle */ - sdbusplus::bus::bus& bus; }; } // namespace ipmi } // namespace phosphor diff --git a/softoff/timer.cpp b/softoff/timer.cpp new file mode 100644 index 0000000..9e722f1 --- /dev/null +++ b/softoff/timer.cpp @@ -0,0 +1,58 @@ +#include +#include "timer.hpp" +namespace phosphor +{ +namespace ipmi +{ + +using namespace phosphor::logging; + +// Initializes the timer object +void Timer::initialize() +{ + // This can not be called more than once. + if (eventSource) + { + throw std::runtime_error("Timer already initialized"); + } + + // Add infinite expiration time + auto r = sd_event_add_time(timeEvent, &eventSource, + CLOCK_MONOTONIC, // Time base + UINT64_MAX, // Expire time - way long enough time + 0, // Use default event accuracy + timeoutHandler, // Callback handler on timeout + this); // User data + if (r < 0) + { + log("Failure to set initial expiration time value", + entry("ERROR=%s", strerror(-r))); + + throw std::runtime_error("Timer initialization failed"); + } + + // Disable the timer for now + r = sd_event_source_set_enabled(eventSource, SD_EVENT_OFF); + if (r < 0) + { + log("Failure to disable timer", + entry("ERROR=%s", strerror(-r))); + + throw std::runtime_error("Setting initial timer value failed"); + } + return; +} + +/** @brief callback handler on timeout */ +int Timer::timeoutHandler(sd_event_source* eventSource, + uint64_t usec, void* userData) +{ + auto timer = static_cast(userData); + timer->expired = true; + + log("Timer expired"); + return 0; +} + +} // namespace ipmi +} // namespace phosphor diff --git a/softoff/timer.hpp b/softoff/timer.hpp new file mode 100644 index 0000000..7c3bac2 --- /dev/null +++ b/softoff/timer.hpp @@ -0,0 +1,82 @@ +#pragma once + +#include +namespace phosphor +{ +namespace ipmi +{ + +/** @class Timer + * @brief Manages starting watchdog timers and handling timeouts + */ +class Timer +{ + public: + /** @brief Only need the default Timer */ + Timer() = delete; + Timer(const Timer&) = delete; + Timer& operator=(const Timer&) = delete; + Timer(Timer&&) = delete; + Timer& operator=(Timer&&) = delete; + + /** @brief Constructs timer object + * + * @param[in] events - sd_event pointer + */ + Timer(sd_event* events) + : timeEvent(events) + { + // Initialize the timer + initialize(); + } + + ~Timer() + { + if (eventSource) + { + eventSource = sd_event_source_unref(eventSource); + } + } + + inline auto isExpired() + { + return expired; + } + + private: + /** @brief the sd_event structure */ + sd_event* timeEvent = nullptr; + + /** @brief Source of events */ + sd_event_source* eventSource = nullptr; + + /** @brief Returns if the associated timer is expired + * + * This is set to true when the timeoutHandler is called into + */ + bool expired = false; + + /** @brief Initializes the timer object with infinite + * expiration time and sets up the callback handler + * + * @return None. + * + * @error std::runtime exception thrown + */ + void initialize(); + + /** @brief Callback function when timer goes off + * + * On getting the signal, initiate the hard power off request + * + * @param[in] eventSource - Source of the event + * @param[in] usec - time in micro seconds + * @param[in] userData - User data pointer + * + */ + static int timeoutHandler(sd_event_source* eventSource, + uint64_t usec, void* userData); +}; + +} // namespace ipmi +} // namespace phosphor -- cgit v1.2.1