#include #include #include namespace sdbusplus::event { source::source(source&& s) { if (&s == this) { return; } ev = std::exchange(s.ev, nullptr); sourcep = std::exchange(s.sourcep, nullptr); } source& source::operator=(source&& s) { if (nullptr != sourcep) { auto l = ev->obtain_lock(); sd_event_source_unref(sourcep); } ev = std::exchange(s.ev, nullptr); sourcep = std::exchange(s.sourcep, nullptr); return *this; } source::~source() { if (nullptr != sourcep) { auto l = ev->obtain_lock(); sd_event_source_unref(sourcep); } } condition::condition(condition&& c) { if (&c == this) { return; } condition_source = std::move(c.condition_source); fd = std::exchange(c.fd, -1); } condition& condition::operator=(condition&& c) { condition_source = std::move(c.condition_source); if (fd >= 0) { close(fd); } fd = std::exchange(c.fd, -1); return *this; } void condition::signal() { uint64_t value = 1; auto rc = write(fd, &value, sizeof(value)); if (rc < static_cast(sizeof(value))) { throw exception::SdBusError(errno, __func__); } } void condition::ack() { uint64_t value = 0; auto rc = read(fd, &value, sizeof(value)); if (rc < static_cast(sizeof(value))) { throw exception::SdBusError(errno, __func__); } } event::event() { if (auto rc = sd_event_new(&eventp); rc < 0) { throw exception::SdBusError(-rc, __func__); } run_condition = add_condition(run_wakeup, this); } void event::run_one(time_resolution timeout) { auto l = obtain_lock(); auto rc = sd_event_run(eventp, static_cast(timeout.count())); if (rc < 0) { throw exception::SdBusError(-rc, __func__); } } void event::break_run() { run_condition.signal(); } source event::add_io(int fd, uint32_t events, sd_event_io_handler_t handler, void* data) { auto l = obtain_lock(); source s{*this}; auto rc = sd_event_add_io(eventp, &s.sourcep, fd, events, handler, data); if (rc < 0) { throw exception::SdBusError(-rc, __func__); } return s; } condition event::add_condition(sd_event_io_handler_t handler, void* data) { // We don't need any locks here because we only touch the sd_event // indirectly through `add_io` which handles its own locking. auto fd = eventfd(0, 0); if (fd < 0) { throw exception::SdBusError(errno, __func__); } try { auto io = add_io(fd, EPOLLIN, handler, data); return {std::move(io), std::move(fd)}; } catch (...) { close(fd); throw; } } source event::add_oneshot_timer(sd_event_time_handler_t handler, void* data, time_resolution time, time_resolution accuracy) { auto l = obtain_lock(); source s{*this}; auto rc = sd_event_add_time_relative(eventp, &s.sourcep, CLOCK_BOOTTIME, time.count(), accuracy.count(), handler, data); if (rc < 0) { throw exception::SdBusError(-rc, __func__); } return s; } int event::run_wakeup(sd_event_source*, int, uint32_t, void* data) { auto self = static_cast(data); self->run_condition.ack(); return 0; } template std::unique_lock event::obtain_lock() { std::unique_lock l{this->lock, std::defer_lock_t()}; if constexpr (Signal) { if (!l.try_lock()) { run_condition.signal(); l.lock(); } } else { l.lock(); } return l; } } // namespace sdbusplus::event