194 TIBase::ResetStatesGuard rsg{
true};
197 BEAST_EXPECT(b.use_count() == 1);
199 BEAST_EXPECT(b.use_count() == 1);
200 auto s = b.releaseStrongRef();
202 BEAST_EXPECT(b.use_count() == 0);
206 auto w = b.releaseWeakRef();
213 TIBase::ResetStatesGuard rsg{
true};
215 using enum TrackedState;
216 auto b = make_SharedIntrusive<TIBase>();
218 BEAST_EXPECT(TIBase::getState(
id) == alive);
219 BEAST_EXPECT(b->use_count() == 1);
220 for (
int i = 0; i < 10; ++i)
225 BEAST_EXPECT(TIBase::getState(
id) == alive);
227 BEAST_EXPECT(TIBase::getState(
id) == alive);
229 BEAST_EXPECT(TIBase::getState(
id) == deleted);
231 b = make_SharedIntrusive<TIBase>();
233 BEAST_EXPECT(TIBase::getState(
id) == alive);
234 BEAST_EXPECT(b->use_count() == 1);
235 for (
int i = 0; i < 10; ++i)
238 BEAST_EXPECT(b->use_count() == 1);
240 BEAST_EXPECT(TIBase::getState(
id) == alive);
242 BEAST_EXPECT(TIBase::getState(
id) == alive);
244 BEAST_EXPECT(TIBase::getState(
id) == partiallyDeleted);
245 while (!weak.
empty())
249 BEAST_EXPECT(TIBase::getState(
id) == partiallyDeleted);
251 BEAST_EXPECT(TIBase::getState(
id) == deleted);
254 TIBase::ResetStatesGuard rsg{
true};
256 using enum TrackedState;
257 auto b = make_SharedIntrusive<TIBase>();
259 BEAST_EXPECT(TIBase::getState(
id) == alive);
261 BEAST_EXPECT(TIBase::getState(
id) == alive);
263 BEAST_EXPECT(s && s->use_count() == 2);
265 BEAST_EXPECT(TIBase::getState(
id) == alive);
266 BEAST_EXPECT(s && s->use_count() == 1);
268 BEAST_EXPECT(TIBase::getState(
id) == partiallyDeleted);
269 BEAST_EXPECT(w.expired());
275 BEAST_EXPECT(TIBase::getState(
id) == deleted);
278 TIBase::ResetStatesGuard rsg{
true};
280 using enum TrackedState;
282 swu b = make_SharedIntrusive<TIBase>();
283 BEAST_EXPECT(b.isStrong() && b.use_count() == 1);
284 auto id = b.get()->id_;
285 BEAST_EXPECT(TIBase::getState(
id) == alive);
287 BEAST_EXPECT(TIBase::getState(
id) == alive);
288 BEAST_EXPECT(w.isStrong() && b.use_count() == 2);
290 BEAST_EXPECT(w.isWeak() && b.use_count() == 1);
292 BEAST_EXPECT(s.isWeak() && b.use_count() == 1);
294 BEAST_EXPECT(s.isStrong() && b.use_count() == 2);
296 BEAST_EXPECT(TIBase::getState(
id) == alive);
297 BEAST_EXPECT(s.use_count() == 1);
298 BEAST_EXPECT(!w.expired());
300 BEAST_EXPECT(TIBase::getState(
id) == partiallyDeleted);
301 BEAST_EXPECT(w.expired());
305 BEAST_EXPECT(w.isWeak());
307 BEAST_EXPECT(TIBase::getState(
id) == deleted);
312 TIBase::ResetStatesGuard rsg{
true};
314 auto strong1 = make_SharedIntrusive<TIBase>();
315 auto strong2 = make_SharedIntrusive<TIBase>();
317 auto id1 = strong1->id_;
318 auto id2 = strong2->id_;
320 BEAST_EXPECT(id1 != id2);
327 BEAST_EXPECT(union1.
get() == strong1.get());
328 BEAST_EXPECT(union2.
get() == strong2.get());
334 BEAST_EXPECT(union1.
get() == union2.
get());
335 BEAST_EXPECT(TIBase::getState(id1) == TrackedState::alive);
336 BEAST_EXPECT(TIBase::getState(id2) == TrackedState::alive);
340 BEAST_EXPECT(TIBase::getState(id1) == TrackedState::alive);
341 int initialRefCount = strong1->use_count();
342#pragma clang diagnostic push
343#pragma clang diagnostic ignored "-Wself-assign-overloaded"
345#pragma clang diagnostic pop
347 BEAST_EXPECT(TIBase::getState(id1) == TrackedState::alive);
348 BEAST_EXPECT(strong1->use_count() == initialRefCount);
352 BEAST_EXPECT(union1.
get() ==
nullptr);
358 BEAST_EXPECT(union1.
get() ==
nullptr);
359 BEAST_EXPECT(TIBase::getState(id2) == TrackedState::deleted);
375 using enum TrackedState;
377 TIBase::ResetStatesGuard rsg{
true};
379 auto strong = make_SharedIntrusive<TIBase>();
381 bool destructorRan =
false;
382 bool partialDeleteRan =
false;
385 using enum TrackedState;
386 if (next == deletedStarted)
393 BEAST_EXPECT(cur == partiallyDeleted);
395 if (next == partiallyDeletedStarted)
397 partialDeleteStartedSyncPoint.arrive_and_wait();
398 using namespace std::chrono_literals;
404 if (next == partiallyDeleted)
406 BEAST_EXPECT(!partialDeleteRan && !destructorRan);
407 partialDeleteRan =
true;
411 BEAST_EXPECT(!destructorRan);
412 destructorRan =
true;
416 partialDeleteStartedSyncPoint.arrive_and_wait();
426 BEAST_EXPECT(destructorRan && partialDeleteRan);
442 using enum TrackedState;
444 TIBase::ResetStatesGuard rsg{
true};
446 auto strong = make_SharedIntrusive<TIBase>();
448 bool destructorRan =
false;
449 bool partialDeleteRan =
false;
452 using enum TrackedState;
453 if (next == partiallyDeleted)
455 BEAST_EXPECT(!partialDeleteRan && !destructorRan);
456 partialDeleteRan =
true;
460 BEAST_EXPECT(!destructorRan);
461 destructorRan =
true;
466 weakResetSyncPoint.arrive_and_wait();
469 weakResetSyncPoint.arrive_and_wait();
475 BEAST_EXPECT(destructorRan && !partialDeleteRan);
481 testcase(
"Multithreaded Clear Mixed Variant");
488 using enum TrackedState;
489 TIBase::ResetStatesGuard rsg{
true};
495 return {(s & 1) != 0, (s & 2) != 0};
500 using enum TrackedState;
501 auto [destructorRan, partialDeleteRan] = getDestructorState();
502 if (next == partiallyDeleted)
504 BEAST_EXPECT(!partialDeleteRan && !destructorRan);
505 setPartialDeleteRan();
509 BEAST_EXPECT(!destructorRan);
518 auto numToCreate = toCreateDist(eng);
520 for (
int i = 0; i < numToCreate; ++i)
522 if (isStrongDist(eng))
533 constexpr int loopIters = 2 * 1024;
534 constexpr int numThreads = 16;
536 Barrier loopStartSyncPoint{numThreads};
537 Barrier postCreateToCloneSyncPoint{numThreads};
538 Barrier postCreateVecOfPointersSyncPoint{numThreads};
543 for (
int i = 0; i < numThreads; ++i)
551 auto cloneAndDestroy = [&](
int threadId) {
552 for (
int i = 0; i < loopIters; ++i)
555 loopStartSyncPoint.arrive_and_wait();
567 auto [destructorRan, partialDeleteRan] = getDestructorState();
568 BEAST_EXPECT(!i || destructorRan);
572 toClone.
resize(numThreads);
573 auto strong = make_SharedIntrusive<TIBase>();
574 strong->tracingCallback_ = tracingCallback;
579 postCreateToCloneSyncPoint.arrive_and_wait();
581 auto v = createVecOfPointers(toClone[threadId], engines[threadId]);
582 toClone[threadId].reset();
585 postCreateVecOfPointersSyncPoint.arrive_and_wait();
591 for (
int i = 0; i < numThreads; ++i)
595 for (
int i = 0; i < numThreads; ++i)
604 testcase(
"Multithreaded Clear Mixed Union");
616 using enum TrackedState;
618 TIBase::ResetStatesGuard rsg{
true};
624 return {(s & 1) != 0, (s & 2) != 0};
629 using enum TrackedState;
630 auto [destructorRan, partialDeleteRan] = getDestructorState();
631 if (next == partiallyDeleted)
633 BEAST_EXPECT(!partialDeleteRan && !destructorRan);
634 setPartialDeleteRan();
638 BEAST_EXPECT(!destructorRan);
642 auto createVecOfPointers = [&](
auto const& toClone,
646 auto numToCreate = toCreateDist(eng);
648 for (
int i = 0; i < numToCreate; ++i)
652 constexpr int loopIters = 2 * 1024;
653 constexpr int flipPointersLoopIters = 256;
654 constexpr int numThreads = 16;
656 Barrier loopStartSyncPoint{numThreads};
657 Barrier postCreateToCloneSyncPoint{numThreads};
658 Barrier postCreateVecOfPointersSyncPoint{numThreads};
659 Barrier postFlipPointersLoopSyncPoint{numThreads};
664 for (
int i = 0; i < numThreads; ++i)
673 auto cloneAndDestroy = [&](
int threadId) {
674 for (
int i = 0; i < loopIters; ++i)
677 loopStartSyncPoint.arrive_and_wait();
688 auto [destructorRan, partialDeleteRan] = getDestructorState();
689 BEAST_EXPECT(!i || destructorRan);
693 toClone.
resize(numThreads);
694 auto strong = make_SharedIntrusive<TIBase>();
695 strong->tracingCallback_ = tracingCallback;
700 postCreateToCloneSyncPoint.arrive_and_wait();
702 auto v = createVecOfPointers(toClone[threadId], engines[threadId]);
703 toClone[threadId].reset();
706 postCreateVecOfPointersSyncPoint.arrive_and_wait();
709 for (
int f = 0; f < flipPointersLoopIters; ++f)
713 if (isStrongDist(engines[threadId]))
725 postFlipPointersLoopSyncPoint.arrive_and_wait();
731 for (
int i = 0; i < numThreads; ++i)
735 for (
int i = 0; i < numThreads; ++i)
744 testcase(
"Multithreaded Locking Weak");
751 using enum TrackedState;
753 TIBase::ResetStatesGuard rsg{
true};
759 return {(s & 1) != 0, (s & 2) != 0};
764 using enum TrackedState;
765 auto [destructorRan, partialDeleteRan] = getDestructorState();
766 if (next == partiallyDeleted)
768 BEAST_EXPECT(!partialDeleteRan && !destructorRan);
769 setPartialDeleteRan();
773 BEAST_EXPECT(!destructorRan);
778 constexpr int loopIters = 2 * 1024;
779 constexpr int lockWeakLoopIters = 256;
780 constexpr int numThreads = 16;
782 Barrier loopStartSyncPoint{numThreads};
783 Barrier postCreateToLockSyncPoint{numThreads};
784 Barrier postLockWeakLoopSyncPoint{numThreads};
789 auto lockAndDestroy = [&](
int threadId) {
790 for (
int i = 0; i < loopIters; ++i)
804 auto [destructorRan, partialDeleteRan] = getDestructorState();
805 BEAST_EXPECT(!i || destructorRan);
809 toLock.
resize(numThreads);
810 auto strong = make_SharedIntrusive<TIBase>();
811 strong->tracingCallback_ = tracingCallback;
816 postCreateToLockSyncPoint.arrive_and_wait();
821 for (
int wi = 0; wi < lockWeakLoopIters; ++wi)
823 BEAST_EXPECT(!weak.expired());
824 auto strong = weak.lock();
825 BEAST_EXPECT(strong);
829 postLockWeakLoopSyncPoint.arrive_and_wait();
831 toLock[threadId].reset();
835 for (
int i = 0; i < numThreads; ++i)
839 for (
int i = 0; i < numThreads; ++i)