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