1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 #include "pw_bluetooth_sapphire/internal/host/transport/slab_allocators.h"
16
17 #include <forward_list>
18 #include <list>
19
20 #include "pw_bluetooth_sapphire/internal/host/transport/acl_data_packet.h"
21 #include "pw_bluetooth_sapphire/internal/host/transport/control_packets.h"
22 #include "pw_unit_test/framework.h"
23
24 namespace bt::hci::allocators {
25 namespace {
26
27 constexpr hci_spec::OpCode kTestOpCode = 0xFFFF;
28
TEST(SlabAllocatorsTest,CommandPacket)29 TEST(SlabAllocatorsTest, CommandPacket) {
30 auto packet = CommandPacket::New(kTestOpCode, 5);
31 EXPECT_TRUE(packet);
32 EXPECT_EQ(5u + sizeof(hci_spec::CommandHeader), packet->view().size());
33
34 packet = CommandPacket::New(kTestOpCode, kSmallControlPayloadSize);
35 EXPECT_TRUE(packet);
36 EXPECT_GE(packet->view().size(), kSmallControlPacketSize);
37
38 packet = CommandPacket::New(kTestOpCode, kSmallControlPayloadSize + 1);
39 EXPECT_TRUE(packet);
40 EXPECT_EQ(kSmallControlPacketSize + 1, packet->view().size());
41 }
42
TEST(SlabAllocatorsTest,CommandPacketFallBack)43 TEST(SlabAllocatorsTest, CommandPacketFallBack) {
44 // Maximum number of packets we can expect to obtain from all the slab
45 // allocators.
46 const size_t kMaxSlabPackets = kMaxNumSlabs * kNumSmallControlPackets +
47 kMaxNumSlabs * kNumLargeControlPackets;
48
49 std::list<std::unique_ptr<hci::CommandPacket>> packets;
50 for (size_t num_packets = 0; num_packets < kMaxSlabPackets; num_packets++) {
51 auto packet = CommandPacket::New(kTestOpCode, 5);
52 packets.push_front(std::move(packet));
53 }
54
55 // Command allocator can fall back on system allocator after slabs are
56 // exhausted.
57 auto packet = CommandPacket::New(kTestOpCode, 5);
58 ASSERT_TRUE(packet);
59 }
60
TEST(SlabAllocatorsTest,ACLDataPacket)61 TEST(SlabAllocatorsTest, ACLDataPacket) {
62 auto packet = ACLDataPacket::New(5);
63 EXPECT_TRUE(packet);
64 EXPECT_EQ(packet->view().size(), 5u + sizeof(hci_spec::ACLDataHeader));
65
66 packet = ACLDataPacket::New(kSmallACLDataPayloadSize);
67 EXPECT_TRUE(packet);
68 EXPECT_EQ(kSmallACLDataPacketSize, packet->view().size());
69
70 packet = ACLDataPacket::New(kSmallACLDataPayloadSize + 1);
71 EXPECT_TRUE(packet);
72 EXPECT_EQ(kSmallACLDataPacketSize + 1, packet->view().size());
73
74 packet = ACLDataPacket::New(kMediumACLDataPayloadSize + 1);
75 EXPECT_EQ(kMediumACLDataPacketSize + 1, packet->view().size());
76 }
77
TEST(SlabAllocatorsTest,ACLDataPacketFallBack)78 TEST(SlabAllocatorsTest, ACLDataPacketFallBack) {
79 // Maximum number of packets we can expect to obtain from all the slab
80 // allocators.
81 const size_t kMaxSlabPackets = kMaxNumSlabs * kNumSmallACLDataPackets +
82 kMaxNumSlabs * kNumMediumACLDataPackets +
83 kMaxNumSlabs * kNumLargeACLDataPackets;
84 const size_t kPayloadSize = 5;
85 std::list<hci::ACLDataPacketPtr> packets;
86
87 for (size_t num_packets = 0; num_packets < kMaxSlabPackets; num_packets++) {
88 auto packet = ACLDataPacket::New(kPayloadSize);
89 EXPECT_TRUE(packet);
90 packets.push_front(std::move(packet));
91 }
92
93 // ACL allocator can fall back on system allocator after slabs are exhausted.
94 auto packet = ACLDataPacket::New(kPayloadSize);
95 ASSERT_TRUE(packet);
96
97 // Fallback-allocated packet should still function as expected.
98 EXPECT_EQ(sizeof(hci_spec::ACLDataHeader) + kPayloadSize,
99 packet->view().size());
100
101 // Write over the whole allocation (errors to be caught by sanitizer
102 // instrumentation).
103 packet->mutable_view()->mutable_data().Fill('m');
104 }
105
TEST(SlabAllocatorsTest,LargeACLDataPacketFallback)106 TEST(SlabAllocatorsTest, LargeACLDataPacketFallback) {
107 // Maximum number of packets we can expect to obtain from the large slab
108 // allocator.
109 const size_t kMaxSlabPackets = kMaxNumSlabs * kNumLargeACLDataPackets;
110 const size_t kPayloadSize = kLargeACLDataPayloadSize;
111 std::list<hci::ACLDataPacketPtr> packets;
112
113 for (size_t num_packets = 0; num_packets < kMaxSlabPackets; num_packets++) {
114 auto packet = ACLDataPacket::New(kPayloadSize);
115 EXPECT_TRUE(packet);
116 packets.push_front(std::move(packet));
117 }
118
119 // ACL allocator can fall back on system allocator after slabs are exhausted.
120 auto packet = ACLDataPacket::New(kPayloadSize);
121 ASSERT_TRUE(packet);
122
123 // Fallback-allocated packet should still function as expected.
124 EXPECT_EQ(sizeof(hci_spec::ACLDataHeader) + kPayloadSize,
125 packet->view().size());
126
127 // Write over the whole allocation (errors to be caught by sanitizer
128 // instrumentation).
129 packet->mutable_view()->mutable_data().Fill('m');
130 }
131
132 } // namespace
133 } // namespace bt::hci::allocators
134