blob: a16f25a11cce914c05384258ccac126fb1839ff8 [file] [log] [blame]
#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