• Home
  • History
  • Annotate
  • 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 
24 namespace art {
25 
26 class MessageQueueTest : public CommonRuntimeTest {};
27 
28 namespace {
29 
30 // Define some message types
31 struct EmptyMessage {};
32 struct IntMessage {
33   int value;
34 };
35 struct OtherIntMessage {
36   int other_value;
37 };
38 struct TwoIntMessage {
39   int value1;
40   int value2;
41 };
42 struct StringMessage {
43   std::string message;
44 };
45 
46 using TestMessageQueue =
47     MessageQueue<EmptyMessage, IntMessage, OtherIntMessage, TwoIntMessage, StringMessage>;
48 
49 }  // namespace
50 
51 TEST_F(MessageQueueTest, SendReceiveTest) {
52   TestMessageQueue queue;
53 
54   queue.SendMessage(EmptyMessage{});
55   ASSERT_TRUE(std::holds_alternative<EmptyMessage>(queue.ReceiveMessage()));
56 
57   queue.SendMessage(IntMessage{42});
58   ASSERT_TRUE(std::holds_alternative<IntMessage>(queue.ReceiveMessage()));
59 
60   queue.SendMessage(OtherIntMessage{43});
61   ASSERT_TRUE(std::holds_alternative<OtherIntMessage>(queue.ReceiveMessage()));
62 
63   queue.SendMessage(TwoIntMessage{1, 2});
64   ASSERT_TRUE(std::holds_alternative<TwoIntMessage>(queue.ReceiveMessage()));
65 
66   queue.SendMessage(StringMessage{"Hello, World!"});
67   ASSERT_TRUE(std::holds_alternative<StringMessage>(queue.ReceiveMessage()));
68 }
69 
70 TEST_F(MessageQueueTest, TestTimeout) {
71   TestMessageQueue queue;
72 
73   constexpr uint64_t kDuration = 500;
74 
75   const auto start = MilliTime();
76   queue.SetTimeout(kDuration);
77   ASSERT_TRUE(std::holds_alternative<TimeoutExpiredMessage>(queue.ReceiveMessage()));
78   const auto elapsed = MilliTime() - start;
79 
80   ASSERT_GT(elapsed, kDuration);
81 }
82 
83 TEST_F(MessageQueueTest, TwoWayMessaging) {
84   TestMessageQueue queue1;
85   TestMessageQueue queue2;
86 
87   std::thread thread{[&]() {
88     // Tell the parent thread we are running.
89     queue1.SendMessage(EmptyMessage{});
90 
91     // Wait for a message from the parent thread.
92     queue2.ReceiveMessage();
93   }};
94 
95   queue1.ReceiveMessage();
96   queue2.SendMessage(EmptyMessage{});
97 
98   thread.join();
99 }
100 
101 TEST_F(MessageQueueTest, SwitchReceiveTest) {
102   TestMessageQueue queue;
103 
104   queue.SendMessage(EmptyMessage{});
105   queue.SendMessage(IntMessage{42});
106   queue.SendMessage(OtherIntMessage{43});
107   queue.SendMessage(TwoIntMessage{1, 2});
108   queue.SendMessage(StringMessage{"Hello, World!"});
109   queue.SetTimeout(500);
110 
111   bool empty_received = false;
112   bool int_received = false;
113   bool other_int_received = false;
114   bool two_int_received = false;
115   bool string_received = false;
116   bool timeout_received = false;
117 
118   while (!(empty_received && int_received && other_int_received && two_int_received &&
119            string_received && timeout_received)) {
120     queue.SwitchReceive(
121         [&]([[maybe_unused]] const EmptyMessage& message) {
122           ASSERT_FALSE(empty_received);
123           empty_received = true;
124         },
125         [&](const IntMessage& message) {
126           ASSERT_FALSE(int_received);
127           int_received = true;
128 
129           ASSERT_EQ(message.value, 42);
130         },
131         [&](const OtherIntMessage& message) {
132           ASSERT_FALSE(other_int_received);
133           other_int_received = true;
134 
135           ASSERT_EQ(message.other_value, 43);
136         },
137         // The timeout message is here to make sure the cases can go in any order
138         [&]([[maybe_unused]] const TimeoutExpiredMessage& message) {
139           ASSERT_FALSE(timeout_received);
140           timeout_received = true;
141         },
142         [&](const TwoIntMessage& message) {
143           ASSERT_FALSE(two_int_received);
144           two_int_received = true;
145 
146           ASSERT_EQ(message.value1, 1);
147           ASSERT_EQ(message.value2, 2);
148         },
149         [&](const StringMessage& message) {
150           ASSERT_FALSE(string_received);
151           string_received = true;
152 
153           ASSERT_EQ(message.message, "Hello, World!");
154         });
155   }
156 }
157 
158 TEST_F(MessageQueueTest, SwitchReceiveAutoTest) {
159   TestMessageQueue queue;
160 
161   queue.SendMessage(EmptyMessage{});
162   queue.SendMessage(IntMessage{42});
163   queue.SendMessage(OtherIntMessage{43});
164   queue.SendMessage(TwoIntMessage{1, 2});
165   queue.SendMessage(StringMessage{"Hello, World!"});
166   queue.SetTimeout(500);
167 
168   int pending_messages = 6;
169 
170   while (pending_messages > 0) {
171     queue.SwitchReceive([&]([[maybe_unused]] auto message) { pending_messages--; });
172   }
173 }
174 
175 TEST_F(MessageQueueTest, SwitchReceivePartialAutoTest) {
176   TestMessageQueue queue;
177 
178   queue.SendMessage(EmptyMessage{});
179   queue.SendMessage(IntMessage{42});
180   queue.SendMessage(OtherIntMessage{43});
181   queue.SendMessage(TwoIntMessage{1, 2});
182   queue.SendMessage(StringMessage{"Hello, World!"});
183   queue.SetTimeout(500);
184 
185   bool running = true;
186   while (running) {
187     queue.SwitchReceive(
188         [&](const StringMessage& message) {
189           ASSERT_EQ(message.message, "Hello, World!");
190           running = false;
191         },
192         [&]([[maybe_unused]] const auto& message) {
193           const bool is_string{std::is_same<StringMessage, decltype(message)>()};
194           ASSERT_FALSE(is_string);
195         });
196   }
197 }
198 
199 TEST_F(MessageQueueTest, SwitchReceiveReturn) {
200   TestMessageQueue queue;
201 
202   queue.SendMessage(EmptyMessage{});
203 
204   ASSERT_TRUE(
205       queue.SwitchReceive<bool>([&]([[maybe_unused]] const EmptyMessage& message) { return true; },
206                                 [&]([[maybe_unused]] const auto& message) { return false; }));
207 
208   queue.SendMessage(IntMessage{42});
209 
210   ASSERT_FALSE(
211       queue.SwitchReceive<bool>([&]([[maybe_unused]] const EmptyMessage& message) { return true; },
212                                 [&]([[maybe_unused]] const auto& message) { return false; }));
213 }
214 
215 TEST_F(MessageQueueTest, ReceiveInOrder) {
216   TestMessageQueue queue;
217 
218   std::vector<TestMessageQueue::Message> messages{
219       EmptyMessage{},
220       IntMessage{42},
221       OtherIntMessage{43},
222       TwoIntMessage{1, 2},
223       StringMessage{"Hello, World!"},
224   };
225 
226   // Send the messages
227   for (const auto& message : messages) {
228     queue.SendMessage(message);
229   }
230   queue.SetTimeout(500);
231 
232   // Receive the messages. Make sure they came in order, except for the TimeoutExpiredMessage, which
233   // can come at any time.
234   bool received_timeout = false;
235   size_t i = 0;
236   while (i < messages.size()) {
237     auto message = queue.ReceiveMessage();
238     if (std::holds_alternative<TimeoutExpiredMessage>(message)) {
239       ASSERT_FALSE(received_timeout);
240       received_timeout = true;
241     } else {
242       ASSERT_EQ(message.index(), messages[i].index());
243       i++;
244     }
245   }
246   if (!received_timeout) {
247     // If we have not received the timeout yet, receive one more message and make sure it's the
248     // timeout.
249     ASSERT_TRUE(std::holds_alternative<TimeoutExpiredMessage>(queue.ReceiveMessage()));
250   }
251 }
252 
253 }  // namespace art
254