194 TIBase::ResetStatesGuard
const 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);
203 TIBase
const* pb = &b;
206 auto w = b.releaseWeakRef();
213 TIBase::ResetStatesGuard
const 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
const 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
const 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
const 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 const 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
const 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
const 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
const rsg{
true};
495 return {(s & 1) != 0, (s & 2) != 0};
497 auto setDestructorRan = [&]() ->
void {
500 auto setPartialDeleteRan = [&]() ->
void {
504 using enum TrackedState;
505 auto [destructorRan, partialDeleteRan] = getDestructorState();
506 if (next == partiallyDeleted)
508 BEAST_EXPECT(!partialDeleteRan && !destructorRan);
509 setPartialDeleteRan();
513 BEAST_EXPECT(!destructorRan);
522 auto numToCreate = toCreateDist(eng);
524 for (
int i = 0; i < numToCreate; ++i)
526 if (isStrongDist(eng))
537 constexpr int loopIters = 2 * 1024;
538 constexpr int numThreads = 16;
540 Barrier loopStartSyncPoint{numThreads};
541 Barrier postCreateToCloneSyncPoint{numThreads};
542 Barrier postCreateVecOfPointersSyncPoint{numThreads};
547 for (
int i = 0; i < numThreads; ++i)
555 auto cloneAndDestroy = [&](
int threadId) {
556 for (
int i = 0; i < loopIters; ++i)
559 loopStartSyncPoint.arrive_and_wait();
571 auto [destructorRan, partialDeleteRan] = getDestructorState();
572 BEAST_EXPECT(!i || destructorRan);
576 toClone.
resize(numThreads);
577 auto strong = make_SharedIntrusive<TIBase>();
578 strong->tracingCallback_ = tracingCallback;
583 postCreateToCloneSyncPoint.arrive_and_wait();
585 auto v = createVecOfPointers(toClone[threadId], engines[threadId]);
586 toClone[threadId].reset();
589 postCreateVecOfPointersSyncPoint.arrive_and_wait();
596 for (
int i = 0; i < numThreads; ++i)
600 for (
int i = 0; i < numThreads; ++i)
609 testcase(
"Multithreaded Clear Mixed Union");
621 using enum TrackedState;
623 TIBase::ResetStatesGuard
const rsg{
true};
629 return {(s & 1) != 0, (s & 2) != 0};
631 auto setDestructorRan = [&]() ->
void {
634 auto setPartialDeleteRan = [&]() ->
void {
638 using enum TrackedState;
639 auto [destructorRan, partialDeleteRan] = getDestructorState();
640 if (next == partiallyDeleted)
642 BEAST_EXPECT(!partialDeleteRan && !destructorRan);
643 setPartialDeleteRan();
647 BEAST_EXPECT(!destructorRan);
651 auto createVecOfPointers =
652 [&](
auto const& toClone,
656 auto numToCreate = toCreateDist(eng);
658 for (
int i = 0; i < numToCreate; ++i)
662 constexpr int loopIters = 2 * 1024;
663 constexpr int flipPointersLoopIters = 256;
664 constexpr int numThreads = 16;
666 Barrier loopStartSyncPoint{numThreads};
667 Barrier postCreateToCloneSyncPoint{numThreads};
668 Barrier postCreateVecOfPointersSyncPoint{numThreads};
669 Barrier postFlipPointersLoopSyncPoint{numThreads};
674 for (
int i = 0; i < numThreads; ++i)
683 auto cloneAndDestroy = [&](
int threadId) {
684 for (
int i = 0; i < loopIters; ++i)
687 loopStartSyncPoint.arrive_and_wait();
698 auto [destructorRan, partialDeleteRan] = getDestructorState();
699 BEAST_EXPECT(!i || destructorRan);
703 toClone.
resize(numThreads);
704 auto strong = make_SharedIntrusive<TIBase>();
705 strong->tracingCallback_ = tracingCallback;
710 postCreateToCloneSyncPoint.arrive_and_wait();
712 auto v = createVecOfPointers(toClone[threadId], engines[threadId]);
713 toClone[threadId].reset();
716 postCreateVecOfPointersSyncPoint.arrive_and_wait();
719 for (
int f = 0; f < flipPointersLoopIters; ++f)
723 if (isStrongDist(engines[threadId]))
735 postFlipPointersLoopSyncPoint.arrive_and_wait();
742 for (
int i = 0; i < numThreads; ++i)
746 for (
int i = 0; i < numThreads; ++i)
755 testcase(
"Multithreaded Locking Weak");
762 using enum TrackedState;
764 TIBase::ResetStatesGuard
const rsg{
true};
770 return {(s & 1) != 0, (s & 2) != 0};
772 auto setDestructorRan = [&]() ->
void {
775 auto setPartialDeleteRan = [&]() ->
void {
779 using enum TrackedState;
780 auto [destructorRan, partialDeleteRan] = getDestructorState();
781 if (next == partiallyDeleted)
783 BEAST_EXPECT(!partialDeleteRan && !destructorRan);
784 setPartialDeleteRan();
788 BEAST_EXPECT(!destructorRan);
793 constexpr int loopIters = 2 * 1024;
794 constexpr int lockWeakLoopIters = 256;
795 constexpr int numThreads = 16;
797 Barrier loopStartSyncPoint{numThreads};
798 Barrier postCreateToLockSyncPoint{numThreads};
799 Barrier postLockWeakLoopSyncPoint{numThreads};
804 auto lockAndDestroy = [&](
int threadId) {
805 for (
int i = 0; i < loopIters; ++i)
819 auto [destructorRan, partialDeleteRan] = getDestructorState();
820 BEAST_EXPECT(!i || destructorRan);
824 toLock.
resize(numThreads);
825 auto strong = make_SharedIntrusive<TIBase>();
826 strong->tracingCallback_ = tracingCallback;
831 postCreateToLockSyncPoint.arrive_and_wait();
836 for (
int wi = 0; wi < lockWeakLoopIters; ++wi)
838 BEAST_EXPECT(!weak.expired());
839 auto strong = weak.lock();
840 BEAST_EXPECT(strong);
844 postLockWeakLoopSyncPoint.arrive_and_wait();
846 toLock[threadId].reset();
851 for (
int i = 0; i < numThreads; ++i)
855 for (
int i = 0; i < numThreads; ++i)