1// Copyright 2016 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <fbl/alloc_checker.h> 6#include <fbl/intrusive_double_list.h> 7#include <fbl/ref_counted.h> 8#include <fbl/ref_ptr.h> 9#include <fbl/slab_allocator.h> 10#include <fbl/unique_ptr.h> 11#include <unittest/unittest.h> 12 13namespace { 14 15enum class ConstructType { 16 DEFAULT, 17 LVALUE_REF, 18 RVALUE_REF, 19 L_THEN_R_REF, 20}; 21 22// Test objects. 23class TestBase { 24public: 25 // Various constructor forms to exercise SlabAllocator::New 26 TestBase() : ctype_(ConstructType::DEFAULT) { ++allocated_obj_count_; } 27 explicit TestBase(const size_t&) : ctype_(ConstructType::LVALUE_REF) { ++allocated_obj_count_; } 28 explicit TestBase(size_t&&) : ctype_(ConstructType::RVALUE_REF) { ++allocated_obj_count_; } 29 explicit TestBase(const size_t&, size_t&&) 30 : ctype_(ConstructType::L_THEN_R_REF) { 31 ++allocated_obj_count_; 32 } 33 34 virtual ~TestBase() { --allocated_obj_count_; } 35 36 ConstructType ctype() const { return ctype_; } 37 38 static void Reset() { allocated_obj_count_ = 0; } 39 static size_t allocated_obj_count() { return allocated_obj_count_; } 40 const uint8_t* payload() const { return payload_; } 41 42private: 43 const ConstructType ctype_; 44 uint8_t payload_[13]; // 13 bytes, just to make the size/alignment strange 45 46 static size_t allocated_obj_count_; 47}; 48 49// Static storage. 50size_t TestBase::allocated_obj_count_; 51 52template <typename SATraits, typename = void> struct ReleaseHelper; 53 54template <typename SATraits> 55struct ReleaseHelper<SATraits, typename fbl::enable_if< 56 (SATraits::PtrTraits::IsManaged == false) && 57 (SATraits::AllocatorFlavor == fbl::SlabAllocatorFlavor::INSTANCED) 58 >::type> { 59 static void ReleasePtr(fbl::SlabAllocator<SATraits>& allocator, 60 typename SATraits::PtrType& ptr) { 61 // Instanced slab allocators should static_assert if you attempt to 62 // expand their delete method. 63#if TEST_WILL_NOT_COMPILE || 0 64 allocator.Delete(ptr); 65#else 66 delete ptr; 67#endif 68 } 69}; 70 71template <typename SATraits> 72struct ReleaseHelper<SATraits, typename fbl::enable_if< 73 (SATraits::PtrTraits::IsManaged == false) && 74 (SATraits::AllocatorFlavor == fbl::SlabAllocatorFlavor::MANUAL_DELETE) 75 >::type> { 76 static void ReleasePtr(fbl::SlabAllocator<SATraits>& allocator, 77 typename SATraits::PtrType& ptr) { 78 // SlabAllocated<> objects which come from MANUAL_DELETE flavors of slab 79 // allocators should have their delete operator protected in order to 80 // prevent someone from calling delete on the object. 81#if TEST_WILL_NOT_COMPILE || 0 82 delete ptr; 83#else 84 allocator.Delete(ptr); 85#endif 86 } 87}; 88 89template <typename SATraits> 90struct ReleaseHelper<SATraits, typename fbl::enable_if< 91 (SATraits::PtrTraits::IsManaged == true) && 92 (SATraits::AllocatorFlavor != fbl::SlabAllocatorFlavor::STATIC) 93 >::type> { 94 static void ReleasePtr(fbl::SlabAllocator<SATraits>&, typename SATraits::PtrType& ptr) { 95 ptr = nullptr; 96 } 97}; 98 99template <typename SATraits> 100struct ReleaseHelper<SATraits, typename fbl::enable_if< 101 (SATraits::PtrTraits::IsManaged == false) && 102 (SATraits::AllocatorFlavor == fbl::SlabAllocatorFlavor::STATIC) 103 >::type> { 104 static void ReleasePtr(typename SATraits::PtrType& ptr) { 105 delete ptr; 106 } 107}; 108 109template <typename SATraits> 110struct ReleaseHelper<SATraits, typename fbl::enable_if< 111 (SATraits::PtrTraits::IsManaged == true) && 112 (SATraits::AllocatorFlavor == fbl::SlabAllocatorFlavor::STATIC) 113 >::type> { 114 static void ReleasePtr(typename SATraits::PtrType& ptr) { 115 ptr = nullptr; 116 } 117}; 118 119// Traits which define the various test flavors. 120template <typename LockType, 121 fbl::SlabAllocatorFlavor AllocatorFlavor = fbl::SlabAllocatorFlavor::INSTANCED, 122 bool ENABLE_OBJ_COUNT = false> 123struct UnmanagedTestTraits { 124 class ObjType; 125 using PtrType = ObjType*; 126 using AllocTraits = fbl::SlabAllocatorTraits 127 <PtrType, 1024, LockType, AllocatorFlavor, ENABLE_OBJ_COUNT>; 128 using AllocatorType = fbl::SlabAllocator<AllocTraits>; 129 using RefList = fbl::DoublyLinkedList<PtrType>; 130 131 class ObjType : public TestBase, 132 public fbl::SlabAllocated<AllocTraits>, 133 public fbl::DoublyLinkedListable<PtrType> { 134 public: 135 ObjType() : TestBase() { } 136 explicit ObjType(const size_t& val) : TestBase(val) { } 137 explicit ObjType(size_t&& val) : TestBase(fbl::move(val)) { } 138 explicit ObjType(const size_t& a, size_t&& b) : TestBase(a, fbl::move(b)) { } 139 }; 140 141 static constexpr size_t MaxSlabs = 4; 142 static constexpr bool IsManaged = false; 143 static constexpr size_t MaxAllocs(size_t slabs) { return AllocatorType::AllocsPerSlab * slabs; } 144}; 145 146template <typename LockType, bool ENABLE_OBJ_COUNT = false> 147struct UniquePtrTestTraits { 148 class ObjType; 149 using PtrType = fbl::unique_ptr<ObjType>; 150 using AllocTraits = fbl::SlabAllocatorTraits 151 <PtrType, 1024, LockType, fbl::SlabAllocatorFlavor::INSTANCED, ENABLE_OBJ_COUNT>; 152 using AllocatorType = fbl::SlabAllocator<AllocTraits>; 153 using RefList = fbl::DoublyLinkedList<PtrType>; 154 155 class ObjType : public TestBase, 156 public fbl::SlabAllocated<AllocTraits>, 157 public fbl::DoublyLinkedListable<PtrType> { 158 public: 159 ObjType() : TestBase() { } 160 explicit ObjType(const size_t& val) : TestBase(val) { } 161 explicit ObjType(size_t&& val) : TestBase(fbl::move(val)) { } 162 explicit ObjType(const size_t& a, size_t&& b) : TestBase(a, fbl::move(b)) { } 163 }; 164 165 166 static constexpr size_t MaxSlabs = 4; 167 static constexpr bool IsManaged = true; 168 static constexpr size_t MaxAllocs(size_t slabs) { return AllocatorType::AllocsPerSlab * slabs; } 169}; 170 171template <typename LockType, bool ENABLE_OBJ_COUNT = false> 172struct RefPtrTestTraits { 173 class ObjType; 174 using PtrType = fbl::RefPtr<ObjType>; 175 using AllocTraits = fbl::SlabAllocatorTraits 176 <PtrType, 1024,LockType, fbl::SlabAllocatorFlavor::INSTANCED, ENABLE_OBJ_COUNT>; 177 using AllocatorType = fbl::SlabAllocator<AllocTraits>; 178 using RefList = fbl::DoublyLinkedList<PtrType>; 179 180 class ObjType : public TestBase, 181 public fbl::RefCounted<ObjType>, 182 public fbl::SlabAllocated<AllocTraits>, 183 public fbl::DoublyLinkedListable<PtrType> { 184 public: 185 ObjType() : TestBase() { } 186 explicit ObjType(const size_t& val) : TestBase(val) { } 187 explicit ObjType(size_t&& val) : TestBase(fbl::move(val)) { } 188 explicit ObjType(const size_t& a, size_t&& b) : TestBase(a, fbl::move(b)) { } 189 }; 190 191 static constexpr size_t MaxSlabs = 4; 192 static constexpr bool IsManaged = true; 193 static constexpr size_t MaxAllocs(size_t slabs) { return AllocatorType::AllocsPerSlab * slabs; } 194}; 195 196template <typename, bool> struct ObjCounterHelper; 197 198template <typename SA> struct ObjCounterHelper<SA, true> { 199 static bool CheckObjCount(const SA& allocator, size_t expected) { 200 return (allocator.obj_count() == expected); 201 } 202 static bool CheckMaxObjCount(const SA& allocator, size_t expected) { 203 return (allocator.max_obj_count() == expected); 204 } 205 static void ResetMaxObjCount(SA* allocator) { 206 allocator->ResetMaxObjCount(); 207 } 208 static bool StaticCheckObjCount(size_t expected) { 209 return (SA::obj_count() == expected); 210 } 211 static bool StaticCheckMaxObjCount(size_t expected) { 212 return (SA::max_obj_count() == expected); 213 } 214 static void StaticResetMaxObjCount() { 215 SA::ResetMaxObjCount(); 216 } 217}; 218 219template <typename SA> struct ObjCounterHelper<SA, false> { 220 static bool CheckObjCount(const SA&, size_t) { 221 return true; 222 } 223 static bool CheckMaxObjCount(const SA&, size_t) { 224 return true; 225 } 226 static void ResetMaxObjCount(SA*) {} 227 static bool StaticCheckObjCount(size_t) { 228 return true; 229 } 230 static bool StaticCheckMaxObjCount(size_t) { 231 return true; 232 } 233 static void StaticResetMaxObjCount() {} 234}; 235 236template <typename Traits> 237bool do_slab_test(typename Traits::AllocatorType& allocator, size_t test_allocs) { 238 BEGIN_TEST; 239 240 const size_t MAX_ALLOCS = Traits::MaxAllocs(allocator.max_slabs()); 241 typename Traits::RefList ref_list; 242 const bool ENB_OBJ_COUNT = Traits::AllocTraits::ENABLE_OBJ_COUNT; 243 using AllocatorType = typename Traits::AllocatorType; 244 245 ObjCounterHelper<AllocatorType, ENB_OBJ_COUNT>::ResetMaxObjCount(&allocator); 246 bool res = ObjCounterHelper<AllocatorType, ENB_OBJ_COUNT>::CheckObjCount(allocator, 0); 247 EXPECT_TRUE(res); 248 res = ObjCounterHelper<AllocatorType, ENB_OBJ_COUNT>::CheckMaxObjCount(allocator, 0); 249 EXPECT_TRUE(res); 250 251 // Allocate up to the test limit. 252 for (size_t i = 0; i < test_allocs; ++i) { 253 typename Traits::PtrType ptr; 254 255 EXPECT_EQ(fbl::min(i, MAX_ALLOCS), TestBase::allocated_obj_count()); 256 res = ObjCounterHelper<AllocatorType, ENB_OBJ_COUNT>::CheckObjCount 257 (allocator,TestBase::allocated_obj_count()); 258 EXPECT_TRUE(res); 259 res = ObjCounterHelper<AllocatorType, ENB_OBJ_COUNT>::CheckMaxObjCount 260 (allocator, TestBase::allocated_obj_count()); 261 EXPECT_TRUE(res); 262 263 // Allocate the object; exercise the various constructors 264 switch (i % 4) { 265 case 0: ptr = allocator.New(); break; 266 case 1: ptr = allocator.New(i); break; 267 case 2: ptr = allocator.New(fbl::move(i)); break; 268 case 3: ptr = allocator.New(i, fbl::move(i)); break; 269 } 270 271 if (i < MAX_ALLOCS) { 272 ASSERT_NONNULL(ptr, "Allocation failed when it should not have!"); 273 ref_list.push_front(fbl::move(ptr)); 274 } else { 275 ASSERT_NULL(ptr, "Allocation succeeded when it should not have!"); 276 } 277 278 EXPECT_EQ(fbl::min(i + 1, MAX_ALLOCS), TestBase::allocated_obj_count()); 279 res = ObjCounterHelper<AllocatorType, ENB_OBJ_COUNT>::CheckObjCount 280 (allocator, TestBase::allocated_obj_count()); 281 EXPECT_TRUE(res); 282 res = ObjCounterHelper<AllocatorType, ENB_OBJ_COUNT>::CheckMaxObjCount 283 (allocator, TestBase::allocated_obj_count()); 284 EXPECT_TRUE(res); 285 } 286 287 // Now remove and de-allocate. 288 size_t max_obj_count = TestBase::allocated_obj_count(); 289 size_t i; 290 for (i = 0; !ref_list.is_empty(); ++i) { 291 auto ptr = ref_list.pop_back(); 292 293 ASSERT_NONNULL(ptr, "nullptr in ref list! This should be impossible."); 294 EXPECT_EQ(fbl::min(test_allocs, MAX_ALLOCS) - i, TestBase::allocated_obj_count()); 295 res = ObjCounterHelper<AllocatorType, ENB_OBJ_COUNT>::CheckObjCount 296 (allocator, TestBase::allocated_obj_count()); 297 EXPECT_TRUE(res); 298 res = ObjCounterHelper<AllocatorType, ENB_OBJ_COUNT>::CheckMaxObjCount 299 (allocator, max_obj_count); 300 EXPECT_TRUE(res); 301 302 switch (i % 4) { 303 case 0: 304 EXPECT_EQ(ConstructType::DEFAULT, ptr->ctype()); 305 break; 306 case 1: 307 EXPECT_EQ(ConstructType::LVALUE_REF, ptr->ctype()); 308 break; 309 case 2: 310 EXPECT_EQ(ConstructType::RVALUE_REF, ptr->ctype()); 311 break; 312 case 3: 313 EXPECT_EQ(ConstructType::L_THEN_R_REF, ptr->ctype()); 314 break; 315 } 316 317 // Release the reference (how this gets done depends on allocator flavor and pointer type) 318 ReleaseHelper<typename Traits::AllocTraits>::ReleasePtr(allocator, ptr); 319 320 if (i % 2 == 1) { 321 ObjCounterHelper<AllocatorType, ENB_OBJ_COUNT>::ResetMaxObjCount(&allocator); 322 max_obj_count = TestBase::allocated_obj_count(); 323 } 324 res = ObjCounterHelper<AllocatorType, ENB_OBJ_COUNT>::CheckMaxObjCount 325 (allocator, max_obj_count); 326 EXPECT_TRUE(res); 327 } 328 329 EXPECT_EQ(fbl::min(test_allocs, MAX_ALLOCS), i); 330 res = ObjCounterHelper<AllocatorType, ENB_OBJ_COUNT>::CheckObjCount 331 (allocator, 0); 332 EXPECT_TRUE(res); 333 res = ObjCounterHelper<AllocatorType, ENB_OBJ_COUNT>::CheckMaxObjCount 334 (allocator, i % 2); 335 EXPECT_TRUE(res); 336 ObjCounterHelper<AllocatorType, ENB_OBJ_COUNT>::ResetMaxObjCount(&allocator); 337 res = ObjCounterHelper<AllocatorType, ENB_OBJ_COUNT>::CheckMaxObjCount 338 (allocator, 0); 339 EXPECT_TRUE(res); 340 341#if TEST_WILL_NOT_COMPILE || 0 342 allocator.obj_count(); 343#endif 344#if TEST_WILL_NOT_COMPILE || 0 345 allocator.max_obj_count(); 346#endif 347#if TEST_WILL_NOT_COMPILE || 0 348 allocator.ResetMaxObjCount(); 349#endif 350 END_TEST; 351} 352 353template <typename Traits, size_t SlabCount = Traits::MaxSlabs> 354bool slab_test() { 355 BEGIN_TEST; 356 typename Traits::AllocatorType allocator(SlabCount); 357 358 TestBase::Reset(); 359 360 EXPECT_TRUE(do_slab_test<Traits>(allocator, 1), 361 "Single allocator test failed"); 362 363 EXPECT_TRUE(do_slab_test<Traits>(allocator, Traits::MaxAllocs(SlabCount) / 2), 364 "1/2 capacity allocator test failed"); 365 366 EXPECT_TRUE(do_slab_test<Traits>(allocator, Traits::MaxAllocs(SlabCount) + 4), 367 "Over-capacity allocator test failed"); 368 369 END_TEST; 370} 371 372template <typename LockType, bool ENABLE_OBJ_COUNT = false> 373struct StaticUnmanagedTestTraits { 374 class ObjType; 375 using PtrType = ObjType*; 376 using AllocTraits = fbl::StaticSlabAllocatorTraits<PtrType, 1024, LockType, ENABLE_OBJ_COUNT>; 377 using AllocatorType = fbl::SlabAllocator<AllocTraits>; 378 using RefList = fbl::DoublyLinkedList<PtrType>; 379 380 class ObjType : public TestBase, 381 public fbl::SlabAllocated<AllocTraits>, 382 public fbl::DoublyLinkedListable<PtrType> { 383 public: 384 ObjType() : TestBase() { } 385 explicit ObjType(const size_t& val) : TestBase(val) { } 386 explicit ObjType(size_t&& val) : TestBase(fbl::move(val)) { } 387 explicit ObjType(const size_t& a, size_t&& b) : TestBase(a, fbl::move(b)) { } 388 }; 389 390 static size_t MaxAllocs() { return AllocatorType::AllocsPerSlab * AllocatorType::max_slabs(); } 391 392 static constexpr size_t MaxSlabs = 4; 393 static constexpr bool IsManaged = false; 394}; 395template <typename LockType> 396using StaticCountedUnmanagedTestTraits = StaticUnmanagedTestTraits<LockType, true>; 397 398template <typename LockType, bool ENABLE_OBJ_COUNT = false> 399struct StaticUniquePtrTestTraits { 400 class ObjType; 401 using PtrType = fbl::unique_ptr<ObjType>; 402 using AllocTraits = fbl::StaticSlabAllocatorTraits<PtrType, 1024, LockType, ENABLE_OBJ_COUNT>; 403 using AllocatorType = fbl::SlabAllocator<AllocTraits>; 404 using RefList = fbl::DoublyLinkedList<PtrType>; 405 406 class ObjType : public TestBase, 407 public fbl::SlabAllocated<AllocTraits>, 408 public fbl::DoublyLinkedListable<PtrType> { 409 public: 410 ObjType() : TestBase() { } 411 explicit ObjType(const size_t& val) : TestBase(val) { } 412 explicit ObjType(size_t&& val) : TestBase(fbl::move(val)) { } 413 explicit ObjType(const size_t& a, size_t&& b) : TestBase(a, fbl::move(b)) { } 414 }; 415 416 static size_t MaxAllocs() { return AllocatorType::AllocsPerSlab * AllocatorType::max_slabs(); } 417 418 static constexpr size_t MaxSlabs = 4; 419 static constexpr bool IsManaged = false; 420}; 421 422template <typename LockType> 423using StaticCountedUniquePtrTestTraits = StaticUniquePtrTestTraits<LockType, true>; 424 425template <typename LockType, bool ENABLE_OBJ_COUNT = false> 426struct StaticRefPtrTestTraits { 427 class ObjType; 428 using PtrType = fbl::RefPtr<ObjType>; 429 using AllocTraits = fbl::StaticSlabAllocatorTraits<PtrType, 1024, LockType, ENABLE_OBJ_COUNT>; 430 using AllocatorType = fbl::SlabAllocator<AllocTraits>; 431 using RefList = fbl::DoublyLinkedList<PtrType>; 432 433 class ObjType : public TestBase, 434 public fbl::SlabAllocated<AllocTraits>, 435 public fbl::RefCounted<ObjType>, 436 public fbl::DoublyLinkedListable<PtrType> { 437 public: 438 ObjType() : TestBase() { } 439 explicit ObjType(const size_t& val) : TestBase(val) { } 440 explicit ObjType(size_t&& val) : TestBase(fbl::move(val)) { } 441 explicit ObjType(const size_t& a, size_t&& b) : TestBase(a, fbl::move(b)) { } 442 }; 443 444 static constexpr size_t MaxSlabs = 4; 445 static constexpr bool IsManaged = false; 446 447 static size_t MaxAllocs() { 448 return AllocatorType::AllocsPerSlab * AllocatorType::max_slabs(); 449 } 450}; 451 452template <typename LockType> 453using StaticCountedRefPtrTestTraits = StaticRefPtrTestTraits<LockType, true>; 454 455template <typename Traits> 456bool do_static_slab_test(size_t test_allocs) { 457 BEGIN_TEST; 458 459 const bool ENB_OBJ_COUNT = Traits::AllocTraits::ENABLE_OBJ_COUNT; 460 using AllocatorType = typename Traits::AllocatorType; 461 462 const size_t MAX_ALLOCS = Traits::MaxAllocs(); 463 typename Traits::RefList ref_list; 464 ObjCounterHelper<AllocatorType, ENB_OBJ_COUNT>::StaticResetMaxObjCount(); 465 bool res = ObjCounterHelper<AllocatorType, ENB_OBJ_COUNT>::StaticCheckObjCount(0); 466 EXPECT_TRUE(res); 467 res = ObjCounterHelper<AllocatorType, ENB_OBJ_COUNT>::StaticCheckMaxObjCount(0); 468 EXPECT_TRUE(res); 469 470 // Allocate up to the test limit. 471 for (size_t i = 0; i < test_allocs; ++i) { 472 typename Traits::PtrType ptr; 473 474 EXPECT_EQ(fbl::min(i, MAX_ALLOCS), TestBase::allocated_obj_count()); 475 res = ObjCounterHelper<AllocatorType, ENB_OBJ_COUNT>::StaticCheckObjCount 476 (TestBase::allocated_obj_count()); 477 EXPECT_TRUE(res); 478 res = ObjCounterHelper<AllocatorType, ENB_OBJ_COUNT>::StaticCheckMaxObjCount 479 (TestBase::allocated_obj_count()); 480 EXPECT_TRUE(res); 481 482 // Allocate the object; exercise the various constructors 483 switch (i % 4) { 484 case 0: ptr = AllocatorType::New(); break; 485 case 1: ptr = AllocatorType::New(i); break; 486 case 2: ptr = AllocatorType::New(fbl::move(i)); break; 487 case 3: ptr = AllocatorType::New(i, fbl::move(i)); break; 488 } 489 490 if (i < MAX_ALLOCS) { 491 ASSERT_NONNULL(ptr, "Allocation failed when it should not have!"); 492 ref_list.push_front(fbl::move(ptr)); 493 } else { 494 ASSERT_NULL(ptr, "Allocation succeeded when it should not have!"); 495 } 496 497 EXPECT_EQ(fbl::min(i + 1, MAX_ALLOCS), TestBase::allocated_obj_count()); 498 res = ObjCounterHelper<AllocatorType, ENB_OBJ_COUNT>::StaticCheckObjCount 499 (TestBase::allocated_obj_count()); 500 EXPECT_TRUE(res); 501 res = ObjCounterHelper<AllocatorType, ENB_OBJ_COUNT>::StaticCheckMaxObjCount 502 (TestBase::allocated_obj_count()); 503 EXPECT_TRUE(res); 504 } 505 506 // Now remove and de-allocate. 507 size_t max_obj_count = TestBase::allocated_obj_count(); 508 size_t i; 509 for (i = 0; !ref_list.is_empty(); ++i) { 510 auto ptr = ref_list.pop_back(); 511 512 ASSERT_NONNULL(ptr, "nullptr in ref list! This should be impossible."); 513 EXPECT_EQ(fbl::min(test_allocs, MAX_ALLOCS) - i, TestBase::allocated_obj_count()); 514 res = ObjCounterHelper<AllocatorType, ENB_OBJ_COUNT>::StaticCheckObjCount 515 (TestBase::allocated_obj_count()); 516 EXPECT_TRUE(res); 517 res = ObjCounterHelper<AllocatorType, ENB_OBJ_COUNT>::StaticCheckMaxObjCount(max_obj_count); 518 EXPECT_TRUE(res); 519 520 switch (i % 4) { 521 case 0: 522 EXPECT_EQ(ConstructType::DEFAULT, ptr->ctype()); 523 break; 524 case 1: 525 EXPECT_EQ(ConstructType::LVALUE_REF, ptr->ctype()); 526 break; 527 case 2: 528 EXPECT_EQ(ConstructType::RVALUE_REF, ptr->ctype()); 529 break; 530 case 3: 531 EXPECT_EQ(ConstructType::L_THEN_R_REF, ptr->ctype()); 532 break; 533 } 534 535 // Release the reference (how this gets done depends on allocator flavor and pointer type) 536 ReleaseHelper<typename Traits::AllocTraits>::ReleasePtr(ptr); 537 if (i % 2 == 1) { 538 ObjCounterHelper<AllocatorType, 539 ENB_OBJ_COUNT>::StaticResetMaxObjCount(); 540 max_obj_count = TestBase::allocated_obj_count(); 541 } 542 res = ObjCounterHelper<AllocatorType, ENB_OBJ_COUNT>::StaticCheckMaxObjCount(max_obj_count); 543 EXPECT_TRUE(res); 544 } 545 546 EXPECT_EQ(fbl::min(test_allocs, MAX_ALLOCS), i); 547 res = ObjCounterHelper<AllocatorType, ENB_OBJ_COUNT>::StaticCheckObjCount(0); 548 EXPECT_TRUE(res); 549 res = ObjCounterHelper<AllocatorType, ENB_OBJ_COUNT>::StaticCheckMaxObjCount(i % 2); 550 EXPECT_TRUE(res); 551 ObjCounterHelper<AllocatorType, ENB_OBJ_COUNT>::StaticResetMaxObjCount(); 552 res = ObjCounterHelper<AllocatorType, ENB_OBJ_COUNT>::StaticCheckMaxObjCount(0); 553 EXPECT_TRUE(res); 554#if TEST_WILL_NOT_COMPILE || 0 555 AllocatorType::obj_count(); 556#endif 557#if TEST_WILL_NOT_COMPILE || 0 558 AllocatorType::max_obj_count(); 559#endif 560#if TEST_WILL_NOT_COMPILE || 0 561 AllocatorType::ResetMaxObjCount(); 562#endif 563 564 END_TEST; 565} 566 567 568template <typename Traits> 569bool static_slab_test() { 570 BEGIN_TEST; 571 572 TestBase::Reset(); 573 574 EXPECT_TRUE(do_static_slab_test<Traits>(1), 575 "Single allocator test failed"); 576 577 EXPECT_TRUE(do_static_slab_test<Traits>(Traits::MaxAllocs() / 2), 578 "1/2 capacity allocator test failed"); 579 580 EXPECT_TRUE(do_static_slab_test<Traits>(Traits::MaxAllocs() + 4), 581 "Over-capacity allocator test failed"); 582 583 END_TEST; 584} 585} // anon namespace 586 587using MutexLock = ::fbl::Mutex; 588using NullLock = ::fbl::NullLock; 589 590DECLARE_STATIC_SLAB_ALLOCATOR_STORAGE(StaticUnmanagedTestTraits<MutexLock>::AllocTraits, 1); 591DECLARE_STATIC_SLAB_ALLOCATOR_STORAGE(StaticUniquePtrTestTraits<MutexLock>::AllocTraits, 1); 592DECLARE_STATIC_SLAB_ALLOCATOR_STORAGE(StaticRefPtrTestTraits<MutexLock>::AllocTraits, 1); 593 594DECLARE_STATIC_SLAB_ALLOCATOR_STORAGE(StaticUnmanagedTestTraits<NullLock>::AllocTraits, 1); 595DECLARE_STATIC_SLAB_ALLOCATOR_STORAGE(StaticUniquePtrTestTraits<NullLock>::AllocTraits, 1); 596DECLARE_STATIC_SLAB_ALLOCATOR_STORAGE(StaticRefPtrTestTraits<NullLock>::AllocTraits, 1); 597 598DECLARE_STATIC_SLAB_ALLOCATOR_STORAGE(StaticCountedUnmanagedTestTraits<MutexLock>::AllocTraits, 1); 599DECLARE_STATIC_SLAB_ALLOCATOR_STORAGE(StaticCountedUniquePtrTestTraits<MutexLock>::AllocTraits, 1); 600DECLARE_STATIC_SLAB_ALLOCATOR_STORAGE(StaticCountedRefPtrTestTraits<MutexLock>::AllocTraits, 1); 601 602DECLARE_STATIC_SLAB_ALLOCATOR_STORAGE(StaticCountedUnmanagedTestTraits<NullLock>::AllocTraits, 1); 603DECLARE_STATIC_SLAB_ALLOCATOR_STORAGE(StaticCountedUniquePtrTestTraits<NullLock>::AllocTraits, 1); 604DECLARE_STATIC_SLAB_ALLOCATOR_STORAGE(StaticCountedRefPtrTestTraits<NullLock>::AllocTraits, 1); 605 606BEGIN_TEST_CASE(slab_allocator_tests) 607RUN_NAMED_TEST("Unmanaged Single Slab (mutex)", (slab_test<UnmanagedTestTraits<MutexLock>, 1>)) 608RUN_NAMED_TEST("Unmanaged Multi Slab (mutex)", (slab_test<UnmanagedTestTraits<MutexLock>>)) 609RUN_NAMED_TEST("UniquePtr Single Slab (mutex)", (slab_test<UniquePtrTestTraits<MutexLock>, 1>)) 610RUN_NAMED_TEST("UniquePtr Multi Slab (mutex)", (slab_test<UniquePtrTestTraits<MutexLock>>)) 611RUN_NAMED_TEST("RefPtr Single Slab (mutex)", (slab_test<RefPtrTestTraits<MutexLock>, 1>)) 612RUN_NAMED_TEST("RefPtr Multi Slab (mutex)", (slab_test<RefPtrTestTraits<MutexLock>>)) 613 614RUN_NAMED_TEST("Unmanaged Single Slab (unlock)", (slab_test<UnmanagedTestTraits<NullLock>, 1>)) 615RUN_NAMED_TEST("Unmanaged Multi Slab (unlock)", (slab_test<UnmanagedTestTraits<NullLock>>)) 616RUN_NAMED_TEST("UniquePtr Single Slab (unlock)", (slab_test<UniquePtrTestTraits<NullLock>, 1>)) 617RUN_NAMED_TEST("UniquePtr Multi Slab (unlock)", (slab_test<UniquePtrTestTraits<NullLock>>)) 618RUN_NAMED_TEST("RefPtr Single Slab (unlock)", (slab_test<RefPtrTestTraits<NullLock>, 1>)) 619RUN_NAMED_TEST("RefPtr Multi Slab (unlock)", (slab_test<RefPtrTestTraits<NullLock>>)) 620 621RUN_NAMED_TEST("Manual Delete Unmanaged (mutex)", 622 (slab_test<UnmanagedTestTraits<MutexLock, fbl::SlabAllocatorFlavor::MANUAL_DELETE>>)) 623RUN_NAMED_TEST("Manual Delete Unmanaged (unlock)", 624 (slab_test<UnmanagedTestTraits<NullLock, fbl::SlabAllocatorFlavor::MANUAL_DELETE>>)) 625 626RUN_NAMED_TEST("Static Unmanaged (unlock)", (static_slab_test<StaticUnmanagedTestTraits<NullLock>>)) 627RUN_NAMED_TEST("Static UniquePtr (unlock)", (static_slab_test<StaticUniquePtrTestTraits<NullLock>>)) 628RUN_NAMED_TEST("Static RefPtr (unlock)", (static_slab_test<StaticRefPtrTestTraits<NullLock>>)) 629 630RUN_NAMED_TEST("Static Unmanaged (mutex)", (static_slab_test<StaticUnmanagedTestTraits<MutexLock>>)) 631RUN_NAMED_TEST("Static UniquePtr (mutex)", (static_slab_test<StaticUniquePtrTestTraits<MutexLock>>)) 632RUN_NAMED_TEST("Static RefPtr (mutex)", (static_slab_test<StaticRefPtrTestTraits<MutexLock>>)) 633 634RUN_NAMED_TEST("Static Unmanaged (unlock)", (static_slab_test<StaticUnmanagedTestTraits<NullLock>>)) 635RUN_NAMED_TEST("Static UniquePtr (unlock)", (static_slab_test<StaticUniquePtrTestTraits<NullLock>>)) 636RUN_NAMED_TEST("Static RefPtr (unlock)", (static_slab_test<StaticRefPtrTestTraits<NullLock>>)) 637 638RUN_NAMED_TEST("Counted Unmanaged Single Slab (mutex)",(slab_test 639 <UnmanagedTestTraits<MutexLock, fbl::SlabAllocatorFlavor::INSTANCED, true>, 1>)) 640RUN_NAMED_TEST("Counted Unmanaged Multi Slab (mutex)", (slab_test 641 <UnmanagedTestTraits<MutexLock, fbl::SlabAllocatorFlavor::INSTANCED, true>>)) 642RUN_NAMED_TEST("Counted UniquePtr Single Slab (mutex)", (slab_test 643 <UniquePtrTestTraits<MutexLock, true>, 1>)) 644RUN_NAMED_TEST("Counted UniquePtr Multi Slab (mutex)", (slab_test 645 <UniquePtrTestTraits<MutexLock, true>>)) 646RUN_NAMED_TEST("Counted RefPtr Single Slab (mutex)", (slab_test 647 <RefPtrTestTraits<MutexLock, true>, 1>)) 648RUN_NAMED_TEST("Counted RefPtr Multi Slab (mutex)", (slab_test 649 <RefPtrTestTraits<MutexLock, true>>)) 650 651RUN_NAMED_TEST("Counted Unmanaged Single Slab (unlock)", (slab_test 652 <UnmanagedTestTraits<NullLock, fbl::SlabAllocatorFlavor::INSTANCED, true>, 1>)) 653RUN_NAMED_TEST("Counted Unmanaged Multi Slab (unlock)", (slab_test 654 <UnmanagedTestTraits<NullLock, fbl::SlabAllocatorFlavor::INSTANCED, true>>)) 655RUN_NAMED_TEST("Counted UniquePtr Single Slab (unlock)", (slab_test 656 <UniquePtrTestTraits<NullLock, true>, 1>)) 657RUN_NAMED_TEST("Counted UniquePtr Multi Slab (unlock)", (slab_test 658 <UniquePtrTestTraits<NullLock, true>>)) 659RUN_NAMED_TEST("Counted RefPtr Single Slab (unlock)", (slab_test 660 <RefPtrTestTraits<NullLock, true>, 1>)) 661RUN_NAMED_TEST("Counted RefPtr Multi Slab (unlock)", (slab_test 662 <RefPtrTestTraits<NullLock, true>>)) 663 664RUN_NAMED_TEST("Counted Manual Delete Unmanaged (mutex)", (slab_test 665 <UnmanagedTestTraits<MutexLock, fbl::SlabAllocatorFlavor::MANUAL_DELETE, true>>)) 666RUN_NAMED_TEST("Counted Manual Delete Unmanaged (unlock)", (slab_test 667 <UnmanagedTestTraits<NullLock, fbl::SlabAllocatorFlavor::MANUAL_DELETE, true>>)) 668 669RUN_NAMED_TEST("Counted Static Unmanaged (unlock)", (static_slab_test 670 <StaticUnmanagedTestTraits<NullLock, true>>)) 671RUN_NAMED_TEST("Counted Static UniquePtr (unlock)", (static_slab_test 672 <StaticUniquePtrTestTraits<NullLock, true>>)) 673RUN_NAMED_TEST("Counted Static RefPtr (unlock)", (static_slab_test 674 <StaticRefPtrTestTraits<NullLock, true>>)) 675 676RUN_NAMED_TEST("Counted Static Unmanaged (mutex)", (static_slab_test 677 <StaticUnmanagedTestTraits<MutexLock, true>>)) 678RUN_NAMED_TEST("Counted Static UniquePtr (mutex)", (static_slab_test 679 <StaticUniquePtrTestTraits<MutexLock, true>>)) 680RUN_NAMED_TEST("Counted Static RefPtr (mutex)", (static_slab_test 681 <StaticRefPtrTestTraits<MutexLock, true>>)) 682 683RUN_NAMED_TEST("Counted Static Unmanaged (unlock)", (static_slab_test 684 <StaticUnmanagedTestTraits<NullLock, true>>)) 685RUN_NAMED_TEST("Counted Static UniquePtr (unlock)", (static_slab_test 686 <StaticUniquePtrTestTraits<NullLock, true>>)) 687RUN_NAMED_TEST("Counted Static RefPtr (unlock)", (static_slab_test 688 <StaticRefPtrTestTraits<NullLock, true>>)) 689END_TEST_CASE(slab_allocator_tests); 690