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