| #include <memory> |
| #include <string> |
| #include <thread> |
| #include <utility> |
| |
| #include <gtest/gtest.h> |
| #include <pdx/rpc/message_buffer.h> |
| |
| namespace android { |
| namespace pdx { |
| namespace rpc { |
| |
| class ThreadLocalBufferTest { |
| public: |
| // Returns the unique address of the thread-local buffer. Used to test the |
| // correct behavior of the type-based thread local storage slot mapping |
| // mechanism. |
| template <typename Slot> |
| static std::uintptr_t GetSlotAddress() { |
| return reinterpret_cast<std::uintptr_t>(&MessageBuffer<Slot>::buffer_); |
| } |
| |
| // Returns the raw value of the thread local buffer. Used to test the behavior |
| // of backing buffer initialization. |
| template <typename Slot> |
| static std::uintptr_t GetSlotValue() { |
| return reinterpret_cast<std::uintptr_t>(MessageBuffer<Slot>::buffer_); |
| } |
| }; |
| |
| } // namespace rpc |
| } // namespace pdx |
| } // namespace android |
| |
| using namespace android::pdx::rpc; |
| |
| namespace { |
| |
| struct TypeTagA; |
| struct TypeTagB; |
| |
| constexpr std::size_t kSendBufferIndex = 0; |
| constexpr std::size_t kReceiveBufferIndex = 1; |
| |
| using SendSlotA = ThreadLocalSlot<TypeTagA, kSendBufferIndex>; |
| using SendSlotB = ThreadLocalSlot<TypeTagB, kSendBufferIndex>; |
| using ReceiveSlotA = ThreadLocalSlot<TypeTagA, kReceiveBufferIndex>; |
| using ReceiveSlotB = ThreadLocalSlot<TypeTagB, kReceiveBufferIndex>; |
| |
| } // anonymous namespace |
| |
| // Tests that index and type-based thread-local slot addressing works by |
| // checking that the slot address is the same when the same index/type |
| // combination is used and different when different combinations are used. |
| TEST(ThreadLocalBufferTest, TypeSlots) { |
| auto id1 = ThreadLocalBufferTest::GetSlotAddress<SendSlotA>(); |
| auto id2 = ThreadLocalBufferTest::GetSlotAddress<ReceiveSlotA>(); |
| auto id3 = ThreadLocalBufferTest::GetSlotAddress<SendSlotB>(); |
| auto id4 = ThreadLocalBufferTest::GetSlotAddress<ReceiveSlotB>(); |
| |
| EXPECT_NE(id1, id2); |
| EXPECT_NE(id3, id4); |
| EXPECT_NE(id1, id3); |
| EXPECT_NE(id2, id4); |
| |
| auto id1_alias = ThreadLocalBufferTest::GetSlotAddress<SendSlotA>(); |
| auto id2_alias = ThreadLocalBufferTest::GetSlotAddress<ReceiveSlotA>(); |
| auto id3_alias = ThreadLocalBufferTest::GetSlotAddress<SendSlotB>(); |
| auto id4_alias = ThreadLocalBufferTest::GetSlotAddress<ReceiveSlotB>(); |
| |
| EXPECT_EQ(id1, id1_alias); |
| EXPECT_EQ(id2, id2_alias); |
| EXPECT_EQ(id3, id3_alias); |
| EXPECT_EQ(id4, id4_alias); |
| } |
| |
| // Tests that different threads get different buffers for the same slot address. |
| TEST(ThreadLocalBufferTest, ThreadSlots) { |
| auto id1 = ThreadLocalBufferTest::GetSlotAddress<SendBuffer>(); |
| std::uintptr_t id2 = 0U; |
| |
| std::thread thread([&id2]() mutable { |
| id2 = ThreadLocalBufferTest::GetSlotAddress<SendBuffer>(); |
| }); |
| thread.join(); |
| |
| EXPECT_NE(0U, id1); |
| EXPECT_NE(0U, id2); |
| EXPECT_NE(id1, id2); |
| } |
| |
| // Tests that thread-local buffers are allocated at the first buffer request. |
| TEST(ThreadLocalBufferTest, InitialValue) { |
| struct TypeTagX; |
| using SendSlotX = ThreadLocalSlot<TypeTagX, kSendBufferIndex>; |
| |
| auto value1 = ThreadLocalBufferTest::GetSlotValue<SendSlotX>(); |
| MessageBuffer<SendSlotX>::GetBuffer(); |
| auto value2 = ThreadLocalBufferTest::GetSlotValue<SendSlotX>(); |
| |
| EXPECT_EQ(0U, value1); |
| EXPECT_NE(0U, value2); |
| } |
| |
| // Tests that the underlying buffers are the same for a given index/type pair |
| // and different across index/type combinations. |
| TEST(ThreadLocalBufferTest, BackingBuffer) { |
| auto& buffer1 = MessageBuffer<SendSlotA>::GetBuffer(); |
| auto& buffer2 = MessageBuffer<SendSlotA>::GetBuffer(); |
| auto& buffer3 = MessageBuffer<SendSlotB>::GetBuffer(); |
| auto& buffer4 = MessageBuffer<SendSlotB>::GetBuffer(); |
| |
| EXPECT_EQ(buffer1.data(), buffer2.data()); |
| EXPECT_EQ(buffer3.data(), buffer4.data()); |
| EXPECT_NE(buffer1.data(), buffer3.data()); |
| EXPECT_NE(buffer2.data(), buffer4.data()); |
| } |