Export of internal Abseil changes.
-- 997d2a8d12d9395046b0bdfc2f206a0b2fe2f1f9 by Abseil Team <absl-team@google.com>: Typo fix: IsHashCallble -> IsHashCallable PiperOrigin-RevId: 245235915 -- 2baa4df2e3284df925bfd728bab7d7bd60ae002e by Eric Fiselier <ericwf@google.com>: Remove need for `Windows.h` header in `waiter.h` Ideally we never want to drag in `windows.h` because it's non-modular and hijacks global identifiers like `ERROR` and `OPAQUE`. This patch changes our waiter implementation to store char buffers for `SRWLOCK` and `CONDITION_VARIABLE` instead of the types directly. PiperOrigin-RevId: 245189428 -- 33cfacd70c0d148d7590472dbcce38c93f2f7a34 by Matthew Brown <matthewbr@google.com>: Internal change. PiperOrigin-RevId: 245092803 GitOrigin-RevId: 997d2a8d12d9395046b0bdfc2f206a0b2fe2f1f9 Change-Id: Icccd6cbe4b205096f6a71e114d135303ee4c1857
This commit is contained in:
		
							parent
							
								
									33841c5c96
								
							
						
					
					
						commit
						cd86d0d20a
					
				
					 4 changed files with 70 additions and 17 deletions
				
			
		|  | @ -35,10 +35,10 @@ cc_library( | ||||||
|     copts = ABSL_DEFAULT_COPTS, |     copts = ABSL_DEFAULT_COPTS, | ||||||
|     linkopts = ABSL_DEFAULT_LINKOPTS, |     linkopts = ABSL_DEFAULT_LINKOPTS, | ||||||
|     deps = [ |     deps = [ | ||||||
|         ":city", |  | ||||||
|         "//absl/base:core_headers", |         "//absl/base:core_headers", | ||||||
|         "//absl/base:endian", |         "//absl/base:endian", | ||||||
|         "//absl/container:fixed_array", |         "//absl/container:fixed_array", | ||||||
|  |         "//absl/hash:city", | ||||||
|         "//absl/meta:type_traits", |         "//absl/meta:type_traits", | ||||||
|         "//absl/numeric:int128", |         "//absl/numeric:int128", | ||||||
|         "//absl/strings", |         "//absl/strings", | ||||||
|  |  | ||||||
|  | @ -425,10 +425,10 @@ TEST(HashValueTest, Maps) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| template <typename T, typename = void> | template <typename T, typename = void> | ||||||
| struct IsHashCallble : std::false_type {}; | struct IsHashCallable : std::false_type {}; | ||||||
| 
 | 
 | ||||||
| template <typename T> | template <typename T> | ||||||
| struct IsHashCallble<T, absl::void_t<decltype(std::declval<absl::Hash<T>>()( | struct IsHashCallable<T, absl::void_t<decltype(std::declval<absl::Hash<T>>()( | ||||||
|                             std::declval<const T&>()))>> : std::true_type {}; |                             std::declval<const T&>()))>> : std::true_type {}; | ||||||
| 
 | 
 | ||||||
| template <typename T, typename = void> | template <typename T, typename = void> | ||||||
|  | @ -445,7 +445,7 @@ TEST(IsHashableTest, ValidHash) { | ||||||
|   EXPECT_TRUE(std::is_move_constructible<absl::Hash<int>>::value); |   EXPECT_TRUE(std::is_move_constructible<absl::Hash<int>>::value); | ||||||
|   EXPECT_TRUE(absl::is_copy_assignable<absl::Hash<int>>::value); |   EXPECT_TRUE(absl::is_copy_assignable<absl::Hash<int>>::value); | ||||||
|   EXPECT_TRUE(absl::is_move_assignable<absl::Hash<int>>::value); |   EXPECT_TRUE(absl::is_move_assignable<absl::Hash<int>>::value); | ||||||
|   EXPECT_TRUE(IsHashCallble<int>::value); |   EXPECT_TRUE(IsHashCallable<int>::value); | ||||||
|   EXPECT_TRUE(IsAggregateInitializable<absl::Hash<int>>::value); |   EXPECT_TRUE(IsAggregateInitializable<absl::Hash<int>>::value); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -458,7 +458,7 @@ TEST(IsHashableTest, PoisonHash) { | ||||||
|   EXPECT_FALSE(std::is_move_constructible<absl::Hash<X>>::value); |   EXPECT_FALSE(std::is_move_constructible<absl::Hash<X>>::value); | ||||||
|   EXPECT_FALSE(absl::is_copy_assignable<absl::Hash<X>>::value); |   EXPECT_FALSE(absl::is_copy_assignable<absl::Hash<X>>::value); | ||||||
|   EXPECT_FALSE(absl::is_move_assignable<absl::Hash<X>>::value); |   EXPECT_FALSE(absl::is_move_assignable<absl::Hash<X>>::value); | ||||||
|   EXPECT_FALSE(IsHashCallble<X>::value); |   EXPECT_FALSE(IsHashCallable<X>::value); | ||||||
|   EXPECT_FALSE(IsAggregateInitializable<absl::Hash<X>>::value); |   EXPECT_FALSE(IsAggregateInitializable<absl::Hash<X>>::value); | ||||||
| } | } | ||||||
| #endif  // ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
 | #endif  // ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
 | ||||||
|  |  | ||||||
|  | @ -40,6 +40,8 @@ | ||||||
| #include <atomic> | #include <atomic> | ||||||
| #include <cassert> | #include <cassert> | ||||||
| #include <cstdint> | #include <cstdint> | ||||||
|  | #include <new> | ||||||
|  | #include <type_traits> | ||||||
| 
 | 
 | ||||||
| #include "absl/base/internal/raw_logging.h" | #include "absl/base/internal/raw_logging.h" | ||||||
| #include "absl/base/internal/thread_identity.h" | #include "absl/base/internal/thread_identity.h" | ||||||
|  | @ -328,6 +330,43 @@ void Waiter::Poke() { | ||||||
| 
 | 
 | ||||||
| #elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_WIN32 | #elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_WIN32 | ||||||
| 
 | 
 | ||||||
|  | class Waiter::WinHelper { | ||||||
|  |  public: | ||||||
|  |   static SRWLOCK *GetLock(Waiter *w) { | ||||||
|  |     return reinterpret_cast<SRWLOCK *>(&w->mu_storage_); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static CONDITION_VARIABLE *GetCond(Waiter *w) { | ||||||
|  |     return reinterpret_cast<CONDITION_VARIABLE *>(&w->cv_storage_); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static_assert(sizeof(SRWLOCK) == sizeof(Waiter::SRWLockStorage), | ||||||
|  |                 "SRWLockStorage does not have the same size as SRWLOCK"); | ||||||
|  |   static_assert( | ||||||
|  |       alignof(SRWLOCK) == alignof(Waiter::SRWLockStorage), | ||||||
|  |       "SRWLockStorage does not have the same alignment as SRWLOCK"); | ||||||
|  | 
 | ||||||
|  |   static_assert(sizeof(CONDITION_VARIABLE) == | ||||||
|  |                     sizeof(Waiter::ConditionVariableStorage), | ||||||
|  |                 "ABSL_CONDITION_VARIABLE_STORAGE does not have the same size " | ||||||
|  |                 "as CONDITION_VARIABLE"); | ||||||
|  |   static_assert(alignof(CONDITION_VARIABLE) == | ||||||
|  |                     alignof(Waiter::ConditionVariableStorage), | ||||||
|  |                 "ConditionVariableStorage does not have the same " | ||||||
|  |                 "alignment as CONDITION_VARIABLE"); | ||||||
|  | 
 | ||||||
|  |   // The SRWLOCK and CONDITION_VARIABLE types must be trivially constuctible
 | ||||||
|  |   // and destructible because we never call their constructors or destructors.
 | ||||||
|  |   static_assert(std::is_trivially_constructible<SRWLOCK>::value, | ||||||
|  |                 "The SRWLOCK type must be trivially constructible"); | ||||||
|  |   static_assert(std::is_trivially_constructible<CONDITION_VARIABLE>::value, | ||||||
|  |                 "The CONDITION_VARIABLE type must be trivially constructible"); | ||||||
|  |   static_assert(std::is_trivially_destructible<SRWLOCK>::value, | ||||||
|  |                 "The SRWLOCK type must be trivially destructible"); | ||||||
|  |   static_assert(std::is_trivially_destructible<CONDITION_VARIABLE>::value, | ||||||
|  |                 "The CONDITION_VARIABLE type must be trivially destructible"); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| class LockHolder { | class LockHolder { | ||||||
|  public: |  public: | ||||||
|   explicit LockHolder(SRWLOCK* mu) : mu_(mu) { |   explicit LockHolder(SRWLOCK* mu) : mu_(mu) { | ||||||
|  | @ -346,14 +385,19 @@ class LockHolder { | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| void Waiter::Init() { | void Waiter::Init() { | ||||||
|   InitializeSRWLock(&mu_); |   auto *mu = ::new (static_cast<void *>(&mu_storage_)) SRWLOCK; | ||||||
|   InitializeConditionVariable(&cv_); |   auto *cv = ::new (static_cast<void *>(&cv_storage_)) CONDITION_VARIABLE; | ||||||
|  |   InitializeSRWLock(mu); | ||||||
|  |   InitializeConditionVariable(cv); | ||||||
|   waiter_count_.store(0, std::memory_order_relaxed); |   waiter_count_.store(0, std::memory_order_relaxed); | ||||||
|   wakeup_count_.store(0, std::memory_order_relaxed); |   wakeup_count_.store(0, std::memory_order_relaxed); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool Waiter::Wait(KernelTimeout t) { | bool Waiter::Wait(KernelTimeout t) { | ||||||
|   LockHolder h(&mu_); |   SRWLOCK *mu = WinHelper::GetLock(this); | ||||||
|  |   CONDITION_VARIABLE *cv = WinHelper::GetCond(this); | ||||||
|  | 
 | ||||||
|  |   LockHolder h(mu); | ||||||
|   waiter_count_.fetch_add(1, std::memory_order_relaxed); |   waiter_count_.fetch_add(1, std::memory_order_relaxed); | ||||||
| 
 | 
 | ||||||
|   // Loop until we find a wakeup to consume or timeout.
 |   // Loop until we find a wakeup to consume or timeout.
 | ||||||
|  | @ -371,8 +415,7 @@ bool Waiter::Wait(KernelTimeout t) { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // No wakeups available, time to wait.
 |     // No wakeups available, time to wait.
 | ||||||
|     if (!SleepConditionVariableSRW( |     if (!SleepConditionVariableSRW(cv, mu, t.InMillisecondsFromNow(), 0)) { | ||||||
|             &cv_, &mu_, t.InMillisecondsFromNow(), 0)) { |  | ||||||
|       // GetLastError() returns a Win32 DWORD, but we assign to
 |       // GetLastError() returns a Win32 DWORD, but we assign to
 | ||||||
|       // unsigned long to simplify the ABSL_RAW_LOG case below.  The uniform
 |       // unsigned long to simplify the ABSL_RAW_LOG case below.  The uniform
 | ||||||
|       // initialization guarantees this is not a narrowing conversion.
 |       // initialization guarantees this is not a narrowing conversion.
 | ||||||
|  | @ -399,11 +442,11 @@ void Waiter::Poke() { | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|   // Potentially a waker. Take the lock and check again.
 |   // Potentially a waker. Take the lock and check again.
 | ||||||
|   LockHolder h(&mu_); |   LockHolder h(WinHelper::GetLock(this)); | ||||||
|   if (waiter_count_.load(std::memory_order_relaxed) == 0) { |   if (waiter_count_.load(std::memory_order_relaxed) == 0) { | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|   WakeConditionVariable(&cv_); |   WakeConditionVariable(WinHelper::GetCond(this)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #else | #else | ||||||
|  |  | ||||||
|  | @ -18,9 +18,7 @@ | ||||||
| 
 | 
 | ||||||
| #include "absl/base/config.h" | #include "absl/base/config.h" | ||||||
| 
 | 
 | ||||||
| #ifdef _WIN32 | #ifndef _WIN32 | ||||||
| #include <windows.h> |  | ||||||
| #else |  | ||||||
| #include <pthread.h> | #include <pthread.h> | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | @ -123,8 +121,20 @@ class Waiter { | ||||||
|   // primivitives.  We are using SRWLOCK and CONDITION_VARIABLE
 |   // primivitives.  We are using SRWLOCK and CONDITION_VARIABLE
 | ||||||
|   // because they don't require a destructor to release system
 |   // because they don't require a destructor to release system
 | ||||||
|   // resources.
 |   // resources.
 | ||||||
|   SRWLOCK mu_; |   //
 | ||||||
|   CONDITION_VARIABLE cv_; |   // However, we can't include Windows.h in our headers, so we use aligned
 | ||||||
|  |   // storage buffers to define the storage.
 | ||||||
|  |   using SRWLockStorage = | ||||||
|  |       typename std::aligned_storage<sizeof(void*), alignof(void*)>::type; | ||||||
|  |   using ConditionVariableStorage = | ||||||
|  |       typename std::aligned_storage<sizeof(void*), alignof(void*)>::type; | ||||||
|  | 
 | ||||||
|  |   // WinHelper - Used to define utilities for accessing the lock and
 | ||||||
|  |   // condition variable storage once the types are complete.
 | ||||||
|  |   class WinHelper; | ||||||
|  | 
 | ||||||
|  |   SRWLockStorage mu_storage_; | ||||||
|  |   ConditionVariableStorage cv_storage_; | ||||||
|   std::atomic<int> waiter_count_; |   std::atomic<int> waiter_count_; | ||||||
|   std::atomic<int> wakeup_count_; |   std::atomic<int> wakeup_count_; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue