1 #include <sdbusplus/async/fdio.hpp> 2 3 namespace sdbusplus::async 4 { 5 fdio::fdio(context& ctx, int fd, std::chrono::microseconds timeout) : 6 context_ref(ctx), 7 timeout(std::chrono::duration_cast<event_t::time_resolution>(timeout)) 8 { 9 static auto eventHandler = 10 [](sd_event_source*, int, uint32_t, void* data) noexcept { 11 static_cast<fdio*>(data)->handleEvent(); 12 return 0; 13 }; 14 15 try 16 { 17 source = event_loop().add_io(fd, EPOLLIN, eventHandler, this); 18 } 19 catch (...) 20 { 21 throw std::runtime_error("Failed to add fd to event loop"); 22 } 23 } 24 25 void fdio::handleEvent() noexcept 26 { 27 std::unique_lock l{lock}; 28 if (complete == nullptr) 29 { 30 return; 31 } 32 auto c = std::exchange(complete, nullptr); 33 l.unlock(); 34 c->complete(); 35 } 36 37 void fdio::handleTimeout() noexcept 38 { 39 std::unique_lock l{lock}; 40 if (complete == nullptr) 41 { 42 return; 43 } 44 auto c = std::exchange(complete, nullptr); 45 l.unlock(); 46 c->error(std::make_exception_ptr(fdio_timeout_exception())); 47 } 48 49 namespace fdio_ns 50 { 51 52 fdio_completion::~fdio_completion() 53 { 54 std::unique_lock l{fdioInstance.lock}; 55 56 if (fdioInstance.complete == this) 57 { 58 std::exchange(fdioInstance.complete, nullptr); 59 } 60 } 61 62 void fdio_completion::arm() noexcept 63 { 64 // Set ourselves as the awaiting Receiver 65 std::unique_lock l{fdioInstance.lock}; 66 67 if (std::exchange(fdioInstance.complete, this) != nullptr) 68 { 69 // We do not support two awaiters; throw exception. Since we are in 70 // a noexcept context this will std::terminate anyhow, which is 71 // approximately the same as 'assert' but with better information. 72 try 73 { 74 throw std::logic_error( 75 "fdio_completion started with another await already pending!"); 76 } 77 catch (...) 78 { 79 std::terminate(); 80 } 81 } 82 83 l.unlock(); 84 85 // Schedule the timeout 86 if (fdioInstance.timeout != event_t::time_resolution::zero()) 87 { 88 static auto eventHandler = 89 [](sd_event_source*, uint64_t, void* data) noexcept { 90 static_cast<fdio*>(data)->handleTimeout(); 91 return 0; 92 }; 93 94 try 95 { 96 source = fdioInstance.event_loop().add_oneshot_timer( 97 eventHandler, &fdioInstance, fdioInstance.timeout); 98 } 99 catch (...) 100 { 101 error(std::current_exception()); 102 } 103 } 104 } 105 106 } // namespace fdio_ns 107 108 } // namespace sdbusplus::async 109