1 #include <sdbusplus/async/fdio.hpp>
2
3 namespace sdbusplus::async
4 {
fdio(context & ctx,int fd,std::chrono::microseconds timeout)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
handleEvent()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
handleTimeout()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
~fdio_completion()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
start()62 void fdio_completion::start() 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