xref: /aosp_15_r20/art/runtime/base/message_queue_test.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2020 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #include "message_queue.h"
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include <thread>
20*795d594fSAndroid Build Coastguard Worker 
21*795d594fSAndroid Build Coastguard Worker #include "common_runtime_test.h"
22*795d594fSAndroid Build Coastguard Worker #include "thread-current-inl.h"
23*795d594fSAndroid Build Coastguard Worker #include "runtime.h"
24*795d594fSAndroid Build Coastguard Worker 
25*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
26*795d594fSAndroid Build Coastguard Worker 
27*795d594fSAndroid Build Coastguard Worker class MessageQueueTest : public CommonRuntimeTest {
28*795d594fSAndroid Build Coastguard Worker  protected:
MessageQueueTest()29*795d594fSAndroid Build Coastguard Worker   MessageQueueTest() {
30*795d594fSAndroid Build Coastguard Worker     this->use_boot_image_ = true;  // Make the Runtime creation cheaper.
31*795d594fSAndroid Build Coastguard Worker   }
32*795d594fSAndroid Build Coastguard Worker };
33*795d594fSAndroid Build Coastguard Worker 
34*795d594fSAndroid Build Coastguard Worker namespace {
35*795d594fSAndroid Build Coastguard Worker 
36*795d594fSAndroid Build Coastguard Worker // Define some message types
37*795d594fSAndroid Build Coastguard Worker struct EmptyMessage {};
38*795d594fSAndroid Build Coastguard Worker struct IntMessage {
39*795d594fSAndroid Build Coastguard Worker   int value;
40*795d594fSAndroid Build Coastguard Worker };
41*795d594fSAndroid Build Coastguard Worker struct OtherIntMessage {
42*795d594fSAndroid Build Coastguard Worker   int other_value;
43*795d594fSAndroid Build Coastguard Worker };
44*795d594fSAndroid Build Coastguard Worker struct TwoIntMessage {
45*795d594fSAndroid Build Coastguard Worker   int value1;
46*795d594fSAndroid Build Coastguard Worker   int value2;
47*795d594fSAndroid Build Coastguard Worker };
48*795d594fSAndroid Build Coastguard Worker struct StringMessage {
49*795d594fSAndroid Build Coastguard Worker   std::string message;
50*795d594fSAndroid Build Coastguard Worker };
51*795d594fSAndroid Build Coastguard Worker 
52*795d594fSAndroid Build Coastguard Worker using TestMessageQueue =
53*795d594fSAndroid Build Coastguard Worker     MessageQueue<EmptyMessage, IntMessage, OtherIntMessage, TwoIntMessage, StringMessage>;
54*795d594fSAndroid Build Coastguard Worker 
55*795d594fSAndroid Build Coastguard Worker }  // namespace
56*795d594fSAndroid Build Coastguard Worker 
TEST_F(MessageQueueTest,SendReceiveTest)57*795d594fSAndroid Build Coastguard Worker TEST_F(MessageQueueTest, SendReceiveTest) {
58*795d594fSAndroid Build Coastguard Worker   TestMessageQueue queue;
59*795d594fSAndroid Build Coastguard Worker 
60*795d594fSAndroid Build Coastguard Worker   queue.SendMessage(EmptyMessage{});
61*795d594fSAndroid Build Coastguard Worker   ASSERT_TRUE(std::holds_alternative<EmptyMessage>(queue.ReceiveMessage()));
62*795d594fSAndroid Build Coastguard Worker 
63*795d594fSAndroid Build Coastguard Worker   queue.SendMessage(IntMessage{42});
64*795d594fSAndroid Build Coastguard Worker   ASSERT_TRUE(std::holds_alternative<IntMessage>(queue.ReceiveMessage()));
65*795d594fSAndroid Build Coastguard Worker 
66*795d594fSAndroid Build Coastguard Worker   queue.SendMessage(OtherIntMessage{43});
67*795d594fSAndroid Build Coastguard Worker   ASSERT_TRUE(std::holds_alternative<OtherIntMessage>(queue.ReceiveMessage()));
68*795d594fSAndroid Build Coastguard Worker 
69*795d594fSAndroid Build Coastguard Worker   queue.SendMessage(TwoIntMessage{1, 2});
70*795d594fSAndroid Build Coastguard Worker   ASSERT_TRUE(std::holds_alternative<TwoIntMessage>(queue.ReceiveMessage()));
71*795d594fSAndroid Build Coastguard Worker 
72*795d594fSAndroid Build Coastguard Worker   queue.SendMessage(StringMessage{"Hello, World!"});
73*795d594fSAndroid Build Coastguard Worker   ASSERT_TRUE(std::holds_alternative<StringMessage>(queue.ReceiveMessage()));
74*795d594fSAndroid Build Coastguard Worker }
75*795d594fSAndroid Build Coastguard Worker 
TEST_F(MessageQueueTest,TestTimeout)76*795d594fSAndroid Build Coastguard Worker TEST_F(MessageQueueTest, TestTimeout) {
77*795d594fSAndroid Build Coastguard Worker   TestMessageQueue queue;
78*795d594fSAndroid Build Coastguard Worker 
79*795d594fSAndroid Build Coastguard Worker   constexpr uint64_t kDuration = 500;
80*795d594fSAndroid Build Coastguard Worker 
81*795d594fSAndroid Build Coastguard Worker   const auto start = MilliTime();
82*795d594fSAndroid Build Coastguard Worker   queue.SetTimeout(kDuration);
83*795d594fSAndroid Build Coastguard Worker   ASSERT_TRUE(std::holds_alternative<TimeoutExpiredMessage>(queue.ReceiveMessage()));
84*795d594fSAndroid Build Coastguard Worker   const auto elapsed = MilliTime() - start;
85*795d594fSAndroid Build Coastguard Worker 
86*795d594fSAndroid Build Coastguard Worker   ASSERT_GT(elapsed, kDuration);
87*795d594fSAndroid Build Coastguard Worker }
88*795d594fSAndroid Build Coastguard Worker 
TEST_F(MessageQueueTest,TwoWayMessaging)89*795d594fSAndroid Build Coastguard Worker TEST_F(MessageQueueTest, TwoWayMessaging) {
90*795d594fSAndroid Build Coastguard Worker   CHECK(Runtime::Current() != nullptr);  // Runtime is needed by Mutex.
91*795d594fSAndroid Build Coastguard Worker 
92*795d594fSAndroid Build Coastguard Worker   TestMessageQueue queue1;
93*795d594fSAndroid Build Coastguard Worker   TestMessageQueue queue2;
94*795d594fSAndroid Build Coastguard Worker 
95*795d594fSAndroid Build Coastguard Worker   std::thread thread{[&]() {
96*795d594fSAndroid Build Coastguard Worker     // Tell the parent thread we are running.
97*795d594fSAndroid Build Coastguard Worker     queue1.SendMessage(EmptyMessage{});
98*795d594fSAndroid Build Coastguard Worker 
99*795d594fSAndroid Build Coastguard Worker     // Wait for a message from the parent thread.
100*795d594fSAndroid Build Coastguard Worker     queue2.ReceiveMessage();
101*795d594fSAndroid Build Coastguard Worker   }};
102*795d594fSAndroid Build Coastguard Worker 
103*795d594fSAndroid Build Coastguard Worker   queue1.ReceiveMessage();
104*795d594fSAndroid Build Coastguard Worker   queue2.SendMessage(EmptyMessage{});
105*795d594fSAndroid Build Coastguard Worker 
106*795d594fSAndroid Build Coastguard Worker   thread.join();
107*795d594fSAndroid Build Coastguard Worker }
108*795d594fSAndroid Build Coastguard Worker 
TEST_F(MessageQueueTest,SwitchReceiveTest)109*795d594fSAndroid Build Coastguard Worker TEST_F(MessageQueueTest, SwitchReceiveTest) {
110*795d594fSAndroid Build Coastguard Worker   TestMessageQueue queue;
111*795d594fSAndroid Build Coastguard Worker 
112*795d594fSAndroid Build Coastguard Worker   queue.SendMessage(EmptyMessage{});
113*795d594fSAndroid Build Coastguard Worker   queue.SendMessage(IntMessage{42});
114*795d594fSAndroid Build Coastguard Worker   queue.SendMessage(OtherIntMessage{43});
115*795d594fSAndroid Build Coastguard Worker   queue.SendMessage(TwoIntMessage{1, 2});
116*795d594fSAndroid Build Coastguard Worker   queue.SendMessage(StringMessage{"Hello, World!"});
117*795d594fSAndroid Build Coastguard Worker   queue.SetTimeout(500);
118*795d594fSAndroid Build Coastguard Worker 
119*795d594fSAndroid Build Coastguard Worker   bool empty_received = false;
120*795d594fSAndroid Build Coastguard Worker   bool int_received = false;
121*795d594fSAndroid Build Coastguard Worker   bool other_int_received = false;
122*795d594fSAndroid Build Coastguard Worker   bool two_int_received = false;
123*795d594fSAndroid Build Coastguard Worker   bool string_received = false;
124*795d594fSAndroid Build Coastguard Worker   bool timeout_received = false;
125*795d594fSAndroid Build Coastguard Worker 
126*795d594fSAndroid Build Coastguard Worker   while (!(empty_received && int_received && other_int_received && two_int_received &&
127*795d594fSAndroid Build Coastguard Worker            string_received && timeout_received)) {
128*795d594fSAndroid Build Coastguard Worker     queue.SwitchReceive(
129*795d594fSAndroid Build Coastguard Worker         [&]([[maybe_unused]] const EmptyMessage& message) {
130*795d594fSAndroid Build Coastguard Worker           ASSERT_FALSE(empty_received);
131*795d594fSAndroid Build Coastguard Worker           empty_received = true;
132*795d594fSAndroid Build Coastguard Worker         },
133*795d594fSAndroid Build Coastguard Worker         [&](const IntMessage& message) {
134*795d594fSAndroid Build Coastguard Worker           ASSERT_FALSE(int_received);
135*795d594fSAndroid Build Coastguard Worker           int_received = true;
136*795d594fSAndroid Build Coastguard Worker 
137*795d594fSAndroid Build Coastguard Worker           ASSERT_EQ(message.value, 42);
138*795d594fSAndroid Build Coastguard Worker         },
139*795d594fSAndroid Build Coastguard Worker         [&](const OtherIntMessage& message) {
140*795d594fSAndroid Build Coastguard Worker           ASSERT_FALSE(other_int_received);
141*795d594fSAndroid Build Coastguard Worker           other_int_received = true;
142*795d594fSAndroid Build Coastguard Worker 
143*795d594fSAndroid Build Coastguard Worker           ASSERT_EQ(message.other_value, 43);
144*795d594fSAndroid Build Coastguard Worker         },
145*795d594fSAndroid Build Coastguard Worker         // The timeout message is here to make sure the cases can go in any order
146*795d594fSAndroid Build Coastguard Worker         [&]([[maybe_unused]] const TimeoutExpiredMessage& message) {
147*795d594fSAndroid Build Coastguard Worker           ASSERT_FALSE(timeout_received);
148*795d594fSAndroid Build Coastguard Worker           timeout_received = true;
149*795d594fSAndroid Build Coastguard Worker         },
150*795d594fSAndroid Build Coastguard Worker         [&](const TwoIntMessage& message) {
151*795d594fSAndroid Build Coastguard Worker           ASSERT_FALSE(two_int_received);
152*795d594fSAndroid Build Coastguard Worker           two_int_received = true;
153*795d594fSAndroid Build Coastguard Worker 
154*795d594fSAndroid Build Coastguard Worker           ASSERT_EQ(message.value1, 1);
155*795d594fSAndroid Build Coastguard Worker           ASSERT_EQ(message.value2, 2);
156*795d594fSAndroid Build Coastguard Worker         },
157*795d594fSAndroid Build Coastguard Worker         [&](const StringMessage& message) {
158*795d594fSAndroid Build Coastguard Worker           ASSERT_FALSE(string_received);
159*795d594fSAndroid Build Coastguard Worker           string_received = true;
160*795d594fSAndroid Build Coastguard Worker 
161*795d594fSAndroid Build Coastguard Worker           ASSERT_EQ(message.message, "Hello, World!");
162*795d594fSAndroid Build Coastguard Worker         });
163*795d594fSAndroid Build Coastguard Worker   }
164*795d594fSAndroid Build Coastguard Worker }
165*795d594fSAndroid Build Coastguard Worker 
TEST_F(MessageQueueTest,SwitchReceiveAutoTest)166*795d594fSAndroid Build Coastguard Worker TEST_F(MessageQueueTest, SwitchReceiveAutoTest) {
167*795d594fSAndroid Build Coastguard Worker   TestMessageQueue queue;
168*795d594fSAndroid Build Coastguard Worker 
169*795d594fSAndroid Build Coastguard Worker   queue.SendMessage(EmptyMessage{});
170*795d594fSAndroid Build Coastguard Worker   queue.SendMessage(IntMessage{42});
171*795d594fSAndroid Build Coastguard Worker   queue.SendMessage(OtherIntMessage{43});
172*795d594fSAndroid Build Coastguard Worker   queue.SendMessage(TwoIntMessage{1, 2});
173*795d594fSAndroid Build Coastguard Worker   queue.SendMessage(StringMessage{"Hello, World!"});
174*795d594fSAndroid Build Coastguard Worker   queue.SetTimeout(500);
175*795d594fSAndroid Build Coastguard Worker 
176*795d594fSAndroid Build Coastguard Worker   int pending_messages = 6;
177*795d594fSAndroid Build Coastguard Worker 
178*795d594fSAndroid Build Coastguard Worker   while (pending_messages > 0) {
179*795d594fSAndroid Build Coastguard Worker     queue.SwitchReceive([&]([[maybe_unused]] auto message) { pending_messages--; });
180*795d594fSAndroid Build Coastguard Worker   }
181*795d594fSAndroid Build Coastguard Worker }
182*795d594fSAndroid Build Coastguard Worker 
TEST_F(MessageQueueTest,SwitchReceivePartialAutoTest)183*795d594fSAndroid Build Coastguard Worker TEST_F(MessageQueueTest, SwitchReceivePartialAutoTest) {
184*795d594fSAndroid Build Coastguard Worker   TestMessageQueue queue;
185*795d594fSAndroid Build Coastguard Worker 
186*795d594fSAndroid Build Coastguard Worker   queue.SendMessage(EmptyMessage{});
187*795d594fSAndroid Build Coastguard Worker   queue.SendMessage(IntMessage{42});
188*795d594fSAndroid Build Coastguard Worker   queue.SendMessage(OtherIntMessage{43});
189*795d594fSAndroid Build Coastguard Worker   queue.SendMessage(TwoIntMessage{1, 2});
190*795d594fSAndroid Build Coastguard Worker   queue.SendMessage(StringMessage{"Hello, World!"});
191*795d594fSAndroid Build Coastguard Worker   queue.SetTimeout(500);
192*795d594fSAndroid Build Coastguard Worker 
193*795d594fSAndroid Build Coastguard Worker   bool running = true;
194*795d594fSAndroid Build Coastguard Worker   while (running) {
195*795d594fSAndroid Build Coastguard Worker     queue.SwitchReceive(
196*795d594fSAndroid Build Coastguard Worker         [&](const StringMessage& message) {
197*795d594fSAndroid Build Coastguard Worker           ASSERT_EQ(message.message, "Hello, World!");
198*795d594fSAndroid Build Coastguard Worker           running = false;
199*795d594fSAndroid Build Coastguard Worker         },
200*795d594fSAndroid Build Coastguard Worker         [&]([[maybe_unused]] const auto& message) {
201*795d594fSAndroid Build Coastguard Worker           const bool is_string{std::is_same<StringMessage, decltype(message)>()};
202*795d594fSAndroid Build Coastguard Worker           ASSERT_FALSE(is_string);
203*795d594fSAndroid Build Coastguard Worker         });
204*795d594fSAndroid Build Coastguard Worker   }
205*795d594fSAndroid Build Coastguard Worker }
206*795d594fSAndroid Build Coastguard Worker 
TEST_F(MessageQueueTest,SwitchReceiveReturn)207*795d594fSAndroid Build Coastguard Worker TEST_F(MessageQueueTest, SwitchReceiveReturn) {
208*795d594fSAndroid Build Coastguard Worker   TestMessageQueue queue;
209*795d594fSAndroid Build Coastguard Worker 
210*795d594fSAndroid Build Coastguard Worker   queue.SendMessage(EmptyMessage{});
211*795d594fSAndroid Build Coastguard Worker 
212*795d594fSAndroid Build Coastguard Worker   ASSERT_TRUE(
213*795d594fSAndroid Build Coastguard Worker       queue.SwitchReceive<bool>([&]([[maybe_unused]] const EmptyMessage& message) { return true; },
214*795d594fSAndroid Build Coastguard Worker                                 [&]([[maybe_unused]] const auto& message) { return false; }));
215*795d594fSAndroid Build Coastguard Worker 
216*795d594fSAndroid Build Coastguard Worker   queue.SendMessage(IntMessage{42});
217*795d594fSAndroid Build Coastguard Worker 
218*795d594fSAndroid Build Coastguard Worker   ASSERT_FALSE(
219*795d594fSAndroid Build Coastguard Worker       queue.SwitchReceive<bool>([&]([[maybe_unused]] const EmptyMessage& message) { return true; },
220*795d594fSAndroid Build Coastguard Worker                                 [&]([[maybe_unused]] const auto& message) { return false; }));
221*795d594fSAndroid Build Coastguard Worker }
222*795d594fSAndroid Build Coastguard Worker 
TEST_F(MessageQueueTest,ReceiveInOrder)223*795d594fSAndroid Build Coastguard Worker TEST_F(MessageQueueTest, ReceiveInOrder) {
224*795d594fSAndroid Build Coastguard Worker   TestMessageQueue queue;
225*795d594fSAndroid Build Coastguard Worker 
226*795d594fSAndroid Build Coastguard Worker   std::vector<TestMessageQueue::Message> messages{
227*795d594fSAndroid Build Coastguard Worker       EmptyMessage{},
228*795d594fSAndroid Build Coastguard Worker       IntMessage{42},
229*795d594fSAndroid Build Coastguard Worker       OtherIntMessage{43},
230*795d594fSAndroid Build Coastguard Worker       TwoIntMessage{1, 2},
231*795d594fSAndroid Build Coastguard Worker       StringMessage{"Hello, World!"},
232*795d594fSAndroid Build Coastguard Worker   };
233*795d594fSAndroid Build Coastguard Worker 
234*795d594fSAndroid Build Coastguard Worker   // Send the messages
235*795d594fSAndroid Build Coastguard Worker   for (const auto& message : messages) {
236*795d594fSAndroid Build Coastguard Worker     queue.SendMessage(message);
237*795d594fSAndroid Build Coastguard Worker   }
238*795d594fSAndroid Build Coastguard Worker   queue.SetTimeout(500);
239*795d594fSAndroid Build Coastguard Worker 
240*795d594fSAndroid Build Coastguard Worker   // Receive the messages. Make sure they came in order, except for the TimeoutExpiredMessage, which
241*795d594fSAndroid Build Coastguard Worker   // can come at any time.
242*795d594fSAndroid Build Coastguard Worker   bool received_timeout = false;
243*795d594fSAndroid Build Coastguard Worker   size_t i = 0;
244*795d594fSAndroid Build Coastguard Worker   while (i < messages.size()) {
245*795d594fSAndroid Build Coastguard Worker     auto message = queue.ReceiveMessage();
246*795d594fSAndroid Build Coastguard Worker     if (std::holds_alternative<TimeoutExpiredMessage>(message)) {
247*795d594fSAndroid Build Coastguard Worker       ASSERT_FALSE(received_timeout);
248*795d594fSAndroid Build Coastguard Worker       received_timeout = true;
249*795d594fSAndroid Build Coastguard Worker     } else {
250*795d594fSAndroid Build Coastguard Worker       ASSERT_EQ(message.index(), messages[i].index());
251*795d594fSAndroid Build Coastguard Worker       i++;
252*795d594fSAndroid Build Coastguard Worker     }
253*795d594fSAndroid Build Coastguard Worker   }
254*795d594fSAndroid Build Coastguard Worker   if (!received_timeout) {
255*795d594fSAndroid Build Coastguard Worker     // If we have not received the timeout yet, receive one more message and make sure it's the
256*795d594fSAndroid Build Coastguard Worker     // timeout.
257*795d594fSAndroid Build Coastguard Worker     ASSERT_TRUE(std::holds_alternative<TimeoutExpiredMessage>(queue.ReceiveMessage()));
258*795d594fSAndroid Build Coastguard Worker   }
259*795d594fSAndroid Build Coastguard Worker }
260*795d594fSAndroid Build Coastguard Worker 
261*795d594fSAndroid Build Coastguard Worker }  // namespace art
262