1290fa427SPatrick Williams #include <sdbusplus/async/match.hpp>
2290fa427SPatrick Williams
3290fa427SPatrick Williams namespace sdbusplus::async
4290fa427SPatrick Williams {
5290fa427SPatrick Williams
makeMatch(context & ctx,const std::string_view & pattern)69d8ba947SWilliam A. Kennington III slot_t match::makeMatch(context& ctx, const std::string_view& pattern)
7290fa427SPatrick Williams {
8290fa427SPatrick Williams // C-style callback to redirect into this::handle_match.
9*06f265f6SPatrick Williams static auto match_cb =
10*06f265f6SPatrick Williams [](message::msgp_t msg, void* ctx, sd_bus_error*) noexcept {
11290fa427SPatrick Williams static_cast<match*>(ctx)->handle_match(message_t{msg});
12290fa427SPatrick Williams return 0;
13290fa427SPatrick Williams };
14290fa427SPatrick Williams
159d8ba947SWilliam A. Kennington III sd_bus_slot* s;
16*06f265f6SPatrick Williams auto r =
17*06f265f6SPatrick Williams sd_bus_add_match(get_busp(ctx), &s, pattern.data(), match_cb, this);
18290fa427SPatrick Williams if (r < 0)
19290fa427SPatrick Williams {
20290fa427SPatrick Williams throw exception::SdBusError(-r, "sd_bus_add_match (async::match)");
21290fa427SPatrick Williams }
22290fa427SPatrick Williams
239d8ba947SWilliam A. Kennington III return slot_t{s, &sdbus_impl};
24290fa427SPatrick Williams }
25290fa427SPatrick Williams
match(context & ctx,const std::string_view & pattern)269d8ba947SWilliam A. Kennington III match::match(context& ctx, const std::string_view& pattern) :
279d8ba947SWilliam A. Kennington III slot(makeMatch(ctx, pattern))
289d8ba947SWilliam A. Kennington III {}
299d8ba947SWilliam A. Kennington III
~match()301b7b54caSPatrick Williams match::~match()
311b7b54caSPatrick Williams {
321b7b54caSPatrick Williams match_ns::match_completion* c = nullptr;
331b7b54caSPatrick Williams
341b7b54caSPatrick Williams {
351b7b54caSPatrick Williams std::lock_guard l{lock};
361b7b54caSPatrick Williams c = std::exchange(complete, nullptr);
371b7b54caSPatrick Williams }
381b7b54caSPatrick Williams
391b7b54caSPatrick Williams if (c)
401b7b54caSPatrick Williams {
411b7b54caSPatrick Williams c->stop();
421b7b54caSPatrick Williams }
431b7b54caSPatrick Williams }
441b7b54caSPatrick Williams
arm()45290fa427SPatrick Williams void match_ns::match_completion::arm() noexcept
46290fa427SPatrick Williams {
47290fa427SPatrick Williams // Set ourselves as the awaiting Receiver and see if there is a message
48290fa427SPatrick Williams // to immediately complete on.
49290fa427SPatrick Williams
50290fa427SPatrick Williams std::unique_lock lock{m.lock};
51290fa427SPatrick Williams
52290fa427SPatrick Williams if (std::exchange(m.complete, this) != nullptr)
53290fa427SPatrick Williams {
54290fa427SPatrick Williams // We do not support two awaiters; throw exception. Since we are in
55290fa427SPatrick Williams // a noexcept context this will std::terminate anyhow, which is
56290fa427SPatrick Williams // approximately the same as 'assert' but with better information.
57290fa427SPatrick Williams try
58290fa427SPatrick Williams {
59290fa427SPatrick Williams throw std::logic_error(
60290fa427SPatrick Williams "match_completion started with another await already pending!");
61290fa427SPatrick Williams }
62290fa427SPatrick Williams catch (...)
63290fa427SPatrick Williams {
64290fa427SPatrick Williams std::terminate();
65290fa427SPatrick Williams }
66290fa427SPatrick Williams }
67290fa427SPatrick Williams
68290fa427SPatrick Williams m.handle_completion(std::move(lock));
69290fa427SPatrick Williams }
70290fa427SPatrick Williams
handle_match(message_t && msg)71290fa427SPatrick Williams void match::handle_match(message_t&& msg) noexcept
72290fa427SPatrick Williams {
73290fa427SPatrick Williams // Insert the message into the queue and see if there is a pair ready for
74290fa427SPatrick Williams // completion (Receiver + message).
75290fa427SPatrick Williams std::unique_lock l{lock};
76290fa427SPatrick Williams queue.emplace(std::move(msg));
77290fa427SPatrick Williams handle_completion(std::move(l));
78290fa427SPatrick Williams }
79290fa427SPatrick Williams
handle_completion(std::unique_lock<std::mutex> && l)80290fa427SPatrick Williams void match::handle_completion(std::unique_lock<std::mutex>&& l) noexcept
81290fa427SPatrick Williams {
82290fa427SPatrick Williams auto lock = std::move(l);
83290fa427SPatrick Williams
84290fa427SPatrick Williams // If there is no match_completion, there is no awaiting Receiver.
85290fa427SPatrick Williams // If the queue is empty, there is no message waiting, so the waiting
86290fa427SPatrick Williams // Receiver isn't complete.
87290fa427SPatrick Williams if ((complete == nullptr) || queue.empty())
88290fa427SPatrick Williams {
89290fa427SPatrick Williams return;
90290fa427SPatrick Williams }
91290fa427SPatrick Williams
92290fa427SPatrick Williams // Get the waiting completion and message.
93290fa427SPatrick Williams auto c = std::exchange(complete, nullptr);
94290fa427SPatrick Williams auto msg = std::move(queue.front());
95290fa427SPatrick Williams queue.pop();
96290fa427SPatrick Williams
97290fa427SPatrick Williams // Unlock before calling complete because the completed task may run and
98290fa427SPatrick Williams // attempt to complete on the next event (and thus deadlock).
99290fa427SPatrick Williams lock.unlock();
100290fa427SPatrick Williams
101290fa427SPatrick Williams // Signal completion.
102290fa427SPatrick Williams c->complete(std::move(msg));
103290fa427SPatrick Williams }
104290fa427SPatrick Williams
105290fa427SPatrick Williams } // namespace sdbusplus::async
106