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 9namespace android { 10namespace pdx { 11namespace rpc { 12 13class 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 35using namespace android::pdx::rpc; 36 37namespace { 38 39struct TypeTagA; 40struct TypeTagB; 41 42constexpr std::size_t kSendBufferIndex = 0; 43constexpr std::size_t kReceiveBufferIndex = 1; 44 45using SendSlotA = ThreadLocalSlot<TypeTagA, kSendBufferIndex>; 46using SendSlotB = ThreadLocalSlot<TypeTagB, kSendBufferIndex>; 47using ReceiveSlotA = ThreadLocalSlot<TypeTagA, kReceiveBufferIndex>; 48using 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. 55TEST(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. 78TEST(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. 93TEST(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. 107TEST(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