thread_identity_test.cc
Go to the documentation of this file.
00001 // Copyright 2017 The Abseil Authors.
00002 //
00003 // Licensed under the Apache License, Version 2.0 (the "License");
00004 // you may not use this file except in compliance with the License.
00005 // You may obtain a copy of the License at
00006 //
00007 //      https://www.apache.org/licenses/LICENSE-2.0
00008 //
00009 // Unless required by applicable law or agreed to in writing, software
00010 // distributed under the License is distributed on an "AS IS" BASIS,
00011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00012 // See the License for the specific language governing permissions and
00013 // limitations under the License.
00014 
00015 #include "absl/base/internal/thread_identity.h"
00016 
00017 #include <thread>  // NOLINT(build/c++11)
00018 #include <vector>
00019 
00020 #include "gtest/gtest.h"
00021 #include "absl/base/attributes.h"
00022 #include "absl/base/internal/spinlock.h"
00023 #include "absl/base/macros.h"
00024 #include "absl/synchronization/internal/per_thread_sem.h"
00025 #include "absl/synchronization/mutex.h"
00026 
00027 namespace absl {
00028 namespace base_internal {
00029 namespace {
00030 
00031 // protects num_identities_reused
00032 static absl::base_internal::SpinLock map_lock(
00033     absl::base_internal::kLinkerInitialized);
00034 static int num_identities_reused;
00035 
00036 static const void* const kCheckNoIdentity = reinterpret_cast<void*>(1);
00037 
00038 static void TestThreadIdentityCurrent(const void* assert_no_identity) {
00039   ThreadIdentity* identity;
00040 
00041   // We have to test this conditionally, because if the test framework relies
00042   // on Abseil, then some previous action may have already allocated an
00043   // identity.
00044   if (assert_no_identity == kCheckNoIdentity) {
00045     identity = CurrentThreadIdentityIfPresent();
00046     EXPECT_TRUE(identity == nullptr);
00047   }
00048 
00049   identity = synchronization_internal::GetOrCreateCurrentThreadIdentity();
00050   EXPECT_TRUE(identity != nullptr);
00051   ThreadIdentity* identity_no_init;
00052   identity_no_init = CurrentThreadIdentityIfPresent();
00053   EXPECT_TRUE(identity == identity_no_init);
00054 
00055   // Check that per_thread_synch is correctly aligned.
00056   EXPECT_EQ(0, reinterpret_cast<intptr_t>(&identity->per_thread_synch) %
00057                    PerThreadSynch::kAlignment);
00058   EXPECT_EQ(identity, identity->per_thread_synch.thread_identity());
00059 
00060   absl::base_internal::SpinLockHolder l(&map_lock);
00061   num_identities_reused++;
00062 }
00063 
00064 TEST(ThreadIdentityTest, BasicIdentityWorks) {
00065   // This tests for the main() thread.
00066   TestThreadIdentityCurrent(nullptr);
00067 }
00068 
00069 TEST(ThreadIdentityTest, BasicIdentityWorksThreaded) {
00070   // Now try the same basic test with multiple threads being created and
00071   // destroyed.  This makes sure that:
00072   // - New threads are created without a ThreadIdentity.
00073   // - We re-allocate ThreadIdentity objects from the free-list.
00074   // - If a thread implementation chooses to recycle threads, that
00075   //   correct re-initialization occurs.
00076   static const int kNumLoops = 3;
00077   static const int kNumThreads = 400;
00078   for (int iter = 0; iter < kNumLoops; iter++) {
00079     std::vector<std::thread> threads;
00080     for (int i = 0; i < kNumThreads; ++i) {
00081       threads.push_back(
00082           std::thread(TestThreadIdentityCurrent, kCheckNoIdentity));
00083     }
00084     for (auto& thread : threads) {
00085       thread.join();
00086     }
00087   }
00088 
00089   // We should have recycled ThreadIdentity objects above; while (external)
00090   // library threads allocating their own identities may preclude some
00091   // reuse, we should have sufficient repetitions to exclude this.
00092   EXPECT_LT(kNumThreads, num_identities_reused);
00093 }
00094 
00095 TEST(ThreadIdentityTest, ReusedThreadIdentityMutexTest) {
00096   // This test repeatly creates and joins a series of threads, each of
00097   // which acquires and releases shared Mutex locks. This verifies
00098   // Mutex operations work correctly under a reused
00099   // ThreadIdentity. Note that the most likely failure mode of this
00100   // test is a crash or deadlock.
00101   static const int kNumLoops = 10;
00102   static const int kNumThreads = 12;
00103   static const int kNumMutexes = 3;
00104   static const int kNumLockLoops = 5;
00105 
00106   Mutex mutexes[kNumMutexes];
00107   for (int iter = 0; iter < kNumLoops; ++iter) {
00108     std::vector<std::thread> threads;
00109     for (int thread = 0; thread < kNumThreads; ++thread) {
00110       threads.push_back(std::thread([&]() {
00111         for (int l = 0; l < kNumLockLoops; ++l) {
00112           for (int m = 0; m < kNumMutexes; ++m) {
00113             MutexLock lock(&mutexes[m]);
00114           }
00115         }
00116       }));
00117     }
00118     for (auto& thread : threads) {
00119       thread.join();
00120     }
00121   }
00122 }
00123 
00124 }  // namespace
00125 }  // namespace base_internal
00126 }  // namespace absl


abseil_cpp
Author(s):
autogenerated on Wed Jun 19 2019 19:42:15