blob: 6cdaf1071a2599e98c6f236e7b1ede71d46e20d2 [file] [log] [blame]
#include <memory>
#include <string>
#include <thread>
#include <utility>
#include <gtest/gtest.h>
#include <pdx/rpc/message_buffer.h>
namespace android {
namespace pdx {
namespace rpc {
class ThreadLocalBufferTest {
public:
// Returns the unique address of the thread-local buffer. Used to test the
// correct behavior of the type-based thread local storage slot mapping
// mechanism.
template <typename Slot>
static std::uintptr_t GetSlotAddress() {
return reinterpret_cast<std::uintptr_t>(&MessageBuffer<Slot>::buffer_);
}
// Returns the raw value of the thread local buffer. Used to test the behavior
// of backing buffer initialization.
template <typename Slot>
static std::uintptr_t GetSlotValue() {
return reinterpret_cast<std::uintptr_t>(MessageBuffer<Slot>::buffer_);
}
};
} // namespace rpc
} // namespace pdx
} // namespace android
using namespace android::pdx::rpc;
namespace {
struct TypeTagA;
struct TypeTagB;
constexpr std::size_t kSendBufferIndex = 0;
constexpr std::size_t kReceiveBufferIndex = 1;
using SendSlotA = ThreadLocalSlot<TypeTagA, kSendBufferIndex>;
using SendSlotB = ThreadLocalSlot<TypeTagB, kSendBufferIndex>;
using ReceiveSlotA = ThreadLocalSlot<TypeTagA, kReceiveBufferIndex>;
using ReceiveSlotB = ThreadLocalSlot<TypeTagB, kReceiveBufferIndex>;
} // anonymous namespace
// Tests that index and type-based thread-local slot addressing works by
// checking that the slot address is the same when the same index/type
// combination is used and different when different combinations are used.
TEST(ThreadLocalBufferTest, TypeSlots) {
auto id1 = ThreadLocalBufferTest::GetSlotAddress<SendSlotA>();
auto id2 = ThreadLocalBufferTest::GetSlotAddress<ReceiveSlotA>();
auto id3 = ThreadLocalBufferTest::GetSlotAddress<SendSlotB>();
auto id4 = ThreadLocalBufferTest::GetSlotAddress<ReceiveSlotB>();
EXPECT_NE(id1, id2);
EXPECT_NE(id3, id4);
EXPECT_NE(id1, id3);
EXPECT_NE(id2, id4);
auto id1_alias = ThreadLocalBufferTest::GetSlotAddress<SendSlotA>();
auto id2_alias = ThreadLocalBufferTest::GetSlotAddress<ReceiveSlotA>();
auto id3_alias = ThreadLocalBufferTest::GetSlotAddress<SendSlotB>();
auto id4_alias = ThreadLocalBufferTest::GetSlotAddress<ReceiveSlotB>();
EXPECT_EQ(id1, id1_alias);
EXPECT_EQ(id2, id2_alias);
EXPECT_EQ(id3, id3_alias);
EXPECT_EQ(id4, id4_alias);
}
// Tests that different threads get different buffers for the same slot address.
TEST(ThreadLocalBufferTest, ThreadSlots) {
auto id1 = ThreadLocalBufferTest::GetSlotAddress<SendBuffer>();
std::uintptr_t id2 = 0U;
std::thread thread([&id2]() mutable {
id2 = ThreadLocalBufferTest::GetSlotAddress<SendBuffer>();
});
thread.join();
EXPECT_NE(0U, id1);
EXPECT_NE(0U, id2);
EXPECT_NE(id1, id2);
}
// Tests that thread-local buffers are allocated at the first buffer request.
TEST(ThreadLocalBufferTest, InitialValue) {
struct TypeTagX;
using SendSlotX = ThreadLocalSlot<TypeTagX, kSendBufferIndex>;
auto value1 = ThreadLocalBufferTest::GetSlotValue<SendSlotX>();
MessageBuffer<SendSlotX>::GetBuffer();
auto value2 = ThreadLocalBufferTest::GetSlotValue<SendSlotX>();
EXPECT_EQ(0U, value1);
EXPECT_NE(0U, value2);
}
// Tests that the underlying buffers are the same for a given index/type pair
// and different across index/type combinations.
TEST(ThreadLocalBufferTest, BackingBuffer) {
auto& buffer1 = MessageBuffer<SendSlotA>::GetBuffer();
auto& buffer2 = MessageBuffer<SendSlotA>::GetBuffer();
auto& buffer3 = MessageBuffer<SendSlotB>::GetBuffer();
auto& buffer4 = MessageBuffer<SendSlotB>::GetBuffer();
EXPECT_EQ(buffer1.data(), buffer2.data());
EXPECT_EQ(buffer3.data(), buffer4.data());
EXPECT_NE(buffer1.data(), buffer3.data());
EXPECT_NE(buffer2.data(), buffer4.data());
}