1 //
2 // Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 #include "td/utils/common.h"
8 #include "td/utils/HazardPointers.h"
9 #include "td/utils/logging.h"
10 #include "td/utils/port/thread.h"
11 #include "td/utils/Random.h"
12 #include "td/utils/Slice.h"
13 #include "td/utils/tests.h"
14 
15 #include <atomic>
16 
17 #if !TD_THREAD_UNSUPPORTED
TEST(HazardPointers,stress)18 TEST(HazardPointers, stress) {
19   struct Node {
20     std::atomic<std::string *> name_{nullptr};
21     char pad[64];
22   };
23   int threads_n = 10;
24   std::vector<Node> nodes(threads_n);
25   td::HazardPointers<std::string> hazard_pointers(threads_n);
26   std::vector<td::thread> threads(threads_n);
27   int thread_id = 0;
28   for (auto &thread : threads) {
29     thread = td::thread([&, thread_id] {
30       std::remove_reference_t<decltype(hazard_pointers)>::Holder holder(hazard_pointers, thread_id, 0);
31       for (int i = 0; i < 1000000; i++) {
32         auto &node = nodes[td::Random::fast(0, threads_n - 1)];
33         auto *str = holder.protect(node.name_);
34         if (str) {
35           CHECK(*str == td::Slice("one") || *str == td::Slice("twotwo"));
36         }
37         holder.clear();
38         if (td::Random::fast(0, 5) == 0) {
39           auto *new_str = new td::string(td::Random::fast_bool() ? "one" : "twotwo");
40           if (node.name_.compare_exchange_strong(str, new_str, std::memory_order_acq_rel)) {
41             hazard_pointers.retire(thread_id, str);
42           } else {
43             delete new_str;
44           }
45         }
46       }
47     });
48     thread_id++;
49   }
50   for (auto &thread : threads) {
51     thread.join();
52   }
53   LOG(INFO) << "Undeleted pointers: " << hazard_pointers.to_delete_size_unsafe();
54   CHECK(static_cast<int>(hazard_pointers.to_delete_size_unsafe()) <= threads_n * threads_n);
55   for (int i = 0; i < threads_n; i++) {
56     hazard_pointers.retire(i);
57   }
58   CHECK(hazard_pointers.to_delete_size_unsafe() == 0);
59 }
60 #endif
61