#pragma once #include #include #include #include #include #include #include namespace sdevent { namespace event { namespace io { class IO; } // namespace io using EventPtr = sd_event*; class Event; /** @brief Get an instance of the 'default' event. */ Event newDefault(); namespace details { /** @brief unique_ptr functor to release an event reference. */ struct EventDeleter { void operator()(sd_event* ptr) const { deleter(ptr); } decltype(&sd_event_unref) deleter = sd_event_unref; }; /* @brief Alias 'event' to a unique_ptr type for auto-release. */ using Event = std::unique_ptr; } // namespace details using namespace phosphor::logging; /** @class Event * @brief Provides C++ bindings to the sd_event_* class functions. */ class Event { private: using InternalFailure = sdbusplus::xyz::openbmc_project::Common:: Error::InternalFailure; public: /* Define all of the basic class operations: * Not allowed: * - Default constructor to avoid nullptrs. * - Copy operations due to internal unique_ptr. * Allowed: * - Move operations. * - Destructor. */ Event() = delete; Event(const Event&) = delete; Event& operator=(const Event&) = delete; Event(Event&&) = default; Event& operator=(Event&&) = default; ~Event() = default; /** @brief Conversion constructor from 'EventPtr'. * * Increments ref-count of the event-pointer and releases it when * done. */ explicit Event(EventPtr e); /** @brief Constructor for 'Event'. * * Takes ownership of the event-pointer and releases it when done. */ Event(EventPtr e, std::false_type); /** @brief Release ownership of the stored event-pointer. */ EventPtr release() { return evt.release(); } /** @brief Wait indefinitely for new event sources. */ void loop() { auto rc = sd_event_loop(evt.get()); if (rc < 0) { log("Error in call to sd_event_loop", entry("RC=%d", rc)); elog(); } } /** @brief Stop the loop. */ void exit(int status = 0) { auto rc = sd_event_exit(evt.get(), status); if (rc < 0) { log("Error in call to sd_event_exit", entry("RC=%d", rc), entry("STATUS=%d", status)); elog(); } } /** @brief Get the loop exit code. */ auto getExitStatus() { int status; auto rc = sd_event_get_exit_code(evt.get(), &status); if (rc < 0) { log("Error in call to sd_event_get_exit_code", entry("RC=%d", rc)); elog(); } return status; } /** @brief Attach to a DBus loop. */ void attach(sdbusplus::bus::bus& bus) { bus.attach_event(evt.get(), SD_EVENT_PRIORITY_NORMAL); } /** @brief C++ wrapper for sd_event_now. */ auto now() { using namespace std::chrono; uint64_t usec; auto rc = sd_event_now(evt.get(), CLOCK_MONOTONIC, &usec); if (rc < 0) { log("Error in call to sd_event_now", entry("RC=%d", rc)); elog(); } microseconds d(usec); return steady_clock::time_point(d); } friend class io::IO; private: EventPtr get() { return evt.get(); } details::Event evt; }; inline Event::Event(EventPtr l) : evt(sd_event_ref(l)) { } inline Event::Event(EventPtr l, std::false_type) : evt(l) { } inline Event newDefault() { using InternalFailure = sdbusplus::xyz::openbmc_project::Common:: Error::InternalFailure; sd_event* e = nullptr; auto rc = sd_event_default(&e); if (rc < 0) { log("Error in call to sd_event_default", entry("RC=%d", rc)); elog(); } return Event(e, std::false_type()); } } // namespace event } // namespace sdevent