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