118 lines
3.7 KiB
C++
118 lines
3.7 KiB
C++
|
#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());
|
||
|
}
|