| #include <sys/eventfd.h> |
| #include <unistd.h> |
| |
| #include <sdbusplus/event.hpp> |
| #include <sdbusplus/exception.hpp> |
| |
| 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<decltype(rc)>(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<decltype(rc)>(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<false>(); |
| |
| auto rc = sd_event_run(eventp, static_cast<uint64_t>(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<event*>(data); |
| self->run_condition.ack(); |
| |
| return 0; |
| } |
| |
| template <bool Signal> |
| std::unique_lock<std::recursive_mutex> event::obtain_lock() |
| { |
| std::unique_lock stage{this->obtain_lock_stage}; |
| |
| std::unique_lock<std::recursive_mutex> 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 |