199 TIBase::ResetStatesGuard
const rsg{
true};
202 BEAST_EXPECT(b.useCount() == 1);
204 BEAST_EXPECT(b.useCount() == 1);
205 auto s = b.releaseStrongRef();
207 BEAST_EXPECT(b.useCount() == 0);
208 TIBase
const* pb = &b;
211 auto w = b.releaseWeakRef();
218 TIBase::ResetStatesGuard
const rsg{
true};
220 using enum TrackedState;
223 BEAST_EXPECT(TIBase::getState(
id) == Alive);
224 BEAST_EXPECT(b->useCount() == 1);
225 for (
int i = 0; i < 10; ++i)
230 BEAST_EXPECT(TIBase::getState(
id) == Alive);
232 BEAST_EXPECT(TIBase::getState(
id) == Alive);
234 BEAST_EXPECT(TIBase::getState(
id) == Deleted);
238 BEAST_EXPECT(TIBase::getState(
id) == Alive);
239 BEAST_EXPECT(b->useCount() == 1);
240 for (
int i = 0; i < 10; ++i)
243 BEAST_EXPECT(b->useCount() == 1);
245 BEAST_EXPECT(TIBase::getState(
id) == Alive);
247 BEAST_EXPECT(TIBase::getState(
id) == Alive);
249 BEAST_EXPECT(TIBase::getState(
id) == PartiallyDeleted);
250 while (!weak.
empty())
254 BEAST_EXPECT(TIBase::getState(
id) == PartiallyDeleted);
256 BEAST_EXPECT(TIBase::getState(
id) == Deleted);
259 TIBase::ResetStatesGuard
const rsg{
true};
261 using enum TrackedState;
264 BEAST_EXPECT(TIBase::getState(
id) == Alive);
266 BEAST_EXPECT(TIBase::getState(
id) == Alive);
268 BEAST_EXPECT(s && s->useCount() == 2);
270 BEAST_EXPECT(TIBase::getState(
id) == Alive);
271 BEAST_EXPECT(s && s->useCount() == 1);
273 BEAST_EXPECT(TIBase::getState(
id) == PartiallyDeleted);
280 BEAST_EXPECT(TIBase::getState(
id) == Deleted);
283 TIBase::ResetStatesGuard
const rsg{
true};
285 using enum TrackedState;
288 BEAST_EXPECT(b.isStrong() && b.useCount() == 1);
289 auto id = b.get()->id;
290 BEAST_EXPECT(TIBase::getState(
id) == Alive);
292 BEAST_EXPECT(TIBase::getState(
id) == Alive);
293 BEAST_EXPECT(w.isStrong() && b.useCount() == 2);
295 BEAST_EXPECT(w.isWeak() && b.useCount() == 1);
297 BEAST_EXPECT(s.isWeak() && b.useCount() == 1);
299 BEAST_EXPECT(s.isStrong() && b.useCount() == 2);
301 BEAST_EXPECT(TIBase::getState(
id) == Alive);
302 BEAST_EXPECT(s.useCount() == 1);
303 BEAST_EXPECT(!w.expired());
305 BEAST_EXPECT(TIBase::getState(
id) == PartiallyDeleted);
306 BEAST_EXPECT(w.expired());
310 BEAST_EXPECT(w.isWeak());
312 BEAST_EXPECT(TIBase::getState(
id) == Deleted);
317 TIBase::ResetStatesGuard
const rsg{
true};
322 auto id1 = strong1->id;
323 auto id2 = strong2->id;
325 BEAST_EXPECT(id1 != id2);
332 BEAST_EXPECT(union1.
get() == strong1.get());
333 BEAST_EXPECT(union2.
get() == strong2.get());
339 BEAST_EXPECT(union1.
get() == union2.
get());
340 BEAST_EXPECT(TIBase::getState(id1) == TrackedState::Alive);
341 BEAST_EXPECT(TIBase::getState(id2) == TrackedState::Alive);
345 BEAST_EXPECT(TIBase::getState(id1) == TrackedState::Alive);
346 int const initialRefCount = strong1->useCount();
347#pragma clang diagnostic push
348#pragma clang diagnostic ignored "-Wself-assign-overloaded"
350#pragma clang diagnostic pop
352 BEAST_EXPECT(TIBase::getState(id1) == TrackedState::Alive);
353 BEAST_EXPECT(strong1->useCount() == initialRefCount);
357 BEAST_EXPECT(union1.
get() ==
nullptr);
363 BEAST_EXPECT(union1.
get() ==
nullptr);
364 BEAST_EXPECT(TIBase::getState(id2) == TrackedState::Deleted);
380 using enum TrackedState;
382 TIBase::ResetStatesGuard
const rsg{
true};
386 bool destructorRan =
false;
387 bool partialDeleteRan =
false;
390 using enum TrackedState;
391 if (next == DeletedStarted)
398 BEAST_EXPECT(cur == PartiallyDeleted);
400 if (next == PartiallyDeletedStarted)
403 using namespace std::chrono_literals;
409 if (next == PartiallyDeleted)
411 BEAST_EXPECT(!partialDeleteRan && !destructorRan);
412 partialDeleteRan =
true;
416 BEAST_EXPECT(!destructorRan);
417 destructorRan =
true;
431 BEAST_EXPECT(destructorRan && partialDeleteRan);
486 testcase(
"Multithreaded Clear Mixed Variant");
493 using enum TrackedState;
494 TIBase::ResetStatesGuard
const rsg{
true};
499 int const s = destructionState.
load(std::memory_order_relaxed);
500 return {(s & 1) != 0, (s & 2) != 0};
502 auto setDestructorRan = [&]() ->
void {
503 destructionState.
fetch_or(1, std::memory_order_acq_rel);
505 auto setPartialDeleteRan = [&]() ->
void {
506 destructionState.
fetch_or(2, std::memory_order_acq_rel);
509 using enum TrackedState;
510 auto [destructorRan, partialDeleteRan] = getDestructorState();
511 if (next == PartiallyDeleted)
513 BEAST_EXPECT(!partialDeleteRan && !destructorRan);
514 setPartialDeleteRan();
518 BEAST_EXPECT(!destructorRan);
527 auto numToCreate = toCreateDist(eng);
529 for (
int i = 0; i < numToCreate; ++i)
531 if (isStrongDist(eng))
542 static constexpr int kLoopIters = 2 * 1024;
543 static constexpr int kNumThreads = 16;
545 Barrier loopStartSyncPoint{kNumThreads};
546 Barrier postCreateToCloneSyncPoint{kNumThreads};
547 Barrier postCreateVecOfPointersSyncPoint{kNumThreads};
552 for (
int i = 0; i < kNumThreads; ++i)
560 auto cloneAndDestroy = [&](
int threadId) {
561 for (
int i = 0; i < kLoopIters; ++i)
576 auto [destructorRan, partialDeleteRan] = getDestructorState();
577 BEAST_EXPECT(!i || destructorRan);
578 destructionState.
store(0, std::memory_order_release);
581 toClone.
resize(kNumThreads);
583 strong->tracingCallback = tracingCallback;
590 auto v = createVecOfPointers(toClone[threadId], engines[threadId]);
591 toClone[threadId].reset();
601 for (
int i = 0; i < kNumThreads; ++i)
605 for (
int i = 0; i < kNumThreads; ++i)
614 testcase(
"Multithreaded Clear Mixed Union");
626 using enum TrackedState;
628 TIBase::ResetStatesGuard
const rsg{
true};
633 int const s = destructionState.
load(std::memory_order_relaxed);
634 return {(s & 1) != 0, (s & 2) != 0};
636 auto setDestructorRan = [&]() ->
void {
637 destructionState.
fetch_or(1, std::memory_order_acq_rel);
639 auto setPartialDeleteRan = [&]() ->
void {
640 destructionState.
fetch_or(2, std::memory_order_acq_rel);
643 using enum TrackedState;
644 auto [destructorRan, partialDeleteRan] = getDestructorState();
645 if (next == PartiallyDeleted)
647 BEAST_EXPECT(!partialDeleteRan && !destructorRan);
648 setPartialDeleteRan();
652 BEAST_EXPECT(!destructorRan);
656 auto createVecOfPointers =
657 [&](
auto const& toClone,
661 auto numToCreate = toCreateDist(eng);
663 for (
int i = 0; i < numToCreate; ++i)
667 static constexpr int kLoopIters = 2 * 1024;
668 static constexpr int kFlipPointersLoopIters = 256;
669 static constexpr int kNumThreads = 16;
671 Barrier loopStartSyncPoint{kNumThreads};
672 Barrier postCreateToCloneSyncPoint{kNumThreads};
673 Barrier postCreateVecOfPointersSyncPoint{kNumThreads};
674 Barrier postFlipPointersLoopSyncPoint{kNumThreads};
679 for (
int i = 0; i < kNumThreads; ++i)
688 auto cloneAndDestroy = [&](
int threadId) {
689 for (
int i = 0; i < kLoopIters; ++i)
703 auto [destructorRan, partialDeleteRan] = getDestructorState();
704 BEAST_EXPECT(!i || destructorRan);
705 destructionState.
store(0, std::memory_order_release);
708 toClone.
resize(kNumThreads);
710 strong->tracingCallback = tracingCallback;
717 auto v = createVecOfPointers(toClone[threadId], engines[threadId]);
718 toClone[threadId].reset();
724 for (
int f = 0; f < kFlipPointersLoopIters; ++f)
728 if (isStrongDist(engines[threadId]))
747 for (
int i = 0; i < kNumThreads; ++i)
751 for (
int i = 0; i < kNumThreads; ++i)
760 testcase(
"Multithreaded Locking Weak");
767 using enum TrackedState;
769 TIBase::ResetStatesGuard
const rsg{
true};
774 int const s = destructionState.
load(std::memory_order_relaxed);
775 return {(s & 1) != 0, (s & 2) != 0};
777 auto setDestructorRan = [&]() ->
void {
778 destructionState.
fetch_or(1, std::memory_order_acq_rel);
780 auto setPartialDeleteRan = [&]() ->
void {
781 destructionState.
fetch_or(2, std::memory_order_acq_rel);
784 using enum TrackedState;
785 auto [destructorRan, partialDeleteRan] = getDestructorState();
786 if (next == PartiallyDeleted)
788 BEAST_EXPECT(!partialDeleteRan && !destructorRan);
789 setPartialDeleteRan();
793 BEAST_EXPECT(!destructorRan);
798 static constexpr int kLoopIters = 2 * 1024;
799 static constexpr int kLockWeakLoopIters = 256;
800 static constexpr int kNumThreads = 16;
802 Barrier loopStartSyncPoint{kNumThreads};
803 Barrier postCreateToLockSyncPoint{kNumThreads};
804 Barrier postLockWeakLoopSyncPoint{kNumThreads};
809 auto lockAndDestroy = [&](
int threadId) {
810 for (
int i = 0; i < kLoopIters; ++i)
824 auto [destructorRan, partialDeleteRan] = getDestructorState();
825 BEAST_EXPECT(!i || destructorRan);
826 destructionState.
store(0, std::memory_order_release);
829 toLock.
resize(kNumThreads);
831 strong->tracingCallback = tracingCallback;
841 for (
int wi = 0; wi < kLockWeakLoopIters; ++wi)
844 auto strong = weak.
lock();
845 BEAST_EXPECT(strong);
851 toLock[threadId].reset();
856 for (
int i = 0; i < kNumThreads; ++i)
860 for (
int i = 0; i < kNumThreads; ++i)