xref: /openbmc/sdbusplus/include/sdbusplus/async/match.hpp (revision 36137e09614746b13603b5fbae79e6f70819c46b)
1290fa427SPatrick Williams #pragma once
2290fa427SPatrick Williams #include <sdbusplus/async/context.hpp>
3290fa427SPatrick Williams #include <sdbusplus/async/execution.hpp>
4290fa427SPatrick Williams #include <sdbusplus/bus/match.hpp>
5290fa427SPatrick Williams #include <sdbusplus/message.hpp>
6290fa427SPatrick Williams #include <sdbusplus/slot.hpp>
7290fa427SPatrick Williams 
8290fa427SPatrick Williams #include <condition_variable>
9290fa427SPatrick Williams #include <mutex>
10290fa427SPatrick Williams #include <queue>
11290fa427SPatrick Williams #include <string_view>
12290fa427SPatrick Williams 
13290fa427SPatrick Williams namespace sdbusplus::async
14290fa427SPatrick Williams {
15290fa427SPatrick Williams namespace match_ns
16290fa427SPatrick Williams {
17290fa427SPatrick Williams struct match_completion;
18290fa427SPatrick Williams }
19290fa427SPatrick Williams 
20290fa427SPatrick Williams /** Generator of dbus match Senders.
21290fa427SPatrick Williams  *
22290fa427SPatrick Williams  *  This class registers a signal match pattern with the dbus and generates
23290fa427SPatrick Williams  *  Senders using `next` to await the next matching signal.
24290fa427SPatrick Williams  */
25290fa427SPatrick Williams class match : private bus::details::bus_friend
26290fa427SPatrick Williams {
27290fa427SPatrick Williams   public:
28290fa427SPatrick Williams     match() = delete;
29290fa427SPatrick Williams     match(const match&) = delete;
30290fa427SPatrick Williams     match& operator=(const match&) = delete;
31290fa427SPatrick Williams     match(match&&) = delete;
32290fa427SPatrick Williams     match& operator=(match&&) = delete;
331b7b54caSPatrick Williams     ~match();
34290fa427SPatrick Williams 
35290fa427SPatrick Williams     /** Construct the match using the `pattern` string on the bus managed by the
36290fa427SPatrick Williams      *  context. */
37290fa427SPatrick Williams     match(context& ctx, const std::string_view& pattern);
38290fa427SPatrick Williams 
39290fa427SPatrick Williams     /** Get the Sender for the next event (as message).
40290fa427SPatrick Williams      *
41290fa427SPatrick Williams      *  Note: the implementation only supports a single awaiting task.  Two
42290fa427SPatrick Williams      *  tasks should not share this object and both call `next`.
43290fa427SPatrick Williams      */
44290fa427SPatrick Williams     auto next() noexcept;
45290fa427SPatrick Williams 
46290fa427SPatrick Williams     /** Get the Sender for the next event, which yields one of:
47290fa427SPatrick Williams      *    void, Rs, tuple<Rs...>
48290fa427SPatrick Williams      *
49290fa427SPatrick Williams      *  Note: the implementation only supports a single awaiting task.  Two
50290fa427SPatrick Williams      *  tasks should not share this object and both call `next`.
51290fa427SPatrick Williams      */
52290fa427SPatrick Williams     template <typename... Rs>
53290fa427SPatrick Williams     auto next() noexcept;
54290fa427SPatrick Williams 
55290fa427SPatrick Williams     friend match_ns::match_completion;
56290fa427SPatrick Williams 
57290fa427SPatrick Williams   private:
589d8ba947SWilliam A. Kennington III     sdbusplus::slot_t slot;
59290fa427SPatrick Williams 
60290fa427SPatrick Williams     std::mutex lock{};
61290fa427SPatrick Williams     std::queue<sdbusplus::message_t> queue{};
62290fa427SPatrick Williams     match_ns::match_completion* complete = nullptr;
63290fa427SPatrick Williams 
64290fa427SPatrick Williams     /** Handle an incoming match event. */
65290fa427SPatrick Williams     void handle_match(message_t&&) noexcept;
66290fa427SPatrick Williams 
67290fa427SPatrick Williams     /** Signal completion if there is an awaiting Receiver.
68290fa427SPatrick Williams      *
69290fa427SPatrick Williams      *  This must be called with `lock` held (and ownership transfers).
70290fa427SPatrick Williams      */
71290fa427SPatrick Williams     void handle_completion(std::unique_lock<std::mutex>&&) noexcept;
729d8ba947SWilliam A. Kennington III 
739d8ba947SWilliam A. Kennington III     slot_t makeMatch(context& ctx, const std::string_view& pattern);
74290fa427SPatrick Williams };
75290fa427SPatrick Williams 
76290fa427SPatrick Williams namespace match_ns
77290fa427SPatrick Williams {
78290fa427SPatrick Williams // Virtual class to handle the match Receiver completions.
79290fa427SPatrick Williams struct match_completion
80290fa427SPatrick Williams {
81290fa427SPatrick Williams     match_completion() = delete;
82290fa427SPatrick Williams     match_completion(match_completion&&) = delete;
83290fa427SPatrick Williams 
match_completionsdbusplus::async::match_ns::match_completion84290fa427SPatrick Williams     explicit match_completion(match& m) : m(m) {};
85290fa427SPatrick Williams     virtual ~match_completion() = default;
86290fa427SPatrick Williams 
87290fa427SPatrick Williams     friend match;
88290fa427SPatrick Williams 
tag_invoke(execution::start_t,match_completion & self)89290fa427SPatrick Williams     friend void tag_invoke(execution::start_t, match_completion& self) noexcept
90290fa427SPatrick Williams     {
91290fa427SPatrick Williams         self.arm();
92290fa427SPatrick Williams     }
93290fa427SPatrick Williams 
94290fa427SPatrick Williams   private:
95290fa427SPatrick Williams     virtual void complete(message_t&&) noexcept = 0;
961b7b54caSPatrick Williams     virtual void stop() noexcept = 0;
97290fa427SPatrick Williams     void arm() noexcept;
98290fa427SPatrick Williams 
99290fa427SPatrick Williams     match& m;
100290fa427SPatrick Williams };
101290fa427SPatrick Williams 
102290fa427SPatrick Williams // Implementation (templated based on Receiver) of match_completion.
103290fa427SPatrick Williams template <execution::receiver Receiver>
104290fa427SPatrick Williams struct match_operation : match_completion
105290fa427SPatrick Williams {
match_operationsdbusplus::async::match_ns::match_operation106290fa427SPatrick Williams     match_operation(match& m, Receiver r) :
107290fa427SPatrick Williams         match_completion(m), receiver(std::move(r))
108290fa427SPatrick Williams     {}
109290fa427SPatrick Williams 
110290fa427SPatrick Williams   private:
completesdbusplus::async::match_ns::match_operation111290fa427SPatrick Williams     void complete(message_t&& msg) noexcept override final
112290fa427SPatrick Williams     {
113290fa427SPatrick Williams         execution::set_value(std::move(receiver), std::move(msg));
114290fa427SPatrick Williams     }
115290fa427SPatrick Williams 
stopsdbusplus::async::match_ns::match_operation1161b7b54caSPatrick Williams     void stop() noexcept override final
1171b7b54caSPatrick Williams     {
1181b7b54caSPatrick Williams         execution::set_stopped(std::move(receiver));
1191b7b54caSPatrick Williams     }
1201b7b54caSPatrick Williams 
121290fa427SPatrick Williams     Receiver receiver;
122290fa427SPatrick Williams };
123290fa427SPatrick Williams 
124290fa427SPatrick Williams // match Sender implementation.
125290fa427SPatrick Williams struct match_sender
126290fa427SPatrick Williams {
1279c6ec9b3SPatrick Williams     using is_sender = void;
1289c6ec9b3SPatrick Williams 
129290fa427SPatrick Williams     match_sender() = delete;
match_sendersdbusplus::async::match_ns::match_sender130290fa427SPatrick Williams     explicit match_sender(match& m) noexcept : m(m) {};
131290fa427SPatrick Williams 
132290fa427SPatrick Williams     friend auto tag_invoke(execution::get_completion_signatures_t,
133290fa427SPatrick Williams                            const match_sender&, auto)
1346ba44310SPatrick Williams         -> execution::completion_signatures<execution::set_value_t(message_t),
1356ba44310SPatrick Williams                                             execution::set_stopped_t()>;
136290fa427SPatrick Williams 
137290fa427SPatrick Williams     template <execution::receiver R>
tag_invoke(execution::connect_t,match_sender && self,R r)138*36137e09SPatrick Williams     friend auto tag_invoke(execution::connect_t, match_sender&& self, R r)
139*36137e09SPatrick Williams         -> match_operation<R>
140290fa427SPatrick Williams     {
141290fa427SPatrick Williams         return {self.m, std::move(r)};
142290fa427SPatrick Williams     }
143290fa427SPatrick Williams 
144290fa427SPatrick Williams   private:
145290fa427SPatrick Williams     match& m;
146290fa427SPatrick Williams };
147290fa427SPatrick Williams 
148290fa427SPatrick Williams }; // namespace match_ns
149290fa427SPatrick Williams 
next()15052d23e8aSPatrick Williams inline auto match::next() noexcept
151290fa427SPatrick Williams {
152290fa427SPatrick Williams     return match_ns::match_sender(*this);
153290fa427SPatrick Williams }
154290fa427SPatrick Williams 
155290fa427SPatrick Williams template <typename... Rs>
next()156290fa427SPatrick Williams auto match::next() noexcept
157290fa427SPatrick Williams {
158290fa427SPatrick Williams     return match_ns::match_sender(*this) |
159290fa427SPatrick Williams            execution::then([](message_t&& m) { return m.unpack<Rs...>(); });
160290fa427SPatrick Williams }
161290fa427SPatrick Williams 
162290fa427SPatrick Williams } // namespace sdbusplus::async
163