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