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