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 int fd;
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 };
49
50 namespace fdio_ns
51 {
52
53 struct fdio_completion
54 {
55 fdio_completion() = delete;
56 fdio_completion(const fdio_completion&) = delete;
57 fdio_completion& operator=(const fdio_completion&) = delete;
58 fdio_completion(fdio_completion&&) = delete;
59
fdio_completionsdbusplus::async::fdio_ns::fdio_completion60 explicit fdio_completion(fdio& fdioInstance) noexcept :
61 fdioInstance(fdioInstance) {};
62 ~fdio_completion();
63
64 friend fdio;
65
tag_invoke(execution::start_t,fdio_completion & self)66 friend void tag_invoke(execution::start_t, fdio_completion& self) noexcept
67 {
68 self.arm();
69 }
70
71 private:
72 virtual void complete() noexcept = 0;
73 virtual void stop() noexcept = 0;
74 void arm() noexcept;
75
76 fdio& fdioInstance;
77 };
78
79 // Implementation (templated based on Receiver) of fdio_completion.
80 template <execution::receiver Receiver>
81 struct fdio_operation : fdio_completion
82 {
fdio_operationsdbusplus::async::fdio_ns::fdio_operation83 fdio_operation(fdio& fdioInstance, Receiver r) :
84 fdio_completion(fdioInstance), receiver(std::move(r))
85 {}
86
87 private:
completesdbusplus::async::fdio_ns::fdio_operation88 void complete() noexcept override final
89 {
90 execution::set_value(std::move(receiver));
91 }
92
stopsdbusplus::async::fdio_ns::fdio_operation93 void stop() noexcept override final
94 {
95 execution::set_stopped(std::move(receiver));
96 }
97
98 Receiver receiver;
99 };
100
101 // fdio Sender implementation.
102 struct fdio_sender
103 {
104 using is_sender = void;
105
106 fdio_sender() = delete;
fdio_sendersdbusplus::async::fdio_ns::fdio_sender107 explicit fdio_sender(fdio& fdioInstance) noexcept :
108 fdioInstance(fdioInstance) {};
109
110 friend auto tag_invoke(
111 execution::get_completion_signatures_t, const fdio_sender&,
112 auto) -> execution::completion_signatures<execution::set_value_t(),
113 execution::set_stopped_t()>;
114
115 template <execution::receiver R>
tag_invoke(execution::connect_t,fdio_sender && self,R r)116 friend auto tag_invoke(execution::connect_t, fdio_sender&& self,
117 R r) -> fdio_operation<R>
118 {
119 return {self.fdioInstance, std::move(r)};
120 }
121
122 private:
123 fdio& fdioInstance;
124 };
125
126 } // namespace fdio_ns
127
next()128 inline auto fdio::next() noexcept
129 {
130 return fdio_ns::fdio_sender{*this};
131 }
132
133 } // namespace sdbusplus::async
134