xref: /openbmc/sdbusplus/test/async/mutex.cpp (revision 540ad059e6e423141e3f31f906a81961b552a749)
1 #include <sdbusplus/async.hpp>
2 
3 #include <filesystem>
4 #include <fstream>
5 
6 #include <gtest/gtest.h>
7 
8 using namespace std::literals;
9 
10 namespace fs = std::filesystem;
11 
12 class MutexTest : public ::testing::Test
13 {
14   protected:
15     ~MutexTest() noexcept override = default;
16     constexpr static std::string testMutex = "TestMutex";
17     const fs::path path = "/tmp";
18 
MutexTest()19     MutexTest() : mutex(testMutex)
20     {
21         auto fd = inotify_init1(IN_NONBLOCK);
22         EXPECT_NE(fd, -1) << "Error occurred during the inotify_init1, error: "
23                           << errno;
24 
25         auto wd = inotify_add_watch(fd, path.c_str(), IN_CLOSE_WRITE);
26         EXPECT_NE(wd, -1)
27             << "Error occurred during the inotify_add_watch, error: " << errno;
28         fdioInstance = std::make_unique<sdbusplus::async::fdio>(*ctx, fd);
29     }
30 
31     std::optional<sdbusplus::async::context> ctx{std::in_place};
32 
testAsyncAddition(int val=1)33     auto testAsyncAddition(int val = 1) -> sdbusplus::async::task<>
34     {
35         sdbusplus::async::lock_guard lg{mutex};
36         co_await lg.lock();
37 
38         sharedVar += val;
39     }
40 
testAsyncSubtraction(int val=1)41     auto testAsyncSubtraction(int val = 1) -> sdbusplus::async::task<>
42     {
43         sdbusplus::async::lock_guard lg{mutex};
44         co_await lg.lock();
45 
46         sharedVar -= val;
47     }
48 
writeToFile()49     auto writeToFile() -> sdbusplus::async::task<>
50     {
51         std::ofstream outfile((path / testMutex).native());
52         EXPECT_TRUE(outfile.is_open())
53             << "Error occurred during file open, error: " << errno;
54 
55         outfile << testMutex << std::endl;
56         outfile.close();
57 
58         co_return;
59     }
60 
readFromFile()61     auto readFromFile() -> sdbusplus::async::task<>
62     {
63         std::ifstream infile((path / testMutex).native());
64         EXPECT_TRUE(infile.is_open())
65             << "Error occurred during file open, error: " << errno;
66 
67         std::string line;
68         std::getline(infile, line);
69         EXPECT_EQ(line, testMutex);
70         infile.close();
71 
72         co_return;
73     }
74 
testFdEvents()75     auto testFdEvents() -> sdbusplus::async::task<>
76     {
77         sdbusplus::async::lock_guard lg{mutex};
78         co_await lg.lock();
79 
80         ctx->spawn(writeToFile());
81         co_await fdioInstance->next();
82         co_await readFromFile();
83         ran++;
84 
85         co_return;
86     }
87 
88     int sharedVar = 0;
89     int ran = 0;
90     sdbusplus::async::mutex mutex;
91 
92   private:
93     std::unique_ptr<sdbusplus::async::fdio> fdioInstance;
94 };
95 
TEST_F(MutexTest,TestAsyncAddition)96 TEST_F(MutexTest, TestAsyncAddition)
97 {
98     constexpr auto testIterations = 10;
99     for (auto i = 0; i < testIterations; i++)
100     {
101         ctx->spawn(testAsyncAddition());
102     }
103 
104     ctx->spawn(
105         sdbusplus::async::sleep_for(*ctx, 1s) |
106         sdbusplus::async::execution::then([&]() { ctx->request_stop(); }));
107 
108     ctx->run();
109 
110     EXPECT_EQ(sharedVar, testIterations);
111 }
112 
TEST_F(MutexTest,TestAsyncMixed)113 TEST_F(MutexTest, TestAsyncMixed)
114 {
115     constexpr auto testIterations = 10;
116     for (auto i = 0; i < testIterations; i++)
117     {
118         ctx->spawn(testAsyncAddition());
119         ctx->spawn(testAsyncSubtraction(2));
120     }
121 
122     ctx->spawn(
123         sdbusplus::async::sleep_for(*ctx, 1s) |
124         sdbusplus::async::execution::then([&]() { ctx->request_stop(); }));
125 
126     ctx->run();
127 
128     EXPECT_EQ(sharedVar, -testIterations);
129 }
130 
TEST_F(MutexTest,TestFdEvents)131 TEST_F(MutexTest, TestFdEvents)
132 {
133     constexpr static auto testIterations = 5;
134 
135     for (auto i = 0; i < testIterations; i++)
136     {
137         ctx->spawn(testFdEvents());
138     }
139     ctx->spawn(
140         sdbusplus::async::sleep_for(*ctx, 3s) |
141         sdbusplus::async::execution::then([&]() { ctx->request_stop(); }));
142     ctx->run();
143     EXPECT_EQ(ran, testIterations);
144 }
145 
TEST_F(MutexTest,TestLockGuardNoLock)146 TEST_F(MutexTest, TestLockGuardNoLock)
147 {
148     sdbusplus::async::lock_guard lg{mutex};
149 }
150