xref: /llvm-project/libcxx/test/libcxx/utilities/memory/util.smartptr/race_condition.pass.cpp (revision a7f9895cc18995549c7facb96e72718da282a864)
11faf289eSEric Fiselier //===----------------------------------------------------------------------===//
21faf289eSEric Fiselier //
357b08b09SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
457b08b09SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
557b08b09SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
61faf289eSEric Fiselier //
71faf289eSEric Fiselier //===----------------------------------------------------------------------===//
81faf289eSEric Fiselier //
9*a7f9895cSLouis Dionne // UNSUPPORTED: no-threads
101faf289eSEric Fiselier //
111faf289eSEric Fiselier // <memory>
121faf289eSEric Fiselier //
131faf289eSEric Fiselier // class shared_ptr
141faf289eSEric Fiselier //
151faf289eSEric Fiselier // This test attempts to create a race condition surrounding use_count()
161faf289eSEric Fiselier // with the hope that TSAN will diagnose it.
171faf289eSEric Fiselier 
181faf289eSEric Fiselier #include <memory>
191faf289eSEric Fiselier #include <atomic>
201faf289eSEric Fiselier #include <thread>
211faf289eSEric Fiselier #include <cassert>
221faf289eSEric Fiselier 
2356462801SLouis Dionne #include "make_test_thread.h"
247fc6a556SMarshall Clow #include "test_macros.h"
257fc6a556SMarshall Clow 
261faf289eSEric Fiselier typedef std::shared_ptr<int> Ptr;
271faf289eSEric Fiselier typedef std::weak_ptr<int> WeakPtr;
281faf289eSEric Fiselier 
291faf289eSEric Fiselier std::atomic_bool Start;
301faf289eSEric Fiselier std::atomic_bool KeepRunning;
311faf289eSEric Fiselier 
321faf289eSEric Fiselier struct TestRunner {
TestRunnerTestRunner331faf289eSEric Fiselier     TestRunner(Ptr xx) : x(xx) {}
operator ()TestRunner341faf289eSEric Fiselier     void operator()() {
351faf289eSEric Fiselier         while (Start == false) {}
361faf289eSEric Fiselier         while (KeepRunning) {
371faf289eSEric Fiselier             // loop to prevent always checking the atomic.
381faf289eSEric Fiselier             for (int i=0; i < 100000; ++i) {
391faf289eSEric Fiselier                 Ptr x2 = x; // increment shared count
401faf289eSEric Fiselier                 WeakPtr x3 = x; // increment weak count
411faf289eSEric Fiselier                 Ptr x4 = x3.lock(); // increment shared count via lock
421faf289eSEric Fiselier                 WeakPtr x5 = x3; // increment weak count
431faf289eSEric Fiselier             }
441faf289eSEric Fiselier         }
451faf289eSEric Fiselier     }
461faf289eSEric Fiselier     Ptr x;
471faf289eSEric Fiselier };
481faf289eSEric Fiselier 
run_test(Ptr p)491faf289eSEric Fiselier void run_test(Ptr p) {
501faf289eSEric Fiselier     Start = false;
511faf289eSEric Fiselier     KeepRunning = true;
521faf289eSEric Fiselier     assert(p.use_count() == 2);
531faf289eSEric Fiselier     TestRunner r(p);
541faf289eSEric Fiselier     assert(p.use_count() == 3);
5556462801SLouis Dionne     std::thread t1 = support::make_test_thread(r); // Start the test thread.
561faf289eSEric Fiselier     assert(p.use_count() == 4);
571faf289eSEric Fiselier     Start = true;
581faf289eSEric Fiselier     // Run until we witness 25 use count changes via both
591faf289eSEric Fiselier     // shared and weak pointer methods.
601faf289eSEric Fiselier     WeakPtr w = p;
611faf289eSEric Fiselier     int shared_changes_count = 0;
621faf289eSEric Fiselier     int weak_changes_count = 0;
631faf289eSEric Fiselier     while (shared_changes_count < 25 && weak_changes_count < 25) {
641faf289eSEric Fiselier         // check use_count on the shared_ptr
651faf289eSEric Fiselier        int last = p.use_count();
661faf289eSEric Fiselier        int new_val = p.use_count();
671faf289eSEric Fiselier        assert(last >= 4);
681faf289eSEric Fiselier        assert(new_val >= 4);
691faf289eSEric Fiselier        if (last != new_val) ++shared_changes_count;
701faf289eSEric Fiselier        // Check use_count on the weak_ptr
711faf289eSEric Fiselier        last = w.use_count();
721faf289eSEric Fiselier        new_val = w.use_count();
731faf289eSEric Fiselier        assert(last >= 4);
741faf289eSEric Fiselier        assert(new_val >= 4);
751faf289eSEric Fiselier        if (last != new_val) ++weak_changes_count;
761faf289eSEric Fiselier     }
771faf289eSEric Fiselier     // kill the test thread.
781faf289eSEric Fiselier     KeepRunning = false;
791faf289eSEric Fiselier     t1.join();
801faf289eSEric Fiselier     assert(p.use_count() == 3);
811faf289eSEric Fiselier }
821faf289eSEric Fiselier 
main(int,char **)832df59c50SJF Bastien int main(int, char**) {
841faf289eSEric Fiselier   {
851faf289eSEric Fiselier     // Test with out-of-place shared_count.
861faf289eSEric Fiselier     Ptr p(new int(42));
871faf289eSEric Fiselier     run_test(p);
881faf289eSEric Fiselier     assert(p.use_count() == 1);
891faf289eSEric Fiselier   }
901faf289eSEric Fiselier   {
911faf289eSEric Fiselier     // Test with in-place shared_count.
921e051aabSEric Fiselier     int val = 42;
931e051aabSEric Fiselier     Ptr p = std::make_shared<int>(val);
941faf289eSEric Fiselier     run_test(p);
951faf289eSEric Fiselier     assert(p.use_count() == 1);
961faf289eSEric Fiselier   }
972df59c50SJF Bastien 
982df59c50SJF Bastien   return 0;
991faf289eSEric Fiselier }
100