1 #pragma once
2
3 #include <sdbusplus/async/context.hpp>
4 #include <sdbusplus/async/execution.hpp>
5 #include <sdbusplus/event.hpp>
6
7 namespace sdbusplus::async
8 {
9
10 namespace fdio_ns
11 {
12 struct fdio_completion;
13 }
14
15 class fdio : private context_ref, details::context_friend
16 {
17 public:
18 fdio() = delete;
19 fdio(const fdio&) = delete;
20 fdio& operator=(const fdio&) = delete;
21 fdio(fdio&&) = delete;
22 fdio& operator=(fdio&&) = delete;
23 ~fdio() = default;
24
25 fdio(context& ctx, int fd,
26 std::chrono::microseconds timeout = std::chrono::microseconds(0));
27
28 /** Get the next fd event.
29 * Note: the implementation only supports a single awaiting task. Two
30 * tasks should not share this object and both call `next`.
31 */
32 auto next() noexcept;
33
34 friend fdio_ns::fdio_completion;
35
36 private:
37 event_t::time_resolution timeout;
38 event_source_t source;
39 std::mutex lock{};
40 fdio_ns::fdio_completion* complete{nullptr};
41
event_loop()42 event_t& event_loop()
43 {
44 return get_event_loop(ctx);
45 }
46
47 void handleEvent() noexcept;
48 void handleTimeout() noexcept;
49 };
50
51 class fdio_timeout_exception : public std::runtime_error
52 {
53 public:
fdio_timeout_exception()54 fdio_timeout_exception() : std::runtime_error("Timeout") {}
55 };
56
57 namespace fdio_ns
58 {
59
60 struct fdio_completion
61 {
62 fdio_completion() = delete;
63 fdio_completion(const fdio_completion&) = delete;
64 fdio_completion& operator=(const fdio_completion&) = delete;
65 fdio_completion(fdio_completion&&) = delete;
66
fdio_completionsdbusplus::async::fdio_ns::fdio_completion67 explicit fdio_completion(fdio& fdioInstance) noexcept :
68 fdioInstance(fdioInstance) {};
69 ~fdio_completion();
70
71 friend fdio;
72
73 void start() noexcept;
74
75 private:
76 virtual void complete() noexcept = 0;
77 virtual void error(std::exception_ptr exceptionPtr) noexcept = 0;
78 virtual void stop() noexcept = 0;
79
80 fdio& fdioInstance;
81 event_source_t source;
82 };
83
84 // Implementation (templated based on Receiver) of fdio_completion.
85 template <execution::receiver Receiver>
86 struct fdio_operation : fdio_completion
87 {
fdio_operationsdbusplus::async::fdio_ns::fdio_operation88 fdio_operation(fdio& fdioInstance, Receiver r) :
89 fdio_completion(fdioInstance), receiver(std::move(r))
90 {}
91
92 private:
completesdbusplus::async::fdio_ns::fdio_operation93 void complete() noexcept override final
94 {
95 execution::set_value(std::move(receiver));
96 }
97
errorsdbusplus::async::fdio_ns::fdio_operation98 void error(std::exception_ptr exceptionPtr) noexcept override final
99 {
100 execution::set_error(std::move(receiver), exceptionPtr);
101 }
102
stopsdbusplus::async::fdio_ns::fdio_operation103 void stop() noexcept override final
104 {
105 execution::set_stopped(std::move(receiver));
106 }
107
108 Receiver receiver;
109 };
110
111 // fdio Sender implementation.
112 struct fdio_sender
113 {
114 using sender_concept = execution::sender_t;
115
116 fdio_sender() = delete;
fdio_sendersdbusplus::async::fdio_ns::fdio_sender117 explicit fdio_sender(fdio& fdioInstance) noexcept :
118 fdioInstance(fdioInstance) {};
119
120 template <typename Self, class... Env>
121 static constexpr auto get_completion_signatures(Self&&, Env&&...)
122 -> execution::completion_signatures<
123 execution::set_value_t(),
124 execution::set_error_t(std::exception_ptr),
125 execution::set_stopped_t()>;
126
127 template <execution::receiver R>
connectsdbusplus::async::fdio_ns::fdio_sender128 auto connect(R r) -> fdio_operation<R>
129 {
130 return {fdioInstance, std::move(r)};
131 }
132
133 private:
134 fdio& fdioInstance;
135 };
136
137 } // namespace fdio_ns
138
next()139 inline auto fdio::next() noexcept
140 {
141 return fdio_ns::fdio_sender{*this};
142 }
143
144 } // namespace sdbusplus::async
145