1 #include <sys/eventfd.h> 2 3 #include <sdbusplus/event.hpp> 4 #include <sdbusplus/exception.hpp> 5 6 namespace sdbusplus::event 7 { 8 9 source::source(source&& s) 10 { 11 if (&s == this) 12 { 13 return; 14 } 15 ev = std::exchange(s.ev, nullptr); 16 sourcep = std::exchange(s.sourcep, nullptr); 17 } 18 19 source& source::operator=(source&& s) 20 { 21 if (nullptr != sourcep) 22 { 23 auto l = ev->obtain_lock(); 24 sd_event_source_unref(sourcep); 25 } 26 ev = std::exchange(s.ev, nullptr); 27 sourcep = std::exchange(s.sourcep, nullptr); 28 29 return *this; 30 } 31 32 source::~source() 33 { 34 if (nullptr != sourcep) 35 { 36 auto l = ev->obtain_lock(); 37 sd_event_source_unref(sourcep); 38 } 39 } 40 41 condition::condition(condition&& c) 42 { 43 if (&c == this) 44 { 45 return; 46 } 47 48 condition_source = std::move(c.condition_source); 49 fd = std::exchange(c.fd, -1); 50 } 51 52 condition& condition::operator=(condition&& c) 53 { 54 condition_source = std::move(c.condition_source); 55 if (fd >= 0) 56 { 57 close(fd); 58 } 59 fd = std::exchange(c.fd, -1); 60 61 return *this; 62 } 63 64 void condition::signal() 65 { 66 uint64_t value = 1; 67 auto rc = write(fd, &value, sizeof(value)); 68 if (rc < static_cast<decltype(rc)>(sizeof(value))) 69 { 70 throw exception::SdBusError(errno, __func__); 71 } 72 } 73 74 void condition::ack() 75 { 76 uint64_t value = 0; 77 auto rc = read(fd, &value, sizeof(value)); 78 if (rc < static_cast<decltype(rc)>(sizeof(value))) 79 { 80 throw exception::SdBusError(errno, __func__); 81 } 82 } 83 84 event::event() 85 { 86 if (auto rc = sd_event_new(&eventp); rc < 0) 87 { 88 throw exception::SdBusError(-rc, __func__); 89 } 90 run_condition = add_condition(run_wakeup, this); 91 } 92 93 void event::run_one(time_resolution timeout) 94 { 95 auto l = obtain_lock<false>(); 96 97 auto rc = sd_event_run(eventp, static_cast<uint64_t>(timeout.count())); 98 if (rc < 0) 99 { 100 throw exception::SdBusError(-rc, __func__); 101 } 102 } 103 104 void event::break_run() 105 { 106 run_condition.signal(); 107 } 108 109 source event::add_io(int fd, uint32_t events, sd_event_io_handler_t handler, 110 void* data) 111 { 112 auto l = obtain_lock(); 113 114 source s{*this}; 115 116 auto rc = sd_event_add_io(eventp, &s.sourcep, fd, events, handler, data); 117 if (rc < 0) 118 { 119 throw exception::SdBusError(-rc, __func__); 120 } 121 122 return s; 123 } 124 125 condition event::add_condition(sd_event_io_handler_t handler, void* data) 126 { 127 // We don't need any locks here because we only touch the sd_event 128 // indirectly through `add_io` which handles its own locking. 129 130 auto fd = eventfd(0, 0); 131 if (fd < 0) 132 { 133 throw exception::SdBusError(errno, __func__); 134 } 135 136 try 137 { 138 auto io = add_io(fd, EPOLLIN, handler, data); 139 return {std::move(io), std::move(fd)}; 140 } 141 catch (...) 142 { 143 close(fd); 144 throw; 145 } 146 } 147 148 source event::add_oneshot_timer(sd_event_time_handler_t handler, void* data, 149 time_resolution time, time_resolution accuracy) 150 { 151 auto l = obtain_lock(); 152 153 source s{*this}; 154 155 auto rc = sd_event_add_time_relative(eventp, &s.sourcep, CLOCK_BOOTTIME, 156 time.count(), accuracy.count(), 157 handler, data); 158 159 if (rc < 0) 160 { 161 throw exception::SdBusError(-rc, __func__); 162 } 163 164 return s; 165 } 166 167 int event::run_wakeup(sd_event_source*, int, uint32_t, void* data) 168 { 169 auto self = static_cast<event*>(data); 170 self->run_condition.ack(); 171 172 return 0; 173 } 174 175 template <bool Signal> 176 std::unique_lock<std::recursive_mutex> event::obtain_lock() 177 { 178 std::unique_lock<std::recursive_mutex> l{this->lock, std::defer_lock_t()}; 179 if constexpr (Signal) 180 { 181 if (!l.try_lock()) 182 { 183 run_condition.signal(); 184 l.lock(); 185 } 186 } 187 else 188 { 189 l.lock(); 190 } 191 192 return l; 193 } 194 195 } // namespace sdbusplus::event 196