- f59c2332341d6b1a3e045d61eb0065f7a226f807 Avoid preprocessing '__CUDACC_VER__ >= 70000' on CUDA 9,... by Abseil Team <absl-team@google.com> - 12dd22cf967603e9a12d58abfe877989d61844e3 Internal change. by Greg Falcon <gfalcon@google.com> GitOrigin-RevId: f59c2332341d6b1a3e045d61eb0065f7a226f807 Change-Id: If4f5274e6d638a2ac86f1377e6ac0481dc584f19
		
			
				
	
	
		
			126 lines
		
	
	
	
		
			4.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			126 lines
		
	
	
	
		
			4.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright 2017 The Abseil Authors.
 | |
| //
 | |
| // Licensed under the Apache License, Version 2.0 (the "License");
 | |
| // you may not use this file except in compliance with the License.
 | |
| // You may obtain a copy of the License at
 | |
| //
 | |
| //      http://www.apache.org/licenses/LICENSE-2.0
 | |
| //
 | |
| // Unless required by applicable law or agreed to in writing, software
 | |
| // distributed under the License is distributed on an "AS IS" BASIS,
 | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| // See the License for the specific language governing permissions and
 | |
| // limitations under the License.
 | |
| 
 | |
| #include "absl/base/internal/thread_identity.h"
 | |
| 
 | |
| #include <thread>  // NOLINT(build/c++11)
 | |
| #include <vector>
 | |
| 
 | |
| #include "gtest/gtest.h"
 | |
| #include "absl/base/attributes.h"
 | |
| #include "absl/base/internal/spinlock.h"
 | |
| #include "absl/base/macros.h"
 | |
| #include "absl/synchronization/internal/per_thread_sem.h"
 | |
| #include "absl/synchronization/mutex.h"
 | |
| 
 | |
| namespace absl {
 | |
| namespace base_internal {
 | |
| namespace {
 | |
| 
 | |
| // protects num_identities_reused
 | |
| static absl::base_internal::SpinLock map_lock(
 | |
|     absl::base_internal::kLinkerInitialized);
 | |
| static int num_identities_reused;
 | |
| 
 | |
| static const void* const kCheckNoIdentity = reinterpret_cast<void*>(1);
 | |
| 
 | |
| static void TestThreadIdentityCurrent(const void* assert_no_identity) {
 | |
|   ThreadIdentity* identity;
 | |
| 
 | |
|   // We have to test this conditionally, because if the test framework relies
 | |
|   // on Abseil, then some previous action may have already allocated an
 | |
|   // identity.
 | |
|   if (assert_no_identity == kCheckNoIdentity) {
 | |
|     identity = CurrentThreadIdentityIfPresent();
 | |
|     EXPECT_TRUE(identity == nullptr);
 | |
|   }
 | |
| 
 | |
|   identity = synchronization_internal::GetOrCreateCurrentThreadIdentity();
 | |
|   EXPECT_TRUE(identity != nullptr);
 | |
|   ThreadIdentity* identity_no_init;
 | |
|   identity_no_init = CurrentThreadIdentityIfPresent();
 | |
|   EXPECT_TRUE(identity == identity_no_init);
 | |
| 
 | |
|   // Check that per_thread_synch is correctly aligned.
 | |
|   EXPECT_EQ(0, reinterpret_cast<intptr_t>(&identity->per_thread_synch) %
 | |
|                    PerThreadSynch::kAlignment);
 | |
|   EXPECT_EQ(identity, identity->per_thread_synch.thread_identity());
 | |
| 
 | |
|   absl::base_internal::SpinLockHolder l(&map_lock);
 | |
|   num_identities_reused++;
 | |
| }
 | |
| 
 | |
| TEST(ThreadIdentityTest, BasicIdentityWorks) {
 | |
|   // This tests for the main() thread.
 | |
|   TestThreadIdentityCurrent(nullptr);
 | |
| }
 | |
| 
 | |
| TEST(ThreadIdentityTest, BasicIdentityWorksThreaded) {
 | |
|   // Now try the same basic test with multiple threads being created and
 | |
|   // destroyed.  This makes sure that:
 | |
|   // - New threads are created without a ThreadIdentity.
 | |
|   // - We re-allocate ThreadIdentity objects from the free-list.
 | |
|   // - If a thread implementation chooses to recycle threads, that
 | |
|   //   correct re-initialization occurs.
 | |
|   static const int kNumLoops = 3;
 | |
|   static const int kNumThreads = 400;
 | |
|   for (int iter = 0; iter < kNumLoops; iter++) {
 | |
|     std::vector<std::thread> threads;
 | |
|     for (int i = 0; i < kNumThreads; ++i) {
 | |
|       threads.push_back(
 | |
|           std::thread(TestThreadIdentityCurrent, kCheckNoIdentity));
 | |
|     }
 | |
|     for (auto& thread : threads) {
 | |
|       thread.join();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // We should have recycled ThreadIdentity objects above; while (external)
 | |
|   // library threads allocating their own identities may preclude some
 | |
|   // reuse, we should have sufficient repetitions to exclude this.
 | |
|   EXPECT_LT(kNumThreads, num_identities_reused);
 | |
| }
 | |
| 
 | |
| TEST(ThreadIdentityTest, ReusedThreadIdentityMutexTest) {
 | |
|   // This test repeatly creates and joins a series of threads, each of
 | |
|   // which acquires and releases shared Mutex locks. This verifies
 | |
|   // Mutex operations work correctly under a reused
 | |
|   // ThreadIdentity. Note that the most likely failure mode of this
 | |
|   // test is a crash or deadlock.
 | |
|   static const int kNumLoops = 10;
 | |
|   static const int kNumThreads = 12;
 | |
|   static const int kNumMutexes = 3;
 | |
|   static const int kNumLockLoops = 5;
 | |
| 
 | |
|   Mutex mutexes[kNumMutexes];
 | |
|   for (int iter = 0; iter < kNumLoops; ++iter) {
 | |
|     std::vector<std::thread> threads;
 | |
|     for (int thread = 0; thread < kNumThreads; ++thread) {
 | |
|       threads.push_back(std::thread([&]() {
 | |
|         for (int l = 0; l < kNumLockLoops; ++l) {
 | |
|           for (int m = 0; m < kNumMutexes; ++m) {
 | |
|             MutexLock lock(&mutexes[m]);
 | |
|           }
 | |
|         }
 | |
|       }));
 | |
|     }
 | |
|     for (auto& thread : threads) {
 | |
|       thread.join();
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| }  // namespace
 | |
| }  // namespace base_internal
 | |
| }  // namespace absl
 |