summaryrefslogtreecommitdiffstats
path: root/softoff
diff options
context:
space:
mode:
Diffstat (limited to 'softoff')
-rw-r--r--softoff/Makefile.am1
-rw-r--r--softoff/mainapp.cpp40
-rw-r--r--softoff/softoff.cpp6
-rw-r--r--softoff/softoff.hpp54
-rw-r--r--softoff/timer.cpp58
-rw-r--r--softoff/timer.hpp82
6 files changed, 221 insertions, 20 deletions
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 <systemd/sd-event.h>
#include <phosphor-logging/log.hpp>
#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<level::ERR>("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<level::ERR>("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 <sdbusplus/bus.hpp>
#include <sdbusplus/server/object.hpp>
#include <xyz/openbmc_project/Ipmi/Internal/SoftPowerOff/server.hpp>
+#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 <phosphor-logging/log.hpp>
+#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<level::ERR>("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<level::ERR>("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<Timer*>(userData);
+ timer->expired = true;
+
+ log<level::INFO>("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 <systemd/sd-event.h>
+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
OpenPOWER on IntegriCloud