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 /** Construct a new fdio object from a context and a file descriptor. */
26 fdio(context& ctx, int fd);
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_source_t source;
38 std::mutex lock{};
39 fdio_ns::fdio_completion* complete{nullptr};
40
event_loop()41 event_t& event_loop()
42 {
43 return get_event_loop(ctx);
44 }
45
46 void handleEvent() noexcept;
47 };
48
49 namespace fdio_ns
50 {
51
52 struct fdio_completion
53 {
54 fdio_completion() = delete;
55 fdio_completion(const fdio_completion&) = delete;
56 fdio_completion& operator=(const fdio_completion&) = delete;
57 fdio_completion(fdio_completion&&) = delete;
58
fdio_completionsdbusplus::async::fdio_ns::fdio_completion59 explicit fdio_completion(fdio& fdioInstance) noexcept :
60 fdioInstance(fdioInstance) {};
61 ~fdio_completion();
62
63 friend fdio;
64
tag_invoke(execution::start_t,fdio_completion & self)65 friend void tag_invoke(execution::start_t, fdio_completion& self) noexcept
66 {
67 self.arm();
68 }
69
70 private:
71 virtual void complete() noexcept = 0;
72 virtual void stop() noexcept = 0;
73 void arm() noexcept;
74
75 fdio& fdioInstance;
76 };
77
78 // Implementation (templated based on Receiver) of fdio_completion.
79 template <execution::receiver Receiver>
80 struct fdio_operation : fdio_completion
81 {
fdio_operationsdbusplus::async::fdio_ns::fdio_operation82 fdio_operation(fdio& fdioInstance, Receiver r) :
83 fdio_completion(fdioInstance), receiver(std::move(r))
84 {}
85
86 private:
completesdbusplus::async::fdio_ns::fdio_operation87 void complete() noexcept override final
88 {
89 execution::set_value(std::move(receiver));
90 }
91
stopsdbusplus::async::fdio_ns::fdio_operation92 void stop() noexcept override final
93 {
94 execution::set_stopped(std::move(receiver));
95 }
96
97 Receiver receiver;
98 };
99
100 // fdio Sender implementation.
101 struct fdio_sender
102 {
103 using is_sender = void;
104
105 fdio_sender() = delete;
fdio_sendersdbusplus::async::fdio_ns::fdio_sender106 explicit fdio_sender(fdio& fdioInstance) noexcept :
107 fdioInstance(fdioInstance) {};
108
109 friend auto tag_invoke(execution::get_completion_signatures_t,
110 const fdio_sender&, auto)
111 -> execution::completion_signatures<execution::set_value_t(),
112 execution::set_stopped_t()>;
113
114 template <execution::receiver R>
tag_invoke(execution::connect_t,fdio_sender && self,R r)115 friend auto tag_invoke(execution::connect_t, fdio_sender&& self, R r)
116 -> fdio_operation<R>
117 {
118 return {self.fdioInstance, std::move(r)};
119 }
120
121 private:
122 fdio& fdioInstance;
123 };
124
125 } // namespace fdio_ns
126
next()127 inline auto fdio::next() noexcept
128 {
129 return fdio_ns::fdio_sender{*this};
130 }
131
132 } // namespace sdbusplus::async
133