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