xref: /llvm-project/libcxx/test/libcxx/utilities/memory/util.smartptr/race_condition.pass.cpp (revision a7f9895cc18995549c7facb96e72718da282a864)
1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // UNSUPPORTED: no-threads
10 //
11 // <memory>
12 //
13 // class shared_ptr
14 //
15 // This test attempts to create a race condition surrounding use_count()
16 // with the hope that TSAN will diagnose it.
17 
18 #include <memory>
19 #include <atomic>
20 #include <thread>
21 #include <cassert>
22 
23 #include "make_test_thread.h"
24 #include "test_macros.h"
25 
26 typedef std::shared_ptr<int> Ptr;
27 typedef std::weak_ptr<int> WeakPtr;
28 
29 std::atomic_bool Start;
30 std::atomic_bool KeepRunning;
31 
32 struct TestRunner {
TestRunnerTestRunner33     TestRunner(Ptr xx) : x(xx) {}
operator ()TestRunner34     void operator()() {
35         while (Start == false) {}
36         while (KeepRunning) {
37             // loop to prevent always checking the atomic.
38             for (int i=0; i < 100000; ++i) {
39                 Ptr x2 = x; // increment shared count
40                 WeakPtr x3 = x; // increment weak count
41                 Ptr x4 = x3.lock(); // increment shared count via lock
42                 WeakPtr x5 = x3; // increment weak count
43             }
44         }
45     }
46     Ptr x;
47 };
48 
run_test(Ptr p)49 void run_test(Ptr p) {
50     Start = false;
51     KeepRunning = true;
52     assert(p.use_count() == 2);
53     TestRunner r(p);
54     assert(p.use_count() == 3);
55     std::thread t1 = support::make_test_thread(r); // Start the test thread.
56     assert(p.use_count() == 4);
57     Start = true;
58     // Run until we witness 25 use count changes via both
59     // shared and weak pointer methods.
60     WeakPtr w = p;
61     int shared_changes_count = 0;
62     int weak_changes_count = 0;
63     while (shared_changes_count < 25 && weak_changes_count < 25) {
64         // check use_count on the shared_ptr
65        int last = p.use_count();
66        int new_val = p.use_count();
67        assert(last >= 4);
68        assert(new_val >= 4);
69        if (last != new_val) ++shared_changes_count;
70        // Check use_count on the weak_ptr
71        last = w.use_count();
72        new_val = w.use_count();
73        assert(last >= 4);
74        assert(new_val >= 4);
75        if (last != new_val) ++weak_changes_count;
76     }
77     // kill the test thread.
78     KeepRunning = false;
79     t1.join();
80     assert(p.use_count() == 3);
81 }
82 
main(int,char **)83 int main(int, char**) {
84   {
85     // Test with out-of-place shared_count.
86     Ptr p(new int(42));
87     run_test(p);
88     assert(p.use_count() == 1);
89   }
90   {
91     // Test with in-place shared_count.
92     int val = 42;
93     Ptr p = std::make_shared<int>(val);
94     run_test(p);
95     assert(p.use_count() == 1);
96   }
97 
98   return 0;
99 }
100