1 #include <memory> 2 #include <string> 3 #include <thread> 4 #include <utility> 5 6 #include <gtest/gtest.h> 7 #include <pdx/rpc/message_buffer.h> 8 9 namespace android { 10 namespace pdx { 11 namespace rpc { 12 13 class ThreadLocalBufferTest { 14 public: 15 // Returns the unique address of the thread-local buffer. Used to test the 16 // correct behavior of the type-based thread local storage slot mapping 17 // mechanism. 18 template <typename Slot> 19 static std::uintptr_t GetSlotAddress() { 20 return reinterpret_cast<std::uintptr_t>(&MessageBuffer<Slot>::buffer_); 21 } 22 23 // Returns the raw value of the thread local buffer. Used to test the behavior 24 // of backing buffer initialization. 25 template <typename Slot> 26 static std::uintptr_t GetSlotValue() { 27 return reinterpret_cast<std::uintptr_t>(MessageBuffer<Slot>::buffer_); 28 } 29 }; 30 31 } // namespace rpc 32 } // namespace pdx 33 } // namespace android 34 35 using namespace android::pdx::rpc; 36 37 namespace { 38 39 struct TypeTagA; 40 struct TypeTagB; 41 42 constexpr std::size_t kSendBufferIndex = 0; 43 constexpr std::size_t kReceiveBufferIndex = 1; 44 45 using SendSlotA = ThreadLocalSlot<TypeTagA, kSendBufferIndex>; 46 using SendSlotB = ThreadLocalSlot<TypeTagB, kSendBufferIndex>; 47 using ReceiveSlotA = ThreadLocalSlot<TypeTagA, kReceiveBufferIndex>; 48 using ReceiveSlotB = ThreadLocalSlot<TypeTagB, kReceiveBufferIndex>; 49 50 } // anonymous namespace 51 52 // Tests that index and type-based thread-local slot addressing works by 53 // checking that the slot address is the same when the same index/type 54 // combination is used and different when different combinations are used. 55 TEST(ThreadLocalBufferTest, TypeSlots) { 56 auto id1 = ThreadLocalBufferTest::GetSlotAddress<SendSlotA>(); 57 auto id2 = ThreadLocalBufferTest::GetSlotAddress<ReceiveSlotA>(); 58 auto id3 = ThreadLocalBufferTest::GetSlotAddress<SendSlotB>(); 59 auto id4 = ThreadLocalBufferTest::GetSlotAddress<ReceiveSlotB>(); 60 61 EXPECT_NE(id1, id2); 62 EXPECT_NE(id3, id4); 63 EXPECT_NE(id1, id3); 64 EXPECT_NE(id2, id4); 65 66 auto id1_alias = ThreadLocalBufferTest::GetSlotAddress<SendSlotA>(); 67 auto id2_alias = ThreadLocalBufferTest::GetSlotAddress<ReceiveSlotA>(); 68 auto id3_alias = ThreadLocalBufferTest::GetSlotAddress<SendSlotB>(); 69 auto id4_alias = ThreadLocalBufferTest::GetSlotAddress<ReceiveSlotB>(); 70 71 EXPECT_EQ(id1, id1_alias); 72 EXPECT_EQ(id2, id2_alias); 73 EXPECT_EQ(id3, id3_alias); 74 EXPECT_EQ(id4, id4_alias); 75 } 76 77 // Tests that different threads get different buffers for the same slot address. 78 TEST(ThreadLocalBufferTest, ThreadSlots) { 79 auto id1 = ThreadLocalBufferTest::GetSlotAddress<SendBuffer>(); 80 std::uintptr_t id2 = 0U; 81 82 std::thread thread([&id2]() mutable { 83 id2 = ThreadLocalBufferTest::GetSlotAddress<SendBuffer>(); 84 }); 85 thread.join(); 86 87 EXPECT_NE(0U, id1); 88 EXPECT_NE(0U, id2); 89 EXPECT_NE(id1, id2); 90 } 91 92 // Tests that thread-local buffers are allocated at the first buffer request. 93 TEST(ThreadLocalBufferTest, InitialValue) { 94 struct TypeTagX; 95 using SendSlotX = ThreadLocalSlot<TypeTagX, kSendBufferIndex>; 96 97 auto value1 = ThreadLocalBufferTest::GetSlotValue<SendSlotX>(); 98 MessageBuffer<SendSlotX>::GetBuffer(); 99 auto value2 = ThreadLocalBufferTest::GetSlotValue<SendSlotX>(); 100 101 EXPECT_EQ(0U, value1); 102 EXPECT_NE(0U, value2); 103 } 104 105 // Tests that the underlying buffers are the same for a given index/type pair 106 // and different across index/type combinations. 107 TEST(ThreadLocalBufferTest, BackingBuffer) { 108 auto& buffer1 = MessageBuffer<SendSlotA>::GetBuffer(); 109 auto& buffer2 = MessageBuffer<SendSlotA>::GetBuffer(); 110 auto& buffer3 = MessageBuffer<SendSlotB>::GetBuffer(); 111 auto& buffer4 = MessageBuffer<SendSlotB>::GetBuffer(); 112 113 EXPECT_EQ(buffer1.data(), buffer2.data()); 114 EXPECT_EQ(buffer3.data(), buffer4.data()); 115 EXPECT_NE(buffer1.data(), buffer3.data()); 116 EXPECT_NE(buffer2.data(), buffer4.data()); 117 } 118