tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

thread_identity_test.cc (4577B)


      1 // Copyright 2017 The Abseil Authors.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //      https://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 #include "absl/base/internal/thread_identity.h"
     16 
     17 #include <thread>  // NOLINT(build/c++11)
     18 #include <vector>
     19 
     20 #include "gtest/gtest.h"
     21 #include "absl/base/attributes.h"
     22 #include "absl/base/internal/spinlock.h"
     23 #include "absl/base/macros.h"
     24 #include "absl/base/thread_annotations.h"
     25 #include "absl/synchronization/internal/per_thread_sem.h"
     26 #include "absl/synchronization/mutex.h"
     27 
     28 namespace absl {
     29 ABSL_NAMESPACE_BEGIN
     30 namespace base_internal {
     31 namespace {
     32 
     33 ABSL_CONST_INIT static absl::base_internal::SpinLock map_lock(
     34    absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
     35 ABSL_CONST_INIT static int num_identities_reused ABSL_GUARDED_BY(map_lock);
     36 
     37 static const void* const kCheckNoIdentity = reinterpret_cast<void*>(1);
     38 
     39 static void TestThreadIdentityCurrent(const void* assert_no_identity) {
     40  ThreadIdentity* identity;
     41 
     42  // We have to test this conditionally, because if the test framework relies
     43  // on Abseil, then some previous action may have already allocated an
     44  // identity.
     45  if (assert_no_identity == kCheckNoIdentity) {
     46    identity = CurrentThreadIdentityIfPresent();
     47    EXPECT_TRUE(identity == nullptr);
     48  }
     49 
     50  identity = synchronization_internal::GetOrCreateCurrentThreadIdentity();
     51  EXPECT_TRUE(identity != nullptr);
     52  ThreadIdentity* identity_no_init;
     53  identity_no_init = CurrentThreadIdentityIfPresent();
     54  EXPECT_TRUE(identity == identity_no_init);
     55 
     56  // Check that per_thread_synch is correctly aligned.
     57  EXPECT_EQ(0, reinterpret_cast<intptr_t>(&identity->per_thread_synch) %
     58                   PerThreadSynch::kAlignment);
     59  EXPECT_EQ(identity, identity->per_thread_synch.thread_identity());
     60 
     61  absl::base_internal::SpinLockHolder l(&map_lock);
     62  num_identities_reused++;
     63 }
     64 
     65 TEST(ThreadIdentityTest, BasicIdentityWorks) {
     66  // This tests for the main() thread.
     67  TestThreadIdentityCurrent(nullptr);
     68 }
     69 
     70 TEST(ThreadIdentityTest, BasicIdentityWorksThreaded) {
     71  // Now try the same basic test with multiple threads being created and
     72  // destroyed.  This makes sure that:
     73  // - New threads are created without a ThreadIdentity.
     74  // - We re-allocate ThreadIdentity objects from the free-list.
     75  // - If a thread implementation chooses to recycle threads, that
     76  //   correct re-initialization occurs.
     77  static const int kNumLoops = 3;
     78  static const int kNumThreads = 32;
     79  for (int iter = 0; iter < kNumLoops; iter++) {
     80    std::vector<std::thread> threads;
     81    for (int i = 0; i < kNumThreads; ++i) {
     82      threads.push_back(
     83          std::thread(TestThreadIdentityCurrent, kCheckNoIdentity));
     84    }
     85    for (auto& thread : threads) {
     86      thread.join();
     87    }
     88  }
     89 
     90  // We should have recycled ThreadIdentity objects above; while (external)
     91  // library threads allocating their own identities may preclude some
     92  // reuse, we should have sufficient repetitions to exclude this.
     93  absl::base_internal::SpinLockHolder l(&map_lock);
     94  EXPECT_LT(kNumThreads, num_identities_reused);
     95 }
     96 
     97 TEST(ThreadIdentityTest, ReusedThreadIdentityMutexTest) {
     98  // This test repeatedly creates and joins a series of threads, each of
     99  // which acquires and releases shared Mutex locks. This verifies
    100  // Mutex operations work correctly under a reused
    101  // ThreadIdentity. Note that the most likely failure mode of this
    102  // test is a crash or deadlock.
    103  static const int kNumLoops = 10;
    104  static const int kNumThreads = 12;
    105  static const int kNumMutexes = 3;
    106  static const int kNumLockLoops = 5;
    107 
    108  Mutex mutexes[kNumMutexes];
    109  for (int iter = 0; iter < kNumLoops; ++iter) {
    110    std::vector<std::thread> threads;
    111    for (int thread = 0; thread < kNumThreads; ++thread) {
    112      threads.push_back(std::thread([&]() {
    113        for (int l = 0; l < kNumLockLoops; ++l) {
    114          for (int m = 0; m < kNumMutexes; ++m) {
    115            MutexLock lock(&mutexes[m]);
    116          }
    117        }
    118      }));
    119    }
    120    for (auto& thread : threads) {
    121      thread.join();
    122    }
    123  }
    124 }
    125 
    126 }  // namespace
    127 }  // namespace base_internal
    128 ABSL_NAMESPACE_END
    129 }  // namespace absl