xref: /openbmc/sdbusplus/include/sdbusplus/async/fdio.hpp (revision 36137e09614746b13603b5fbae79e6f70819c46b)
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