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>
GetSlotAddress()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>
GetSlotValue()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.
TEST(ThreadLocalBufferTest,TypeSlots)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.
TEST(ThreadLocalBufferTest,ThreadSlots)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.
TEST(ThreadLocalBufferTest,InitialValue)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.
TEST(ThreadLocalBufferTest,BackingBuffer)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