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