200 TIBase::ResetStatesGuard rsg{
true};
203 BEAST_EXPECT(b.use_count() == 1);
205 BEAST_EXPECT(b.use_count() == 1);
206 auto s = b.releaseStrongRef();
208 BEAST_EXPECT(b.use_count() == 0);
212 auto w = b.releaseWeakRef();
219 TIBase::ResetStatesGuard rsg{
true};
221 using enum TrackedState;
222 auto b = make_SharedIntrusive<TIBase>();
224 BEAST_EXPECT(TIBase::getState(
id) == alive);
225 BEAST_EXPECT(b->use_count() == 1);
226 for (
int i = 0; i < 10; ++i)
231 BEAST_EXPECT(TIBase::getState(
id) == alive);
233 BEAST_EXPECT(TIBase::getState(
id) == alive);
235 BEAST_EXPECT(TIBase::getState(
id) == deleted);
237 b = make_SharedIntrusive<TIBase>();
239 BEAST_EXPECT(TIBase::getState(
id) == alive);
240 BEAST_EXPECT(b->use_count() == 1);
241 for (
int i = 0; i < 10; ++i)
244 BEAST_EXPECT(b->use_count() == 1);
246 BEAST_EXPECT(TIBase::getState(
id) == alive);
248 BEAST_EXPECT(TIBase::getState(
id) == alive);
250 BEAST_EXPECT(TIBase::getState(
id) == partiallyDeleted);
251 while (!weak.
empty())
255 BEAST_EXPECT(TIBase::getState(
id) == partiallyDeleted);
257 BEAST_EXPECT(TIBase::getState(
id) == deleted);
260 TIBase::ResetStatesGuard rsg{
true};
262 using enum TrackedState;
263 auto b = make_SharedIntrusive<TIBase>();
265 BEAST_EXPECT(TIBase::getState(
id) == alive);
267 BEAST_EXPECT(TIBase::getState(
id) == alive);
269 BEAST_EXPECT(s && s->use_count() == 2);
271 BEAST_EXPECT(TIBase::getState(
id) == alive);
272 BEAST_EXPECT(s && s->use_count() == 1);
274 BEAST_EXPECT(TIBase::getState(
id) == partiallyDeleted);
275 BEAST_EXPECT(w.expired());
281 BEAST_EXPECT(TIBase::getState(
id) == deleted);
284 TIBase::ResetStatesGuard rsg{
true};
286 using enum TrackedState;
288 swu b = make_SharedIntrusive<TIBase>();
289 BEAST_EXPECT(b.isStrong() && b.use_count() == 1);
290 auto id = b.get()->id_;
291 BEAST_EXPECT(TIBase::getState(
id) == alive);
293 BEAST_EXPECT(TIBase::getState(
id) == alive);
294 BEAST_EXPECT(w.isStrong() && b.use_count() == 2);
296 BEAST_EXPECT(w.isWeak() && b.use_count() == 1);
298 BEAST_EXPECT(s.isWeak() && b.use_count() == 1);
300 BEAST_EXPECT(s.isStrong() && b.use_count() == 2);
302 BEAST_EXPECT(TIBase::getState(
id) == alive);
303 BEAST_EXPECT(s.use_count() == 1);
304 BEAST_EXPECT(!w.expired());
306 BEAST_EXPECT(TIBase::getState(
id) == partiallyDeleted);
307 BEAST_EXPECT(w.expired());
311 BEAST_EXPECT(w.isWeak());
313 BEAST_EXPECT(TIBase::getState(
id) == deleted);
318 TIBase::ResetStatesGuard rsg{
true};
320 auto strong1 = make_SharedIntrusive<TIBase>();
321 auto strong2 = make_SharedIntrusive<TIBase>();
323 auto id1 = strong1->id_;
324 auto id2 = strong2->id_;
326 BEAST_EXPECT(id1 != id2);
333 BEAST_EXPECT(union1.
get() == strong1.get());
334 BEAST_EXPECT(union2.
get() == strong2.get());
340 BEAST_EXPECT(union1.
get() == union2.
get());
341 BEAST_EXPECT(TIBase::getState(id1) == TrackedState::alive);
342 BEAST_EXPECT(TIBase::getState(id2) == TrackedState::alive);
346 BEAST_EXPECT(TIBase::getState(id1) == TrackedState::alive);
347 int initialRefCount = strong1->use_count();
348#pragma clang diagnostic push
349#pragma clang diagnostic ignored "-Wself-assign-overloaded"
351#pragma clang diagnostic pop
353 BEAST_EXPECT(TIBase::getState(id1) == TrackedState::alive);
354 BEAST_EXPECT(strong1->use_count() == initialRefCount);
358 BEAST_EXPECT(union1.
get() ==
nullptr);
364 BEAST_EXPECT(union1.
get() ==
nullptr);
365 BEAST_EXPECT(TIBase::getState(id2) == TrackedState::deleted);
381 using enum TrackedState;
383 TIBase::ResetStatesGuard rsg{
true};
385 auto strong = make_SharedIntrusive<TIBase>();
387 bool destructorRan =
false;
388 bool partialDeleteRan =
false;
390 strong->tracingCallback_ = [&](TrackedState cur,
392 using enum TrackedState;
393 if (next == deletedStarted)
400 BEAST_EXPECT(cur == partiallyDeleted);
402 if (next == partiallyDeletedStarted)
404 partialDeleteStartedSyncPoint.arrive_and_wait();
405 using namespace std::chrono_literals;
411 if (next == partiallyDeleted)
413 BEAST_EXPECT(!partialDeleteRan && !destructorRan);
414 partialDeleteRan =
true;
418 BEAST_EXPECT(!destructorRan);
419 destructorRan =
true;
423 partialDeleteStartedSyncPoint.arrive_and_wait();
433 BEAST_EXPECT(destructorRan && partialDeleteRan);
449 using enum TrackedState;
451 TIBase::ResetStatesGuard rsg{
true};
453 auto strong = make_SharedIntrusive<TIBase>();
455 bool destructorRan =
false;
456 bool partialDeleteRan =
false;
458 strong->tracingCallback_ = [&](TrackedState cur,
460 using enum TrackedState;
461 if (next == partiallyDeleted)
463 BEAST_EXPECT(!partialDeleteRan && !destructorRan);
464 partialDeleteRan =
true;
468 BEAST_EXPECT(!destructorRan);
469 destructorRan =
true;
474 weakResetSyncPoint.arrive_and_wait();
477 weakResetSyncPoint.arrive_and_wait();
483 BEAST_EXPECT(destructorRan && !partialDeleteRan);
489 testcase(
"Multithreaded Clear Mixed Variant");
496 using enum TrackedState;
497 TIBase::ResetStatesGuard rsg{
true};
503 return {(s & 1) != 0, (s & 2) != 0};
505 auto setDestructorRan = [&]() ->
void {
508 auto setPartialDeleteRan = [&]() ->
void {
511 auto tracingCallback = [&](TrackedState cur,
513 using enum TrackedState;
514 auto [destructorRan, partialDeleteRan] = getDestructorState();
515 if (next == partiallyDeleted)
517 BEAST_EXPECT(!partialDeleteRan && !destructorRan);
518 setPartialDeleteRan();
522 BEAST_EXPECT(!destructorRan);
526 auto createVecOfPointers = [&](
auto const& toClone,
535 auto numToCreate = toCreateDist(eng);
536 result.reserve(numToCreate);
537 for (
int i = 0; i < numToCreate; ++i)
539 if (isStrongDist(eng))
550 constexpr int loopIters = 2 * 1024;
551 constexpr int numThreads = 16;
553 Barrier loopStartSyncPoint{numThreads};
554 Barrier postCreateToCloneSyncPoint{numThreads};
555 Barrier postCreateVecOfPointersSyncPoint{numThreads};
560 for (
int i = 0; i < numThreads; ++i)
568 auto cloneAndDestroy = [&](
int threadId) {
569 for (
int i = 0; i < loopIters; ++i)
572 loopStartSyncPoint.arrive_and_wait();
584 auto [destructorRan, partialDeleteRan] =
585 getDestructorState();
586 BEAST_EXPECT(!i || destructorRan);
590 toClone.
resize(numThreads);
591 auto strong = make_SharedIntrusive<TIBase>();
592 strong->tracingCallback_ = tracingCallback;
597 postCreateToCloneSyncPoint.arrive_and_wait();
600 createVecOfPointers(toClone[threadId], engines[threadId]);
601 toClone[threadId].reset();
604 postCreateVecOfPointersSyncPoint.arrive_and_wait();
610 for (
int i = 0; i < numThreads; ++i)
614 for (
int i = 0; i < numThreads; ++i)
623 testcase(
"Multithreaded Clear Mixed Union");
635 using enum TrackedState;
637 TIBase::ResetStatesGuard rsg{
true};
643 return {(s & 1) != 0, (s & 2) != 0};
645 auto setDestructorRan = [&]() ->
void {
648 auto setPartialDeleteRan = [&]() ->
void {
651 auto tracingCallback = [&](TrackedState cur,
653 using enum TrackedState;
654 auto [destructorRan, partialDeleteRan] = getDestructorState();
655 if (next == partiallyDeleted)
657 BEAST_EXPECT(!partialDeleteRan && !destructorRan);
658 setPartialDeleteRan();
662 BEAST_EXPECT(!destructorRan);
666 auto createVecOfPointers = [&](
auto const& toClone,
671 auto numToCreate = toCreateDist(eng);
673 for (
int i = 0; i < numToCreate; ++i)
677 constexpr int loopIters = 2 * 1024;
678 constexpr int flipPointersLoopIters = 256;
679 constexpr int numThreads = 16;
681 Barrier loopStartSyncPoint{numThreads};
682 Barrier postCreateToCloneSyncPoint{numThreads};
683 Barrier postCreateVecOfPointersSyncPoint{numThreads};
684 Barrier postFlipPointersLoopSyncPoint{numThreads};
689 for (
int i = 0; i < numThreads; ++i)
698 auto cloneAndDestroy = [&](
int threadId) {
699 for (
int i = 0; i < loopIters; ++i)
702 loopStartSyncPoint.arrive_and_wait();
713 auto [destructorRan, partialDeleteRan] =
714 getDestructorState();
715 BEAST_EXPECT(!i || destructorRan);
719 toClone.
resize(numThreads);
720 auto strong = make_SharedIntrusive<TIBase>();
721 strong->tracingCallback_ = tracingCallback;
726 postCreateToCloneSyncPoint.arrive_and_wait();
729 createVecOfPointers(toClone[threadId], engines[threadId]);
730 toClone[threadId].reset();
733 postCreateVecOfPointersSyncPoint.arrive_and_wait();
736 for (
int f = 0; f < flipPointersLoopIters; ++f)
740 if (isStrongDist(engines[threadId]))
752 postFlipPointersLoopSyncPoint.arrive_and_wait();
758 for (
int i = 0; i < numThreads; ++i)
762 for (
int i = 0; i < numThreads; ++i)
771 testcase(
"Multithreaded Locking Weak");
778 using enum TrackedState;
780 TIBase::ResetStatesGuard rsg{
true};
786 return {(s & 1) != 0, (s & 2) != 0};
788 auto setDestructorRan = [&]() ->
void {
791 auto setPartialDeleteRan = [&]() ->
void {
794 auto tracingCallback = [&](TrackedState cur,
796 using enum TrackedState;
797 auto [destructorRan, partialDeleteRan] = getDestructorState();
798 if (next == partiallyDeleted)
800 BEAST_EXPECT(!partialDeleteRan && !destructorRan);
801 setPartialDeleteRan();
805 BEAST_EXPECT(!destructorRan);
810 constexpr int loopIters = 2 * 1024;
811 constexpr int lockWeakLoopIters = 256;
812 constexpr int numThreads = 16;
814 Barrier loopStartSyncPoint{numThreads};
815 Barrier postCreateToLockSyncPoint{numThreads};
816 Barrier postLockWeakLoopSyncPoint{numThreads};
821 auto lockAndDestroy = [&](
int threadId) {
822 for (
int i = 0; i < loopIters; ++i)
836 auto [destructorRan, partialDeleteRan] =
837 getDestructorState();
838 BEAST_EXPECT(!i || destructorRan);
842 toLock.
resize(numThreads);
843 auto strong = make_SharedIntrusive<TIBase>();
844 strong->tracingCallback_ = tracingCallback;
849 postCreateToLockSyncPoint.arrive_and_wait();
854 for (
int wi = 0; wi < lockWeakLoopIters; ++wi)
856 BEAST_EXPECT(!weak.expired());
857 auto strong = weak.lock();
858 BEAST_EXPECT(strong);
862 postLockWeakLoopSyncPoint.arrive_and_wait();
864 toLock[threadId].reset();
868 for (
int i = 0; i < numThreads; ++i)
872 for (
int i = 0; i < numThreads; ++i)