diff options
Diffstat (limited to 'absl/base/internal')
39 files changed, 907 insertions, 356 deletions
diff --git a/absl/base/internal/atomic_hook.h b/absl/base/internal/atomic_hook.h index 7d0ee2fa..58ddf272 100644 --- a/absl/base/internal/atomic_hook.h +++ b/absl/base/internal/atomic_hook.h @@ -28,7 +28,7 @@ #endif namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace base_internal { template <typename T> @@ -161,7 +161,7 @@ class AtomicHook<ReturnType (*)(Args...)> { #undef ABSL_HAVE_WORKING_ATOMIC_POINTER } // namespace base_internal -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl #endif // ABSL_BASE_INTERNAL_ATOMIC_HOOK_H_ diff --git a/absl/base/internal/bits.h b/absl/base/internal/bits.h new file mode 100644 index 00000000..29657426 --- /dev/null +++ b/absl/base/internal/bits.h @@ -0,0 +1,195 @@ +// Copyright 2018 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. + +#ifndef ABSL_BASE_INTERNAL_BITS_H_ +#define ABSL_BASE_INTERNAL_BITS_H_ + +// This file contains bitwise ops which are implementation details of various +// absl libraries. + +#include <cstdint> + +// Clang on Windows has __builtin_clzll; otherwise we need to use the +// windows intrinsic functions. +#if defined(_MSC_VER) +#include <intrin.h> +#if defined(_M_X64) +#pragma intrinsic(_BitScanReverse64) +#pragma intrinsic(_BitScanForward64) +#endif +#pragma intrinsic(_BitScanReverse) +#pragma intrinsic(_BitScanForward) +#endif + +#include "absl/base/attributes.h" + +#if defined(_MSC_VER) +// We can achieve something similar to attribute((always_inline)) with MSVC by +// using the __forceinline keyword, however this is not perfect. MSVC is +// much less aggressive about inlining, and even with the __forceinline keyword. +#define ABSL_BASE_INTERNAL_FORCEINLINE __forceinline +#else +// Use default attribute inline. +#define ABSL_BASE_INTERNAL_FORCEINLINE inline ABSL_ATTRIBUTE_ALWAYS_INLINE +#endif + + +namespace absl { +inline namespace lts_2018_12_18 { +namespace base_internal { + +ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64Slow(uint64_t n) { + int zeroes = 60; + if (n >> 32) zeroes -= 32, n >>= 32; + if (n >> 16) zeroes -= 16, n >>= 16; + if (n >> 8) zeroes -= 8, n >>= 8; + if (n >> 4) zeroes -= 4, n >>= 4; + return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[n] + zeroes; +} + +ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64(uint64_t n) { +#if defined(_MSC_VER) && defined(_M_X64) + // MSVC does not have __buitin_clzll. Use _BitScanReverse64. + unsigned long result = 0; // NOLINT(runtime/int) + if (_BitScanReverse64(&result, n)) { + return 63 - result; + } + return 64; +#elif defined(_MSC_VER) + // MSVC does not have __buitin_clzll. Compose two calls to _BitScanReverse + unsigned long result = 0; // NOLINT(runtime/int) + if ((n >> 32) && _BitScanReverse(&result, n >> 32)) { + return 31 - result; + } + if (_BitScanReverse(&result, n)) { + return 63 - result; + } + return 64; +#elif defined(__GNUC__) + // Use __builtin_clzll, which uses the following instructions: + // x86: bsr + // ARM64: clz + // PPC: cntlzd + static_assert(sizeof(unsigned long long) == sizeof(n), // NOLINT(runtime/int) + "__builtin_clzll does not take 64-bit arg"); + + // Handle 0 as a special case because __builtin_clzll(0) is undefined. + if (n == 0) { + return 64; + } + return __builtin_clzll(n); +#else + return CountLeadingZeros64Slow(n); +#endif +} + +ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros32Slow(uint64_t n) { + int zeroes = 28; + if (n >> 16) zeroes -= 16, n >>= 16; + if (n >> 8) zeroes -= 8, n >>= 8; + if (n >> 4) zeroes -= 4, n >>= 4; + return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[n] + zeroes; +} + +ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros32(uint32_t n) { +#if defined(_MSC_VER) + unsigned long result = 0; // NOLINT(runtime/int) + if (_BitScanReverse(&result, n)) { + return 31 - result; + } + return 32; +#elif defined(__GNUC__) + // Use __builtin_clz, which uses the following instructions: + // x86: bsr + // ARM64: clz + // PPC: cntlzd + static_assert(sizeof(int) == sizeof(n), + "__builtin_clz does not take 32-bit arg"); + + // Handle 0 as a special case because __builtin_clz(0) is undefined. + if (n == 0) { + return 32; + } + return __builtin_clz(n); +#else + return CountLeadingZeros32Slow(n); +#endif +} + +ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero64Slow(uint64_t n) { + int c = 63; + n &= ~n + 1; + if (n & 0x00000000FFFFFFFF) c -= 32; + if (n & 0x0000FFFF0000FFFF) c -= 16; + if (n & 0x00FF00FF00FF00FF) c -= 8; + if (n & 0x0F0F0F0F0F0F0F0F) c -= 4; + if (n & 0x3333333333333333) c -= 2; + if (n & 0x5555555555555555) c -= 1; + return c; +} + +ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero64(uint64_t n) { +#if defined(_MSC_VER) && defined(_M_X64) + unsigned long result = 0; // NOLINT(runtime/int) + _BitScanForward64(&result, n); + return result; +#elif defined(_MSC_VER) + unsigned long result = 0; // NOLINT(runtime/int) + if (static_cast<uint32_t>(n) == 0) { + _BitScanForward(&result, n >> 32); + return result + 32; + } + _BitScanForward(&result, n); + return result; +#elif defined(__GNUC__) + static_assert(sizeof(unsigned long long) == sizeof(n), // NOLINT(runtime/int) + "__builtin_ctzll does not take 64-bit arg"); + return __builtin_ctzll(n); +#else + return CountTrailingZerosNonZero64Slow(n); +#endif +} + +ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero32Slow(uint32_t n) { + int c = 31; + n &= ~n + 1; + if (n & 0x0000FFFF) c -= 16; + if (n & 0x00FF00FF) c -= 8; + if (n & 0x0F0F0F0F) c -= 4; + if (n & 0x33333333) c -= 2; + if (n & 0x55555555) c -= 1; + return c; +} + +ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero32(uint32_t n) { +#if defined(_MSC_VER) + unsigned long result = 0; // NOLINT(runtime/int) + _BitScanForward(&result, n); + return result; +#elif defined(__GNUC__) + static_assert(sizeof(int) == sizeof(n), + "__builtin_ctz does not take 32-bit arg"); + return __builtin_ctz(n); +#else + return CountTrailingZerosNonZero32Slow(n); +#endif +} + +#undef ABSL_BASE_INTERNAL_FORCEINLINE + +} // namespace base_internal +} // inline namespace lts_2018_12_18 +} // namespace absl + +#endif // ABSL_BASE_INTERNAL_BITS_H_ diff --git a/absl/base/internal/bits_test.cc b/absl/base/internal/bits_test.cc new file mode 100644 index 00000000..e5d991d6 --- /dev/null +++ b/absl/base/internal/bits_test.cc @@ -0,0 +1,97 @@ +// Copyright 2018 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/bits.h" + +#include "gtest/gtest.h" + +namespace { + +int CLZ64(uint64_t n) { + int fast = absl::base_internal::CountLeadingZeros64(n); + int slow = absl::base_internal::CountLeadingZeros64Slow(n); + EXPECT_EQ(fast, slow) << n; + return fast; +} + +TEST(BitsTest, CountLeadingZeros64) { + EXPECT_EQ(64, CLZ64(uint64_t{})); + EXPECT_EQ(0, CLZ64(~uint64_t{})); + + for (int index = 0; index < 64; index++) { + uint64_t x = static_cast<uint64_t>(1) << index; + const auto cnt = 63 - index; + ASSERT_EQ(cnt, CLZ64(x)) << index; + ASSERT_EQ(cnt, CLZ64(x + x - 1)) << index; + } +} + +int CLZ32(uint32_t n) { + int fast = absl::base_internal::CountLeadingZeros32(n); + int slow = absl::base_internal::CountLeadingZeros32Slow(n); + EXPECT_EQ(fast, slow) << n; + return fast; +} + +TEST(BitsTest, CountLeadingZeros32) { + EXPECT_EQ(32, CLZ32(uint32_t{})); + EXPECT_EQ(0, CLZ32(~uint32_t{})); + + for (int index = 0; index < 32; index++) { + uint32_t x = static_cast<uint32_t>(1) << index; + const auto cnt = 31 - index; + ASSERT_EQ(cnt, CLZ32(x)) << index; + ASSERT_EQ(cnt, CLZ32(x + x - 1)) << index; + ASSERT_EQ(CLZ64(x), CLZ32(x) + 32); + } +} + +int CTZ64(uint64_t n) { + int fast = absl::base_internal::CountTrailingZerosNonZero64(n); + int slow = absl::base_internal::CountTrailingZerosNonZero64Slow(n); + EXPECT_EQ(fast, slow) << n; + return fast; +} + +TEST(BitsTest, CountTrailingZerosNonZero64) { + EXPECT_EQ(0, CTZ64(~uint64_t{})); + + for (int index = 0; index < 64; index++) { + uint64_t x = static_cast<uint64_t>(1) << index; + const auto cnt = index; + ASSERT_EQ(cnt, CTZ64(x)) << index; + ASSERT_EQ(cnt, CTZ64(~(x - 1))) << index; + } +} + +int CTZ32(uint32_t n) { + int fast = absl::base_internal::CountTrailingZerosNonZero32(n); + int slow = absl::base_internal::CountTrailingZerosNonZero32Slow(n); + EXPECT_EQ(fast, slow) << n; + return fast; +} + +TEST(BitsTest, CountTrailingZerosNonZero32) { + EXPECT_EQ(0, CTZ32(~uint32_t{})); + + for (int index = 0; index < 32; index++) { + uint32_t x = static_cast<uint32_t>(1) << index; + const auto cnt = index; + ASSERT_EQ(cnt, CTZ32(x)) << index; + ASSERT_EQ(cnt, CTZ32(~(x - 1))) << index; + } +} + + +} // namespace diff --git a/absl/base/internal/cycleclock.cc b/absl/base/internal/cycleclock.cc index a4f1fc21..d99b63d3 100644 --- a/absl/base/internal/cycleclock.cc +++ b/absl/base/internal/cycleclock.cc @@ -27,7 +27,7 @@ #include "absl/base/internal/unscaledcycleclock.h" namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace base_internal { #if ABSL_USE_UNSCALED_CYCLECLOCK @@ -79,5 +79,5 @@ double CycleClock::Frequency() { #endif } // namespace base_internal -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl diff --git a/absl/base/internal/cycleclock.h b/absl/base/internal/cycleclock.h index 5fd8b348..ae5ede3e 100644 --- a/absl/base/internal/cycleclock.h +++ b/absl/base/internal/cycleclock.h @@ -46,7 +46,7 @@ #include <cstdint> namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace base_internal { // ----------------------------------------------------------------------------- @@ -73,7 +73,7 @@ class CycleClock { }; } // namespace base_internal -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl #endif // ABSL_BASE_INTERNAL_CYCLECLOCK_H_ diff --git a/absl/base/internal/direct_mmap.h b/absl/base/internal/direct_mmap.h index e98c9960..f064e363 100644 --- a/absl/base/internal/direct_mmap.h +++ b/absl/base/internal/direct_mmap.h @@ -62,7 +62,7 @@ extern "C" void* __mmap2(void*, size_t, int, int, int, size_t); #endif // __BIONIC__ namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace base_internal { // Platform specific logic extracted from @@ -76,7 +76,11 @@ inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd, // On these architectures, implement mmap with mmap2. static int pagesize = 0; if (pagesize == 0) { +#if defined(__wasm__) || defined(__asmjs__) pagesize = getpagesize(); +#else + pagesize = sysconf(_SC_PAGESIZE); +#endif } if (offset < 0 || offset % pagesize != 0) { errno = EINVAL; @@ -93,11 +97,13 @@ inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd, #endif #elif defined(__s390x__) // On s390x, mmap() arguments are passed in memory. - uint32_t buf[6] = { - reinterpret_cast<uint32_t>(start), static_cast<uint32_t>(length), - static_cast<uint32_t>(prot), static_cast<uint32_t>(flags), - static_cast<uint32_t>(fd), static_cast<uint32_t>(offset)}; - return reintrepret_cast<void*>(syscall(SYS_mmap, buf)); + unsigned long buf[6] = {reinterpret_cast<unsigned long>(start), // NOLINT + static_cast<unsigned long>(length), // NOLINT + static_cast<unsigned long>(prot), // NOLINT + static_cast<unsigned long>(flags), // NOLINT + static_cast<unsigned long>(fd), // NOLINT + static_cast<unsigned long>(offset)}; // NOLINT + return reinterpret_cast<void*>(syscall(SYS_mmap, buf)); #elif defined(__x86_64__) // The x32 ABI has 32 bit longs, but the syscall interface is 64 bit. // We need to explicitly cast to an unsigned 64 bit type to avoid implicit @@ -123,7 +129,7 @@ inline int DirectMunmap(void* start, size_t length) { } } // namespace base_internal -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl #else // !__linux__ @@ -132,7 +138,7 @@ inline int DirectMunmap(void* start, size_t length) { // actual mmap()/munmap() methods. namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace base_internal { inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd, @@ -145,7 +151,7 @@ inline int DirectMunmap(void* start, size_t length) { } } // namespace base_internal -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl #endif // __linux__ diff --git a/absl/base/internal/endian.h b/absl/base/internal/endian.h index 00447110..52c09c5b 100644 --- a/absl/base/internal/endian.h +++ b/absl/base/internal/endian.h @@ -34,7 +34,7 @@ #include "absl/base/port.h" namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { // Use compiler byte-swapping intrinsics if they are available. 32-bit // and 64-bit versions are available in Clang and GCC as of GCC 4.3.0. @@ -83,14 +83,14 @@ inline uint64_t gbswap_64(uint64_t host_int) { #elif defined(__GLIBC__) return bswap_64(host_int); #else - return (((x & uint64_t{(0xFF}) << 56) | - ((x & uint64_t{(0xFF00}) << 40) | - ((x & uint64_t{(0xFF0000}) << 24) | - ((x & uint64_t{(0xFF000000}) << 8) | - ((x & uint64_t{(0xFF00000000}) >> 8) | - ((x & uint64_t{(0xFF0000000000}) >> 24) | - ((x & uint64_t{(0xFF000000000000}) >> 40) | - ((x & uint64_t{(0xFF00000000000000}) >> 56)); + return (((host_int & uint64_t{0xFF}) << 56) | + ((host_int & uint64_t{0xFF00}) << 40) | + ((host_int & uint64_t{0xFF0000}) << 24) | + ((host_int & uint64_t{0xFF000000}) << 8) | + ((host_int & uint64_t{0xFF00000000}) >> 8) | + ((host_int & uint64_t{0xFF0000000000}) >> 24) | + ((host_int & uint64_t{0xFF000000000000}) >> 40) | + ((host_int & uint64_t{0xFF00000000000000}) >> 56)); #endif // bswap_64 } @@ -98,8 +98,10 @@ inline uint32_t gbswap_32(uint32_t host_int) { #if defined(__GLIBC__) return bswap_32(host_int); #else - return (((x & 0xFF) << 24) | ((x & 0xFF00) << 8) | ((x & 0xFF0000) >> 8) | - ((x & 0xFF000000) >> 24)); + return (((host_int & uint32_t{0xFF}) << 24) | + ((host_int & uint32_t{0xFF00}) << 8) | + ((host_int & uint32_t{0xFF0000}) >> 8) | + ((host_int & uint32_t{0xFF000000}) >> 24)); #endif } @@ -107,7 +109,8 @@ inline uint16_t gbswap_16(uint16_t host_int) { #if defined(__GLIBC__) return bswap_16(host_int); #else - return uint16_t{((x & 0xFF) << 8) | ((x & 0xFF00) >> 8)}; + return (((host_int & uint16_t{0xFF}) << 8) | + ((host_int & uint16_t{0xFF00}) >> 8)); #endif } @@ -265,7 +268,7 @@ inline void Store64(void *p, uint64_t v) { } // namespace big_endian -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl #endif // ABSL_BASE_INTERNAL_ENDIAN_H_ diff --git a/absl/base/internal/endian_test.cc b/absl/base/internal/endian_test.cc index 66ccd45a..14ac4765 100644 --- a/absl/base/internal/endian_test.cc +++ b/absl/base/internal/endian_test.cc @@ -24,7 +24,7 @@ #include "absl/base/config.h" namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace { const uint64_t kInitialNumber{0x0123456789abcdef}; @@ -34,32 +34,16 @@ const uint16_t k16Value{0x0123}; const int kNumValuesToTest = 1000000; const int kRandomSeed = 12345; -#ifdef ABSL_IS_BIG_ENDIAN +#if defined(ABSL_IS_BIG_ENDIAN) const uint64_t kInitialInNetworkOrder{kInitialNumber}; const uint64_t k64ValueLE{0xefcdab8967452301}; const uint32_t k32ValueLE{0x67452301}; const uint16_t k16ValueLE{0x2301}; -const uint8_t k8ValueLE{k8Value}; -const uint64_t k64IValueLE{0xefcdab89674523a1}; -const uint32_t k32IValueLE{0x67452391}; -const uint16_t k16IValueLE{0x85ff}; -const uint8_t k8IValueLE{0xff}; -const uint64_t kDoubleValueLE{0x6e861bf0f9210940}; -const uint32_t kFloatValueLE{0xd00f4940}; -const uint8_t kBoolValueLE{0x1}; const uint64_t k64ValueBE{kInitialNumber}; const uint32_t k32ValueBE{k32Value}; const uint16_t k16ValueBE{k16Value}; -const uint8_t k8ValueBE{k8Value}; -const uint64_t k64IValueBE{0xa123456789abcdef}; -const uint32_t k32IValueBE{0x91234567}; -const uint16_t k16IValueBE{0xff85}; -const uint8_t k8IValueBE{0xff}; -const uint64_t kDoubleValueBE{0x400921f9f01b866e}; -const uint32_t kFloatValueBE{0x40490fd0}; -const uint8_t kBoolValueBE{0x1}; -#elif defined ABSL_IS_LITTLE_ENDIAN +#elif defined(ABSL_IS_LITTLE_ENDIAN) const uint64_t kInitialInNetworkOrder{0xefcdab8967452301}; const uint64_t k64ValueLE{kInitialNumber}; const uint32_t k32ValueLE{k32Value}; @@ -277,5 +261,5 @@ TEST(EndianessTest, big_endian) { } } // namespace -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl diff --git a/absl/base/internal/exception_safety_testing.cc b/absl/base/internal/exception_safety_testing.cc index f1d081f7..8207b7d7 100644 --- a/absl/base/internal/exception_safety_testing.cc +++ b/absl/base/internal/exception_safety_testing.cc @@ -23,6 +23,10 @@ exceptions_internal::NoThrowTag nothrow_ctor; exceptions_internal::StrongGuaranteeTagType strong_guarantee; +exceptions_internal::ExceptionSafetyTestBuilder<> MakeExceptionSafetyTester() { + return {}; +} + namespace exceptions_internal { int countdown = -1; diff --git a/absl/base/internal/exception_safety_testing.h b/absl/base/internal/exception_safety_testing.h index 8c2f5093..d4d41a8a 100644 --- a/absl/base/internal/exception_safety_testing.h +++ b/absl/base/internal/exception_safety_testing.h @@ -33,7 +33,7 @@ #include "absl/meta/type_traits.h" #include "absl/strings/string_view.h" #include "absl/strings/substitute.h" -#include "absl/types/optional.h" +#include "absl/utility/utility.h" namespace testing { @@ -127,10 +127,8 @@ class ConstructorTracker { void* address = it.first; TrackedAddress& tracked_address = it.second; if (tracked_address.is_alive) { - ADD_FAILURE() << "Object at address " << address - << " with countdown of " << countdown_ - << " was not destroyed [" << tracked_address.description - << "]"; + ADD_FAILURE() << ErrorMessage(address, tracked_address.description, + countdown_, "Object was not destroyed."); } } } @@ -141,11 +139,11 @@ class ConstructorTracker { TrackedAddress& tracked_address = current_tracker_instance_->address_map_[address]; if (tracked_address.is_alive) { - ADD_FAILURE() << "Object at address " << address << " with countdown of " - << current_tracker_instance_->countdown_ - << " was re-constructed. Previously: [" - << tracked_address.description << "] Now: [" << description - << "]"; + ADD_FAILURE() << ErrorMessage( + address, tracked_address.description, + current_tracker_instance_->countdown_, + "Object was re-constructed. Current object was constructed by " + + description); } tracked_address = {true, std::move(description)}; } @@ -159,10 +157,9 @@ class ConstructorTracker { TrackedAddress& tracked_address = it->second; if (!tracked_address.is_alive) { - ADD_FAILURE() << "Object at address " << address << " with countdown of " - << current_tracker_instance_->countdown_ - << " was re-destroyed or created prior to construction " - << "tracking [" << tracked_address.description << "]"; + ADD_FAILURE() << ErrorMessage(address, tracked_address.description, + current_tracker_instance_->countdown_, + "Object was re-destroyed."); } tracked_address.is_alive = false; } @@ -172,6 +169,16 @@ class ConstructorTracker { return current_tracker_instance_ != nullptr; } + static std::string ErrorMessage(void* address, const std::string& address_description, + int countdown, const std::string& error_description) { + return absl::Substitute( + "With coundtown at $0:\n" + " $1\n" + " Object originally constructed by $2\n" + " Object address: $3\n", + countdown, error_description, address_description, address); + } + std::unordered_map<void*, TrackedAddress> address_map_; int countdown_; @@ -190,70 +197,6 @@ class TrackedObject { ~TrackedObject() noexcept { ConstructorTracker::ObjectDestructed(this); } }; - -template <typename Factory, typename Operation, typename Invariant> -absl::optional<testing::AssertionResult> TestSingleInvariantAtCountdownImpl( - const Factory& factory, const Operation& operation, int count, - const Invariant& invariant) { - auto t_ptr = factory(); - absl::optional<testing::AssertionResult> current_res; - SetCountdown(count); - try { - operation(t_ptr.get()); - } catch (const exceptions_internal::TestException& e) { - current_res.emplace(invariant(t_ptr.get())); - if (!current_res.value()) { - *current_res << e.what() << " failed invariant check"; - } - } - UnsetCountdown(); - return current_res; -} - -template <typename Factory, typename Operation> -absl::optional<testing::AssertionResult> TestSingleInvariantAtCountdownImpl( - const Factory& factory, const Operation& operation, int count, - StrongGuaranteeTagType) { - using TPtr = typename decltype(factory())::pointer; - auto t_is_strong = [&](TPtr t) { return *t == *factory(); }; - return TestSingleInvariantAtCountdownImpl(factory, operation, count, - t_is_strong); -} - -template <typename Factory, typename Operation, typename Invariant> -int TestSingleInvariantAtCountdown( - const Factory& factory, const Operation& operation, int count, - const Invariant& invariant, - absl::optional<testing::AssertionResult>* reduced_res) { - // If reduced_res is empty, it means the current call to - // TestSingleInvariantAtCountdown(...) is the first test being run so we do - // want to run it. Alternatively, if it's not empty (meaning a previous test - // has run) we want to check if it passed. If the previous test did pass, we - // want to contine running tests so we do want to run the current one. If it - // failed, we want to short circuit so as not to overwrite the AssertionResult - // output. If that's the case, we do not run the current test and instead we - // simply return. - if (!reduced_res->has_value() || reduced_res->value()) { - *reduced_res = TestSingleInvariantAtCountdownImpl(factory, operation, count, - invariant); - } - return 0; -} - -template <typename Factory, typename Operation, typename... Invariants> -inline absl::optional<testing::AssertionResult> TestAllInvariantsAtCountdown( - const Factory& factory, const Operation& operation, int count, - const Invariants&... invariants) { - absl::optional<testing::AssertionResult> reduced_res; - - // Run each checker, short circuiting after the first failure - int dummy[] = { - 0, (TestSingleInvariantAtCountdown(factory, operation, count, invariants, - &reduced_res))...}; - static_cast<void>(dummy); - return reduced_res; -} - } // namespace exceptions_internal extern exceptions_internal::NoThrowTag nothrow_ctor; @@ -773,7 +716,7 @@ class ThrowingAllocator : private exceptions_internal::TrackedObject { } size_type max_size() const noexcept { - return std::numeric_limits<difference_type>::max() / sizeof(value_type); + return (std::numeric_limits<difference_type>::max)() / sizeof(value_type); } ThrowingAllocator select_on_container_copy_construction() noexcept( @@ -858,7 +801,7 @@ testing::AssertionResult TestNothrowOp(const Operation& operation) { try { operation(); return testing::AssertionSuccess(); - } catch (exceptions_internal::TestException) { + } catch (const exceptions_internal::TestException&) { return testing::AssertionFailure() << "TestException thrown during call to operation() when nothrow " "guarantee was expected."; @@ -871,7 +814,7 @@ testing::AssertionResult TestNothrowOp(const Operation& operation) { namespace exceptions_internal { -// Dummy struct for ExceptionSafetyTester<> partial state. +// Dummy struct for ExceptionSafetyTestBuilder<> partial state. struct UninitializedT {}; template <typename T> @@ -884,29 +827,106 @@ class DefaultFactory { T t_; }; -template <size_t LazyInvariantsCount, typename LazyFactory, +template <size_t LazyContractsCount, typename LazyFactory, typename LazyOperation> using EnableIfTestable = typename absl::enable_if_t< - LazyInvariantsCount != 0 && + LazyContractsCount != 0 && !std::is_same<LazyFactory, UninitializedT>::value && !std::is_same<LazyOperation, UninitializedT>::value>; template <typename Factory = UninitializedT, - typename Operation = UninitializedT, typename... Invariants> -class ExceptionSafetyTester; + typename Operation = UninitializedT, typename... Contracts> +class ExceptionSafetyTestBuilder; } // namespace exceptions_internal -exceptions_internal::ExceptionSafetyTester<> MakeExceptionSafetyTester(); +/* + * Constructs an empty ExceptionSafetyTestBuilder. All + * ExceptionSafetyTestBuilder objects are immutable and all With[thing] mutation + * methods return new instances of ExceptionSafetyTestBuilder. + * + * In order to test a T for exception safety, a factory for that T, a testable + * operation, and at least one contract callback returning an assertion + * result must be applied using the respective methods. + */ +exceptions_internal::ExceptionSafetyTestBuilder<> MakeExceptionSafetyTester(); namespace exceptions_internal { +template <typename T> +struct IsUniquePtr : std::false_type {}; + +template <typename T, typename D> +struct IsUniquePtr<std::unique_ptr<T, D>> : std::true_type {}; + +template <typename Factory> +struct FactoryPtrTypeHelper { + using type = decltype(std::declval<const Factory&>()()); + + static_assert(IsUniquePtr<type>::value, "Factories must return a unique_ptr"); +}; + +template <typename Factory> +using FactoryPtrType = typename FactoryPtrTypeHelper<Factory>::type; + +template <typename Factory> +using FactoryElementType = typename FactoryPtrType<Factory>::element_type; + +template <typename T> +class ExceptionSafetyTest { + using Factory = std::function<std::unique_ptr<T>()>; + using Operation = std::function<void(T*)>; + using Contract = std::function<AssertionResult(T*)>; + + public: + template <typename... Contracts> + explicit ExceptionSafetyTest(const Factory& f, const Operation& op, + const Contracts&... contracts) + : factory_(f), operation_(op), contracts_{WrapContract(contracts)...} {} + + AssertionResult Test() const { + for (int count = 0;; ++count) { + exceptions_internal::ConstructorTracker ct(count); + + for (const auto& contract : contracts_) { + auto t_ptr = factory_(); + try { + SetCountdown(count); + operation_(t_ptr.get()); + // Unset for the case that the operation throws no exceptions, which + // would leave the countdown set and break the *next* exception safety + // test after this one. + UnsetCountdown(); + return AssertionSuccess(); + } catch (const exceptions_internal::TestException& e) { + if (!contract(t_ptr.get())) { + return AssertionFailure() << e.what() << " failed contract check"; + } + } + } + } + } + + private: + template <typename ContractFn> + Contract WrapContract(const ContractFn& contract) { + return [contract](T* t_ptr) { return AssertionResult(contract(t_ptr)); }; + } + + Contract WrapContract(StrongGuaranteeTagType) { + return [this](T* t_ptr) { return AssertionResult(*factory_() == *t_ptr); }; + } + + Factory factory_; + Operation operation_; + std::vector<Contract> contracts_; +}; /* * Builds a tester object that tests if performing a operation on a T follows - * exception safety guarantees. Verification is done via invariant assertion + * exception safety guarantees. Verification is done via contract assertion * callbacks applied to T instances post-throw. * - * Template parameters for ExceptionSafetyTester: + * Template parameters for ExceptionSafetyTestBuilder: * * - Factory: The factory object (passed in via tester.WithFactory(...) or * tester.WithInitialValue(...)) must be invocable with the signature @@ -921,25 +941,25 @@ namespace exceptions_internal { * fresh T instance so it's free to modify and destroy the T instances as it * pleases. * - * - Invariants...: The invariant assertion callback objects (passed in via - * tester.WithInvariants(...)) must be invocable with the signature + * - Contracts...: The contract assertion callback objects (passed in via + * tester.WithContracts(...)) must be invocable with the signature * `testing::AssertionResult operator()(T*) const` where T is the type being - * tested. Invariant assertion callbacks are provided T instances post-throw. - * They must return testing::AssertionSuccess when the type invariants of the - * provided T instance hold. If the type invariants of the T instance do not + * tested. Contract assertion callbacks are provided T instances post-throw. + * They must return testing::AssertionSuccess when the type contracts of the + * provided T instance hold. If the type contracts of the T instance do not * hold, they must return testing::AssertionFailure. Execution order of - * Invariants... is unspecified. They will each individually get a fresh T + * Contracts... is unspecified. They will each individually get a fresh T * instance so they are free to modify and destroy the T instances as they * please. */ -template <typename Factory, typename Operation, typename... Invariants> -class ExceptionSafetyTester { +template <typename Factory, typename Operation, typename... Contracts> +class ExceptionSafetyTestBuilder { public: /* - * Returns a new ExceptionSafetyTester with an included T factory based on the - * provided T instance. The existing factory will not be included in the newly - * created tester instance. The created factory returns a new T instance by - * copy-constructing the provided const T& t. + * Returns a new ExceptionSafetyTestBuilder with an included T factory based + * on the provided T instance. The existing factory will not be included in + * the newly created tester instance. The created factory returns a new T + * instance by copy-constructing the provided const T& t. * * Preconditions for tester.WithInitialValue(const T& t): * @@ -948,63 +968,63 @@ class ExceptionSafetyTester { * tester.WithFactory(...). */ template <typename T> - ExceptionSafetyTester<DefaultFactory<T>, Operation, Invariants...> + ExceptionSafetyTestBuilder<DefaultFactory<T>, Operation, Contracts...> WithInitialValue(const T& t) const { return WithFactory(DefaultFactory<T>(t)); } /* - * Returns a new ExceptionSafetyTester with the provided T factory included. - * The existing factory will not be included in the newly-created tester - * instance. This method is intended for use with types lacking a copy + * Returns a new ExceptionSafetyTestBuilder with the provided T factory + * included. The existing factory will not be included in the newly-created + * tester instance. This method is intended for use with types lacking a copy * constructor. Types that can be copy-constructed should instead use the * method tester.WithInitialValue(...). */ template <typename NewFactory> - ExceptionSafetyTester<absl::decay_t<NewFactory>, Operation, Invariants...> + ExceptionSafetyTestBuilder<absl::decay_t<NewFactory>, Operation, Contracts...> WithFactory(const NewFactory& new_factory) const { - return {new_factory, operation_, invariants_}; + return {new_factory, operation_, contracts_}; } /* - * Returns a new ExceptionSafetyTester with the provided testable operation - * included. The existing operation will not be included in the newly created - * tester. + * Returns a new ExceptionSafetyTestBuilder with the provided testable + * operation included. The existing operation will not be included in the + * newly created tester. */ template <typename NewOperation> - ExceptionSafetyTester<Factory, absl::decay_t<NewOperation>, Invariants...> + ExceptionSafetyTestBuilder<Factory, absl::decay_t<NewOperation>, Contracts...> WithOperation(const NewOperation& new_operation) const { - return {factory_, new_operation, invariants_}; + return {factory_, new_operation, contracts_}; } /* - * Returns a new ExceptionSafetyTester with the provided MoreInvariants... - * combined with the Invariants... that were already included in the instance - * on which the method was called. Invariants... cannot be removed or replaced - * once added to an ExceptionSafetyTester instance. A fresh object must be - * created in order to get an empty Invariants... list. + * Returns a new ExceptionSafetyTestBuilder with the provided MoreContracts... + * combined with the Contracts... that were already included in the instance + * on which the method was called. Contracts... cannot be removed or replaced + * once added to an ExceptionSafetyTestBuilder instance. A fresh object must + * be created in order to get an empty Contracts... list. * - * In addition to passing in custom invariant assertion callbacks, this method + * In addition to passing in custom contract assertion callbacks, this method * accepts `testing::strong_guarantee` as an argument which checks T instances * post-throw against freshly created T instances via operator== to verify * that any state changes made during the execution of the operation were * properly rolled back. */ - template <typename... MoreInvariants> - ExceptionSafetyTester<Factory, Operation, Invariants..., - absl::decay_t<MoreInvariants>...> - WithInvariants(const MoreInvariants&... more_invariants) const { - return {factory_, operation_, - std::tuple_cat(invariants_, - std::tuple<absl::decay_t<MoreInvariants>...>( - more_invariants...))}; + template <typename... MoreContracts> + ExceptionSafetyTestBuilder<Factory, Operation, Contracts..., + absl::decay_t<MoreContracts>...> + WithContracts(const MoreContracts&... more_contracts) const { + return { + factory_, operation_, + std::tuple_cat(contracts_, std::tuple<absl::decay_t<MoreContracts>...>( + more_contracts...))}; } /* * Returns a testing::AssertionResult that is the reduced result of the * exception safety algorithm. The algorithm short circuits and returns - * AssertionFailure after the first invariant callback returns an - * AssertionFailure. Otherwise, if all invariant callbacks return an + * AssertionFailure after the first contract callback returns an + * AssertionFailure. Otherwise, if all contract callbacks return an * AssertionSuccess, the reduced result is AssertionSuccess. * * The passed-in testable operation will not be saved in a new tester instance @@ -1013,97 +1033,62 @@ class ExceptionSafetyTester { * * Preconditions for tester.Test(const NewOperation& new_operation): * - * - May only be called after at least one invariant assertion callback and a + * - May only be called after at least one contract assertion callback and a * factory or initial value have been provided. */ template < typename NewOperation, - typename = EnableIfTestable<sizeof...(Invariants), Factory, NewOperation>> + typename = EnableIfTestable<sizeof...(Contracts), Factory, NewOperation>> testing::AssertionResult Test(const NewOperation& new_operation) const { - return TestImpl(new_operation, absl::index_sequence_for<Invariants...>()); + return TestImpl(new_operation, absl::index_sequence_for<Contracts...>()); } /* * Returns a testing::AssertionResult that is the reduced result of the * exception safety algorithm. The algorithm short circuits and returns - * AssertionFailure after the first invariant callback returns an - * AssertionFailure. Otherwise, if all invariant callbacks return an + * AssertionFailure after the first contract callback returns an + * AssertionFailure. Otherwise, if all contract callbacks return an * AssertionSuccess, the reduced result is AssertionSuccess. * * Preconditions for tester.Test(): * - * - May only be called after at least one invariant assertion callback, a + * - May only be called after at least one contract assertion callback, a * factory or initial value and a testable operation have been provided. */ - template <typename LazyOperation = Operation, - typename = - EnableIfTestable<sizeof...(Invariants), Factory, LazyOperation>> + template < + typename LazyOperation = Operation, + typename = EnableIfTestable<sizeof...(Contracts), Factory, LazyOperation>> testing::AssertionResult Test() const { - return TestImpl(operation_, absl::index_sequence_for<Invariants...>()); + return Test(operation_); } private: template <typename, typename, typename...> - friend class ExceptionSafetyTester; + friend class ExceptionSafetyTestBuilder; - friend ExceptionSafetyTester<> testing::MakeExceptionSafetyTester(); + friend ExceptionSafetyTestBuilder<> testing::MakeExceptionSafetyTester(); - ExceptionSafetyTester() {} + ExceptionSafetyTestBuilder() {} - ExceptionSafetyTester(const Factory& f, const Operation& o, - const std::tuple<Invariants...>& i) - : factory_(f), operation_(o), invariants_(i) {} + ExceptionSafetyTestBuilder(const Factory& f, const Operation& o, + const std::tuple<Contracts...>& i) + : factory_(f), operation_(o), contracts_(i) {} template <typename SelectedOperation, size_t... Indices> - testing::AssertionResult TestImpl(const SelectedOperation& selected_operation, + testing::AssertionResult TestImpl(SelectedOperation selected_operation, absl::index_sequence<Indices...>) const { - // Starting from 0 and counting upwards until one of the exit conditions is - // hit... - for (int count = 0;; ++count) { - exceptions_internal::ConstructorTracker ct(count); - - // Run the full exception safety test algorithm for the current countdown - auto reduced_res = - TestAllInvariantsAtCountdown(factory_, selected_operation, count, - std::get<Indices>(invariants_)...); - // If there is no value in the optional, no invariants were run because no - // exception was thrown. This means that the test is complete and the loop - // can exit successfully. - if (!reduced_res.has_value()) { - return testing::AssertionSuccess(); - } - // If the optional is not empty and the value is falsy, an invariant check - // failed so the test must exit to propegate the failure. - if (!reduced_res.value()) { - return reduced_res.value(); - } - // If the optional is not empty and the value is not falsy, it means - // exceptions were thrown but the invariants passed so the test must - // continue to run. - } + return ExceptionSafetyTest<FactoryElementType<Factory>>( + factory_, selected_operation, std::get<Indices>(contracts_)...) + .Test(); } Factory factory_; Operation operation_; - std::tuple<Invariants...> invariants_; + std::tuple<Contracts...> contracts_; }; } // namespace exceptions_internal -/* - * Constructs an empty ExceptionSafetyTester. All ExceptionSafetyTester - * objects are immutable and all With[thing] mutation methods return new - * instances of ExceptionSafetyTester. - * - * In order to test a T for exception safety, a factory for that T, a testable - * operation, and at least one invariant callback returning an assertion - * result must be applied using the respective methods. - */ -inline exceptions_internal::ExceptionSafetyTester<> -MakeExceptionSafetyTester() { - return {}; -} - } // namespace testing #endif // ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_ diff --git a/absl/base/internal/exception_testing.h b/absl/base/internal/exception_testing.h index fd89a3f6..0cf7918e 100644 --- a/absl/base/internal/exception_testing.h +++ b/absl/base/internal/exception_testing.h @@ -35,7 +35,7 @@ EXPECT_DEATH(expr, ".*") #else #define ABSL_BASE_INTERNAL_EXPECT_FAIL(expr, exception_t, text) \ - EXPECT_DEATH(expr, text) + EXPECT_DEATH_IF_SUPPORTED(expr, text) #endif diff --git a/absl/base/internal/hide_ptr.h b/absl/base/internal/hide_ptr.h index a2694508..ce390dc4 100644 --- a/absl/base/internal/hide_ptr.h +++ b/absl/base/internal/hide_ptr.h @@ -18,7 +18,7 @@ #include <cstdint> namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace base_internal { // Arbitrary value with high bits set. Xor'ing with it is unlikely @@ -43,7 +43,7 @@ inline T* UnhidePtr(uintptr_t hidden) { } } // namespace base_internal -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl #endif // ABSL_BASE_INTERNAL_HIDE_PTR_H_ diff --git a/absl/base/internal/identity.h b/absl/base/internal/identity.h index 2eaab453..d57c83f4 100644 --- a/absl/base/internal/identity.h +++ b/absl/base/internal/identity.h @@ -17,7 +17,7 @@ #define ABSL_BASE_INTERNAL_IDENTITY_H_ namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace internal { template <typename T> @@ -29,7 +29,7 @@ template <typename T> using identity_t = typename identity<T>::type; } // namespace internal -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl #endif // ABSL_BASE_INTERNAL_IDENTITY_H_ diff --git a/absl/base/internal/inline_variable_testing.h b/absl/base/internal/inline_variable_testing.h index 49fa4ade..be0b0b96 100644 --- a/absl/base/internal/inline_variable_testing.h +++ b/absl/base/internal/inline_variable_testing.h @@ -18,7 +18,7 @@ #include "absl/base/internal/inline_variable.h" namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace inline_variable_testing_internal { struct Foo { @@ -40,7 +40,7 @@ const int& get_int_a(); const int& get_int_b(); } // namespace inline_variable_testing_internal -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl #endif // ABSL_BASE_INLINE_VARIABLE_TESTING_H_ diff --git a/absl/base/internal/invoke.h b/absl/base/internal/invoke.h index bc05a0a3..1372ef50 100644 --- a/absl/base/internal/invoke.h +++ b/absl/base/internal/invoke.h @@ -43,7 +43,7 @@ // top of this file for the API documentation. namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace base_internal { // The five classes below each implement one of the clauses from the definition @@ -184,7 +184,7 @@ InvokeT<F, Args...> Invoke(F&& f, Args&&... args) { std::forward<Args>(args)...); } } // namespace base_internal -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl #endif // ABSL_BASE_INTERNAL_INVOKE_H_ diff --git a/absl/base/internal/low_level_alloc.cc b/absl/base/internal/low_level_alloc.cc index ca6239ad..10d805cc 100644 --- a/absl/base/internal/low_level_alloc.cc +++ b/absl/base/internal/low_level_alloc.cc @@ -63,7 +63,7 @@ #endif // __APPLE__ namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace base_internal { // A first-fit allocator with amortized logarithmic free() time. @@ -209,7 +209,7 @@ struct LowLevelAlloc::Arena { int32_t allocation_count GUARDED_BY(mu); // flags passed to NewArena const uint32_t flags; - // Result of getpagesize() + // Result of sysconf(_SC_PAGESIZE) const size_t pagesize; // Lowest power of two >= max(16, sizeof(AllocList)) const size_t roundup; @@ -325,8 +325,10 @@ size_t GetPageSize() { SYSTEM_INFO system_info; GetSystemInfo(&system_info); return std::max(system_info.dwPageSize, system_info.dwAllocationGranularity); -#else +#elif defined(__wasm__) || defined(__asmjs__) return getpagesize(); +#else + return sysconf(_SC_PAGESIZE); #endif } @@ -402,16 +404,20 @@ bool LowLevelAlloc::DeleteArena(Arena *arena) { ABSL_RAW_CHECK(munmap_result != 0, "LowLevelAlloc::DeleteArena: VitualFree failed"); #else +#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING if ((arena->flags & LowLevelAlloc::kAsyncSignalSafe) == 0) { munmap_result = munmap(region, size); } else { munmap_result = base_internal::DirectMunmap(region, size); } +#else + munmap_result = munmap(region, size); +#endif // ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING if (munmap_result != 0) { ABSL_RAW_LOG(FATAL, "LowLevelAlloc::DeleteArena: munmap failed: %d", errno); } -#endif +#endif // _WIN32 } section.Leave(); arena->~Arena(); @@ -546,6 +552,7 @@ static void *DoAllocWithArena(size_t request, LowLevelAlloc::Arena *arena) { MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); ABSL_RAW_CHECK(new_pages != nullptr, "VirtualAlloc failed"); #else +#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING if ((arena->flags & LowLevelAlloc::kAsyncSignalSafe) != 0) { new_pages = base_internal::DirectMmap(nullptr, new_pages_size, PROT_WRITE|PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); @@ -553,10 +560,15 @@ static void *DoAllocWithArena(size_t request, LowLevelAlloc::Arena *arena) { new_pages = mmap(nullptr, new_pages_size, PROT_WRITE | PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); } +#else + new_pages = mmap(nullptr, new_pages_size, PROT_WRITE | PROT_READ, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); +#endif // ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING if (new_pages == MAP_FAILED) { ABSL_RAW_LOG(FATAL, "mmap error: %d", errno); } -#endif + +#endif // _WIN32 arena->mu.Lock(); s = reinterpret_cast<AllocList *>(new_pages); s->header.size = new_pages_size; @@ -600,7 +612,7 @@ void *LowLevelAlloc::AllocWithArena(size_t request, Arena *arena) { } } // namespace base_internal -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl #endif // ABSL_LOW_LEVEL_ALLOC_MISSING diff --git a/absl/base/internal/low_level_alloc.h b/absl/base/internal/low_level_alloc.h index 3f289571..87cfc934 100644 --- a/absl/base/internal/low_level_alloc.h +++ b/absl/base/internal/low_level_alloc.h @@ -39,10 +39,13 @@ #define ABSL_LOW_LEVEL_ALLOC_MISSING 1 #endif -// Using LowLevelAlloc with kAsyncSignalSafe isn't supported on Windows. +// Using LowLevelAlloc with kAsyncSignalSafe isn't supported on Windows or +// asm.js / WebAssembly. +// See https://kripken.github.io/emscripten-site/docs/porting/pthreads.html +// for more information. #ifdef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING #error ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING cannot be directly set -#elif defined(_WIN32) +#elif defined(_WIN32) || defined(__asmjs__) || defined(__wasm__) #define ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING 1 #endif @@ -51,7 +54,7 @@ #include "absl/base/port.h" namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace base_internal { class LowLevelAlloc { @@ -116,6 +119,6 @@ class LowLevelAlloc { }; } // namespace base_internal -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl #endif // ABSL_BASE_INTERNAL_LOW_LEVEL_ALLOC_H_ diff --git a/absl/base/internal/low_level_alloc_test.cc b/absl/base/internal/low_level_alloc_test.cc index 15ffe298..65bb519d 100644 --- a/absl/base/internal/low_level_alloc_test.cc +++ b/absl/base/internal/low_level_alloc_test.cc @@ -22,7 +22,7 @@ #include <utility> namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace base_internal { namespace { @@ -149,7 +149,7 @@ static struct BeforeMain { } // namespace } // namespace base_internal -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl int main(int argc, char *argv[]) { diff --git a/absl/base/internal/low_level_scheduling.h b/absl/base/internal/low_level_scheduling.h index 2ae464b4..7cb6117e 100644 --- a/absl/base/internal/low_level_scheduling.h +++ b/absl/base/internal/low_level_scheduling.h @@ -28,7 +28,7 @@ extern "C" bool __google_disable_rescheduling(void); extern "C" void __google_enable_rescheduling(bool disable_result); namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace base_internal { class SchedulingHelper; // To allow use of SchedulingGuard. @@ -101,6 +101,6 @@ inline void SchedulingGuard::EnableRescheduling(bool /* disable_result */) { } // namespace base_internal -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl #endif // ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_ diff --git a/absl/base/internal/raw_logging.cc b/absl/base/internal/raw_logging.cc index cd1bbc09..ed8b8d7c 100644 --- a/absl/base/internal/raw_logging.cc +++ b/absl/base/internal/raw_logging.cc @@ -139,7 +139,7 @@ void RawLogVA(absl::LogSeverity severity, const char* file, int line, #endif #ifdef ABSL_MIN_LOG_LEVEL - if (static_cast<int>(severity) < ABSL_MIN_LOG_LEVEL && + if (severity < static_cast<absl::LogSeverity>(ABSL_MIN_LOG_LEVEL) && severity < absl::LogSeverity::kFatal) { enabled = false; } @@ -181,7 +181,7 @@ void RawLogVA(absl::LogSeverity severity, const char* file, int line, } // namespace namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace raw_logging_internal { void SafeWriteToStderr(const char *s, size_t len) { #if defined(ABSL_HAVE_SYSCALL_WRITE) @@ -207,6 +207,15 @@ void RawLog(absl::LogSeverity severity, const char* file, int line, va_end(ap); } +// Non-formatting version of RawLog(). +// +// TODO(gfalcon): When string_view no longer depends on base, change this +// interface to take its message as a string_view instead. +static void DefaultInternalLog(absl::LogSeverity severity, const char* file, + int line, const std::string& message) { + RawLog(severity, file, line, "%s", message.c_str()); +} + bool RawLoggingFullySupported() { #ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED return true; @@ -215,6 +224,13 @@ bool RawLoggingFullySupported() { #endif // !ABSL_LOW_LEVEL_WRITE_SUPPORTED } +ABSL_CONST_INIT absl::base_internal::AtomicHook<InternalLogFunction> + internal_log_function(DefaultInternalLog); + +void RegisterInternalLogFunction(InternalLogFunction func) { + internal_log_function.Store(func); +} + } // namespace raw_logging_internal -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl diff --git a/absl/base/internal/raw_logging.h b/absl/base/internal/raw_logging.h index 04ff0607..2786a3de 100644 --- a/absl/base/internal/raw_logging.h +++ b/absl/base/internal/raw_logging.h @@ -19,7 +19,10 @@ #ifndef ABSL_BASE_INTERNAL_RAW_LOGGING_H_ #define ABSL_BASE_INTERNAL_RAW_LOGGING_H_ +#include <string> + #include "absl/base/attributes.h" +#include "absl/base/internal/atomic_hook.h" #include "absl/base/log_severity.h" #include "absl/base/macros.h" #include "absl/base/port.h" @@ -57,6 +60,34 @@ } \ } while (0) +// ABSL_INTERNAL_LOG and ABSL_INTERNAL_CHECK work like the RAW variants above, +// except that if the richer log library is linked into the binary, we dispatch +// to that instead. This is potentially useful for internal logging and +// assertions, where we are using RAW_LOG neither for its async-signal-safety +// nor for its non-allocating nature, but rather because raw logging has very +// few other dependencies. +// +// The API is a subset of the above: each macro only takes two arguments. Use +// StrCat if you need to build a richer message. +#define ABSL_INTERNAL_LOG(severity, message) \ + do { \ + constexpr const char* absl_raw_logging_internal_basename = \ + ::absl::raw_logging_internal::Basename(__FILE__, \ + sizeof(__FILE__) - 1); \ + ::absl::raw_logging_internal::internal_log_function( \ + ABSL_RAW_LOGGING_INTERNAL_##severity, \ + absl_raw_logging_internal_basename, __LINE__, message); \ + } while (0) + +#define ABSL_INTERNAL_CHECK(condition, message) \ + do { \ + if (ABSL_PREDICT_FALSE(!(condition))) { \ + std::string death_message = "Check " #condition " failed: "; \ + death_message += std::string(message); \ + ABSL_INTERNAL_LOG(FATAL, death_message); \ + } \ + } while (0) + #define ABSL_RAW_LOGGING_INTERNAL_INFO ::absl::LogSeverity::kInfo #define ABSL_RAW_LOGGING_INTERNAL_WARNING ::absl::LogSeverity::kWarning #define ABSL_RAW_LOGGING_INTERNAL_ERROR ::absl::LogSeverity::kError @@ -65,7 +96,7 @@ ::absl::NormalizeLogSeverity(severity) namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace raw_logging_internal { // Helper function to implement ABSL_RAW_LOG @@ -84,7 +115,7 @@ void SafeWriteToStderr(const char *s, size_t len); // compile-time function to get the "base" filename, that is, the part of // a filename after the last "/" or "\" path separator. The search starts at -// the end of the std::string; the second parameter is the length of the std::string. +// the end of the string; the second parameter is the length of the string. constexpr const char* Basename(const char* fname, int offset) { return offset == 0 || fname[offset - 1] == '/' || fname[offset - 1] == '\\' ? fname + offset @@ -132,8 +163,20 @@ using LogPrefixHook = bool (*)(absl::LogSeverity severity, const char* file, using AbortHook = void (*)(const char* file, int line, const char* buf_start, const char* prefix_end, const char* buf_end); +// Internal logging function for ABSL_INTERNAL_LOG to dispatch to. +// +// TODO(gfalcon): When string_view no longer depends on base, change this +// interface to take its message as a string_view instead. +using InternalLogFunction = void (*)(absl::LogSeverity severity, + const char* file, int line, + const std::string& message); + +extern base_internal::AtomicHook<InternalLogFunction> internal_log_function; + +void RegisterInternalLogFunction(InternalLogFunction func); + } // namespace raw_logging_internal -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl #endif // ABSL_BASE_INTERNAL_RAW_LOGGING_H_ diff --git a/absl/base/internal/scheduling_mode.h b/absl/base/internal/scheduling_mode.h index dd7df6bb..19a7514c 100644 --- a/absl/base/internal/scheduling_mode.h +++ b/absl/base/internal/scheduling_mode.h @@ -19,7 +19,7 @@ #define ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_ namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace base_internal { // Used to describe how a thread may be scheduled. Typically associated with @@ -50,7 +50,7 @@ enum SchedulingMode { }; } // namespace base_internal -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl #endif // ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_ diff --git a/absl/base/internal/spinlock.cc b/absl/base/internal/spinlock.cc index 9d90b3cb..8f8eef82 100644 --- a/absl/base/internal/spinlock.cc +++ b/absl/base/internal/spinlock.cc @@ -54,7 +54,7 @@ // holder to acquire the lock. There may be outstanding waiter(s). namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace base_internal { ABSL_CONST_INIT static base_internal::AtomicHook<void (*)(const void *lock, @@ -96,13 +96,9 @@ void SpinLock::InitLinkerInitializedAndCooperative() { } // Monitor the lock to see if its value changes within some time period -// (adaptive_spin_count loop iterations). A timestamp indicating -// when the thread initially started waiting for the lock is passed in via -// the initial_wait_timestamp value. The total wait time in cycles for the -// lock is returned in the wait_cycles parameter. The last value read -// from the lock is returned from the method. -uint32_t SpinLock::SpinLoop(int64_t initial_wait_timestamp, - uint32_t *wait_cycles) { +// (adaptive_spin_count loop iterations). The last value read from the lock +// is returned from the method. +uint32_t SpinLock::SpinLoop() { // We are already in the slow path of SpinLock, initialize the // adaptive_spin_count here. ABSL_CONST_INIT static absl::once_flag init_adaptive_spin_count; @@ -116,22 +112,21 @@ uint32_t SpinLock::SpinLoop(int64_t initial_wait_timestamp, do { lock_value = lockword_.load(std::memory_order_relaxed); } while ((lock_value & kSpinLockHeld) != 0 && --c > 0); - uint32_t spin_loop_wait_cycles = - EncodeWaitCycles(initial_wait_timestamp, CycleClock::Now()); - *wait_cycles = spin_loop_wait_cycles; - - return TryLockInternal(lock_value, spin_loop_wait_cycles); + return lock_value; } void SpinLock::SlowLock() { + uint32_t lock_value = SpinLoop(); + lock_value = TryLockInternal(lock_value, 0); + if ((lock_value & kSpinLockHeld) == 0) { + return; + } // The lock was not obtained initially, so this thread needs to wait for // it. Record the current timestamp in the local variable wait_start_time // so the total wait time can be stored in the lockword once this thread // obtains the lock. int64_t wait_start_time = CycleClock::Now(); - uint32_t wait_cycles; - uint32_t lock_value = SpinLoop(wait_start_time, &wait_cycles); - + uint32_t wait_cycles = 0; int lock_wait_call_count = 0; while ((lock_value & kSpinLockHeld) != 0) { // If the lock is currently held, but not marked as having a sleeper, mark @@ -142,7 +137,7 @@ void SpinLock::SlowLock() { // owner to think it experienced contention. if (lockword_.compare_exchange_strong( lock_value, lock_value | kSpinLockSleeper, - std::memory_order_acquire, std::memory_order_relaxed)) { + std::memory_order_relaxed, std::memory_order_relaxed)) { // Successfully transitioned to kSpinLockSleeper. Pass // kSpinLockSleeper to the SpinLockWait routine to properly indicate // the last lock_value observed. @@ -171,7 +166,9 @@ void SpinLock::SlowLock() { ABSL_TSAN_MUTEX_POST_DIVERT(this, 0); // Spin again after returning from the wait routine to give this thread // some chance of obtaining the lock. - lock_value = SpinLoop(wait_start_time, &wait_cycles); + lock_value = SpinLoop(); + wait_cycles = EncodeWaitCycles(wait_start_time, CycleClock::Now()); + lock_value = TryLockInternal(lock_value, wait_cycles); } } @@ -207,14 +204,20 @@ uint32_t SpinLock::EncodeWaitCycles(int64_t wait_start_time, (wait_end_time - wait_start_time) >> PROFILE_TIMESTAMP_SHIFT; // Return a representation of the time spent waiting that can be stored in - // the lock word's upper bits. bit_cast is required as Atomic32 is signed. - const uint32_t clamped = static_cast<uint32_t>( + // the lock word's upper bits. + uint32_t clamped = static_cast<uint32_t>( std::min(scaled_wait_time, kMaxWaitTime) << LOCKWORD_RESERVED_SHIFT); - // bump up value if necessary to avoid returning kSpinLockSleeper. - const uint32_t after_spinlock_sleeper = - kSpinLockSleeper + (1 << LOCKWORD_RESERVED_SHIFT); - return clamped == kSpinLockSleeper ? after_spinlock_sleeper : clamped; + if (clamped == 0) { + return kSpinLockSleeper; // Just wake waiters, but don't record contention. + } + // Bump up value if necessary to avoid returning kSpinLockSleeper. + const uint32_t kMinWaitTime = + kSpinLockSleeper + (1 << LOCKWORD_RESERVED_SHIFT); + if (clamped == kSpinLockSleeper) { + return kMinWaitTime; + } + return clamped; } uint64_t SpinLock::DecodeWaitCycles(uint32_t lock_value) { @@ -226,5 +229,5 @@ uint64_t SpinLock::DecodeWaitCycles(uint32_t lock_value) { } } // namespace base_internal -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl diff --git a/absl/base/internal/spinlock.h b/absl/base/internal/spinlock.h index 7b59fe26..d53878b2 100644 --- a/absl/base/internal/spinlock.h +++ b/absl/base/internal/spinlock.h @@ -45,7 +45,7 @@ #include "absl/base/thread_annotations.h" namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace base_internal { class LOCKABLE SpinLock { @@ -102,8 +102,8 @@ class LOCKABLE SpinLock { inline void Unlock() UNLOCK_FUNCTION() { ABSL_TSAN_MUTEX_PRE_UNLOCK(this, 0); uint32_t lock_value = lockword_.load(std::memory_order_relaxed); - lockword_.store(lock_value & kSpinLockCooperative, - std::memory_order_release); + lock_value = lockword_.exchange(lock_value & kSpinLockCooperative, + std::memory_order_release); if ((lock_value & kSpinLockDisabledScheduling) != 0) { base_internal::SchedulingGuard::EnableRescheduling(true); @@ -162,7 +162,7 @@ class LOCKABLE SpinLock { void InitLinkerInitializedAndCooperative(); void SlowLock() ABSL_ATTRIBUTE_COLD; void SlowUnlock(uint32_t lock_value) ABSL_ATTRIBUTE_COLD; - uint32_t SpinLoop(int64_t initial_wait_timestamp, uint32_t* wait_cycles); + uint32_t SpinLoop(); inline bool TryLockImpl() { uint32_t lock_value = lockword_.load(std::memory_order_relaxed); @@ -235,7 +235,7 @@ inline uint32_t SpinLock::TryLockInternal(uint32_t lock_value, } } // namespace base_internal -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl #endif // ABSL_BASE_INTERNAL_SPINLOCK_H_ diff --git a/absl/base/internal/spinlock_benchmark.cc b/absl/base/internal/spinlock_benchmark.cc new file mode 100644 index 00000000..907d3e27 --- /dev/null +++ b/absl/base/internal/spinlock_benchmark.cc @@ -0,0 +1,52 @@ +// Copyright 2018 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. + +// See also //absl/synchronization:mutex_benchmark for a comparison of SpinLock +// and Mutex performance under varying levels of contention. + +#include "absl/base/internal/raw_logging.h" +#include "absl/base/internal/scheduling_mode.h" +#include "absl/base/internal/spinlock.h" +#include "absl/synchronization/internal/create_thread_identity.h" +#include "benchmark/benchmark.h" + +namespace { + +template <absl::base_internal::SchedulingMode scheduling_mode> +static void BM_SpinLock(benchmark::State& state) { + // Ensure a ThreadIdentity is installed. + ABSL_INTERNAL_CHECK( + absl::synchronization_internal::GetOrCreateCurrentThreadIdentity() != + nullptr, + "GetOrCreateCurrentThreadIdentity() failed"); + + static auto* spinlock = new absl::base_internal::SpinLock(scheduling_mode); + for (auto _ : state) { + absl::base_internal::SpinLockHolder holder(spinlock); + } +} + +BENCHMARK_TEMPLATE(BM_SpinLock, + absl::base_internal::SCHEDULE_KERNEL_ONLY) + ->UseRealTime() + ->Threads(1) + ->ThreadPerCpu(); + +BENCHMARK_TEMPLATE(BM_SpinLock, + absl::base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL) + ->UseRealTime() + ->Threads(1) + ->ThreadPerCpu(); + +} // namespace diff --git a/absl/base/internal/spinlock_linux.inc b/absl/base/internal/spinlock_linux.inc new file mode 100644 index 00000000..94c861dc --- /dev/null +++ b/absl/base/internal/spinlock_linux.inc @@ -0,0 +1,72 @@ +// Copyright 2018 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. +// +// This file is a Linux-specific part of spinlock_wait.cc + +#include <linux/futex.h> +#include <sys/syscall.h> +#include <unistd.h> + +#include <atomic> +#include <cerrno> +#include <climits> +#include <cstdint> +#include <ctime> + +#include "absl/base/attributes.h" + +// The SpinLock lockword is `std::atomic<uint32_t>`. Here we assert that +// `std::atomic<uint32_t>` is bitwise equivalent of the `int` expected +// by SYS_futex. We also assume that reads/writes done to the lockword +// by SYS_futex have rational semantics with regard to the +// std::atomic<> API. C++ provides no guarantees of these assumptions, +// but they are believed to hold in practice. +static_assert(sizeof(std::atomic<uint32_t>) == sizeof(int), + "SpinLock lockword has the wrong size for a futex"); + +// Some Android headers are missing these definitions even though they +// support these futex operations. +#ifdef __BIONIC__ +#ifndef SYS_futex +#define SYS_futex __NR_futex +#endif +#ifndef FUTEX_PRIVATE_FLAG +#define FUTEX_PRIVATE_FLAG 128 +#endif +#endif + +extern "C" { + +ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay( + std::atomic<uint32_t> *w, uint32_t value, int loop, + absl::base_internal::SchedulingMode) { + if (loop != 0) { + int save_errno = errno; + struct timespec tm; + tm.tv_sec = 0; + // Increase the delay; we expect (but do not rely on) explicit wakeups. + // We don't rely on explicit wakeups because we intentionally allow for + // a race on the kSpinLockSleeper bit. + tm.tv_nsec = 16 * absl::base_internal::SpinLockSuggestedDelayNS(loop); + syscall(SYS_futex, w, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, value, &tm); + errno = save_errno; + } +} + +ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockWake(std::atomic<uint32_t> *w, + bool all) { + syscall(SYS_futex, w, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, all ? INT_MAX : 1, 0); +} + +} // extern "C" diff --git a/absl/base/internal/spinlock_wait.cc b/absl/base/internal/spinlock_wait.cc index 6709d01e..3f8e43f0 100644 --- a/absl/base/internal/spinlock_wait.cc +++ b/absl/base/internal/spinlock_wait.cc @@ -13,7 +13,7 @@ // limitations under the License. // The OS-specific header included below must provide two calls: -// base::subtle::SpinLockDelay() and base::subtle::SpinLockWake(). +// AbslInternalSpinLockDelay() and AbslInternalSpinLockWake(). // See spinlock_wait.h for the specs. #include <atomic> @@ -23,6 +23,8 @@ #if defined(_WIN32) #include "absl/base/internal/spinlock_win32.inc" +#elif defined(__linux__) +#include "absl/base/internal/spinlock_linux.inc" #elif defined(__akaros__) #include "absl/base/internal/spinlock_akaros.inc" #else @@ -30,21 +32,22 @@ #endif namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace base_internal { // See spinlock_wait.h for spec. uint32_t SpinLockWait(std::atomic<uint32_t> *w, int n, const SpinLockWaitTransition trans[], base_internal::SchedulingMode scheduling_mode) { - for (int loop = 0; ; loop++) { + int loop = 0; + for (;;) { uint32_t v = w->load(std::memory_order_acquire); int i; for (i = 0; i != n && v != trans[i].from; i++) { } if (i == n) { - SpinLockDelay(w, v, loop, scheduling_mode); // no matching transition - } else if (trans[i].to == v || // null transition + SpinLockDelay(w, v, ++loop, scheduling_mode); // no matching transition + } else if (trans[i].to == v || // null transition w->compare_exchange_strong(v, trans[i].to, std::memory_order_acquire, std::memory_order_relaxed)) { @@ -77,5 +80,5 @@ int SpinLockSuggestedDelayNS(int loop) { } } // namespace base_internal -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl diff --git a/absl/base/internal/spinlock_wait.h b/absl/base/internal/spinlock_wait.h index 31aaa8c6..5eb727f1 100644 --- a/absl/base/internal/spinlock_wait.h +++ b/absl/base/internal/spinlock_wait.h @@ -24,7 +24,7 @@ #include "absl/base/internal/scheduling_mode.h" namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace base_internal { // SpinLockWait() waits until it can perform one of several transitions from @@ -63,7 +63,7 @@ void SpinLockDelay(std::atomic<uint32_t> *w, uint32_t value, int loop, int SpinLockSuggestedDelayNS(int loop); } // namespace base_internal -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl // In some build configurations we pass --detect-odr-violations to the diff --git a/absl/base/internal/sysinfo.cc b/absl/base/internal/sysinfo.cc index 7db2e001..ce14fc0f 100644 --- a/absl/base/internal/sysinfo.cc +++ b/absl/base/internal/sysinfo.cc @@ -56,7 +56,7 @@ #include "absl/base/internal/unscaledcycleclock.h" namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace base_internal { static once_flag init_system_info_once; @@ -402,5 +402,5 @@ pid_t GetTID() { #endif } // namespace base_internal -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl diff --git a/absl/base/internal/sysinfo.h b/absl/base/internal/sysinfo.h index 18aa2e29..79100f61 100644 --- a/absl/base/internal/sysinfo.h +++ b/absl/base/internal/sysinfo.h @@ -33,7 +33,7 @@ #include "absl/base/port.h" namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace base_internal { // Nominal core processor cycles per second of each processor. This is _not_ @@ -59,7 +59,7 @@ using pid_t = DWORD; pid_t GetTID(); } // namespace base_internal -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl #endif // ABSL_BASE_INTERNAL_SYSINFO_H_ diff --git a/absl/base/internal/sysinfo_test.cc b/absl/base/internal/sysinfo_test.cc index fdbbdf88..c072ebc2 100644 --- a/absl/base/internal/sysinfo_test.cc +++ b/absl/base/internal/sysinfo_test.cc @@ -28,7 +28,7 @@ #include "absl/synchronization/mutex.h" namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace base_internal { namespace { @@ -96,5 +96,5 @@ TEST(SysinfoTest, LinuxGetTID) { } // namespace } // namespace base_internal -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl diff --git a/absl/base/internal/thread_identity.cc b/absl/base/internal/thread_identity.cc index aa1add8b..b35bee34 100644 --- a/absl/base/internal/thread_identity.cc +++ b/absl/base/internal/thread_identity.cc @@ -28,7 +28,7 @@ #include "absl/base/internal/spinlock.h" namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace base_internal { #if ABSL_THREAD_IDENTITY_MODE != ABSL_THREAD_IDENTITY_MODE_USE_CPP11 @@ -69,6 +69,14 @@ void SetCurrentThreadIdentity( // NOTE: Not async-safe. But can be open-coded. absl::call_once(init_thread_identity_key_once, AllocateThreadIdentityKey, reclaimer); + +#ifdef __EMSCRIPTEN__ + // Emscripten PThread implementation does not support signals. + // See https://kripken.github.io/emscripten-site/docs/porting/pthreads.html + // for more information. + pthread_setspecific(thread_identity_pthread_key, + reinterpret_cast<void*>(identity)); +#else // We must mask signals around the call to setspecific as with current glibc, // a concurrent getspecific (needed for GetCurrentThreadIdentityIfPresent()) // may zero our value. @@ -82,6 +90,8 @@ void SetCurrentThreadIdentity( pthread_setspecific(thread_identity_pthread_key, reinterpret_cast<void*>(identity)); pthread_sigmask(SIG_SETMASK, &curr_signals, nullptr); +#endif // !__EMSCRIPTEN__ + #elif ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS // NOTE: Not async-safe. But can be open-coded. absl::call_once(init_thread_identity_key_once, AllocateThreadIdentityKey, @@ -121,5 +131,5 @@ ThreadIdentity* CurrentThreadIdentityIfPresent() { #endif } // namespace base_internal -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl diff --git a/absl/base/internal/thread_identity.h b/absl/base/internal/thread_identity.h index 18a5a750..17ac2a7c 100644 --- a/absl/base/internal/thread_identity.h +++ b/absl/base/internal/thread_identity.h @@ -33,7 +33,7 @@ #include "absl/base/internal/per_thread_tls.h" namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { struct SynchLocksHeld; struct SynchWaitParams; @@ -237,6 +237,6 @@ inline ThreadIdentity* CurrentThreadIdentityIfPresent() { #endif } // namespace base_internal -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl #endif // ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_ diff --git a/absl/base/internal/thread_identity_test.cc b/absl/base/internal/thread_identity_test.cc index f39f11d2..ec93fc27 100644 --- a/absl/base/internal/thread_identity_test.cc +++ b/absl/base/internal/thread_identity_test.cc @@ -25,7 +25,7 @@ #include "absl/synchronization/mutex.h" namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace base_internal { namespace { @@ -124,5 +124,5 @@ TEST(ThreadIdentityTest, ReusedThreadIdentityMutexTest) { } // namespace } // namespace base_internal -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl diff --git a/absl/base/internal/throw_delegate.cc b/absl/base/internal/throw_delegate.cc index 5466e0f3..0f73c3eb 100644 --- a/absl/base/internal/throw_delegate.cc +++ b/absl/base/internal/throw_delegate.cc @@ -22,7 +22,7 @@ #include "absl/base/internal/raw_logging.h" namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace base_internal { namespace { @@ -31,8 +31,8 @@ template <typename T> #ifdef ABSL_HAVE_EXCEPTIONS throw error; #else - ABSL_RAW_LOG(ERROR, "%s", error.what()); - abort(); + ABSL_RAW_LOG(FATAL, "%s", error.what()); + std::abort(); #endif } } // namespace @@ -104,5 +104,5 @@ void ThrowStdBadFunctionCall() { Throw(std::bad_function_call()); } void ThrowStdBadAlloc() { Throw(std::bad_alloc()); } } // namespace base_internal -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl diff --git a/absl/base/internal/throw_delegate.h b/absl/base/internal/throw_delegate.h index d34ff79c..7e5510c0 100644 --- a/absl/base/internal/throw_delegate.h +++ b/absl/base/internal/throw_delegate.h @@ -20,7 +20,7 @@ #include <string> namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace base_internal { // Helper functions that allow throwing exceptions consistently from anywhere. @@ -67,7 +67,7 @@ namespace base_internal { // [[noreturn]] void ThrowStdBadArrayNewLength(); } // namespace base_internal -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl #endif // ABSL_BASE_INTERNAL_THROW_DELEGATE_H_ diff --git a/absl/base/internal/unaligned_access.h b/absl/base/internal/unaligned_access.h index f20a8694..07a64bba 100644 --- a/absl/base/internal/unaligned_access.h +++ b/absl/base/internal/unaligned_access.h @@ -65,7 +65,8 @@ void __sanitizer_unaligned_store64(void *p, uint64_t v); } // extern "C" namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { +namespace base_internal { inline uint16_t UnalignedLoad16(const void *p) { return __sanitizer_unaligned_load16(p); @@ -91,19 +92,71 @@ inline void UnalignedStore64(void *p, uint64_t v) { __sanitizer_unaligned_store64(p, v); } -} // inline namespace lts_2018_06_20 +} // namespace base_internal +} // inline namespace lts_2018_12_18 } // namespace absl -#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) (absl::UnalignedLoad16(_p)) -#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) (absl::UnalignedLoad32(_p)) -#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) (absl::UnalignedLoad64(_p)) +#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \ + (absl::base_internal::UnalignedLoad16(_p)) +#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \ + (absl::base_internal::UnalignedLoad32(_p)) +#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) \ + (absl::base_internal::UnalignedLoad64(_p)) + +#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \ + (absl::base_internal::UnalignedStore16(_p, _val)) +#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \ + (absl::base_internal::UnalignedStore32(_p, _val)) +#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \ + (absl::base_internal::UnalignedStore64(_p, _val)) + +#elif defined(UNDEFINED_BEHAVIOR_SANITIZER) + +namespace absl { +inline namespace lts_2018_12_18 { +namespace base_internal { + +inline uint16_t UnalignedLoad16(const void *p) { + uint16_t t; + memcpy(&t, p, sizeof t); + return t; +} + +inline uint32_t UnalignedLoad32(const void *p) { + uint32_t t; + memcpy(&t, p, sizeof t); + return t; +} + +inline uint64_t UnalignedLoad64(const void *p) { + uint64_t t; + memcpy(&t, p, sizeof t); + return t; +} + +inline void UnalignedStore16(void *p, uint16_t v) { memcpy(p, &v, sizeof v); } + +inline void UnalignedStore32(void *p, uint32_t v) { memcpy(p, &v, sizeof v); } + +inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); } + +} // namespace base_internal +} // inline namespace lts_2018_12_18 +} // namespace absl + +#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \ + (absl::base_internal::UnalignedLoad16(_p)) +#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \ + (absl::base_internal::UnalignedLoad32(_p)) +#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) \ + (absl::base_internal::UnalignedLoad64(_p)) #define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \ - (absl::UnalignedStore16(_p, _val)) + (absl::base_internal::UnalignedStore16(_p, _val)) #define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \ - (absl::UnalignedStore32(_p, _val)) + (absl::base_internal::UnalignedStore32(_p, _val)) #define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \ - (absl::UnalignedStore64(_p, _val)) + (absl::base_internal::UnalignedStore64(_p, _val)) #elif defined(__x86_64__) || defined(_M_X64) || defined(__i386) || \ defined(_M_IX86) || defined(__ppc__) || defined(__PPC__) || \ @@ -160,8 +213,8 @@ inline void UnalignedStore64(void *p, uint64_t v) { // so we do that. namespace absl { -inline namespace lts_2018_06_20 { -namespace internal { +inline namespace lts_2018_12_18 { +namespace base_internal { struct Unaligned16Struct { uint16_t value; @@ -173,24 +226,27 @@ struct Unaligned32Struct { uint8_t dummy; // To make the size non-power-of-two. } ABSL_ATTRIBUTE_PACKED; -} // namespace internal -} // inline namespace lts_2018_06_20 +} // namespace base_internal +} // inline namespace lts_2018_12_18 } // namespace absl -#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \ - ((reinterpret_cast<const ::absl::internal::Unaligned16Struct *>(_p))->value) -#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \ - ((reinterpret_cast<const ::absl::internal::Unaligned32Struct *>(_p))->value) +#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \ + ((reinterpret_cast<const ::absl::base_internal::Unaligned16Struct *>(_p)) \ + ->value) +#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \ + ((reinterpret_cast<const ::absl::base_internal::Unaligned32Struct *>(_p)) \ + ->value) -#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \ - ((reinterpret_cast< ::absl::internal::Unaligned16Struct *>(_p))->value = \ - (_val)) -#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \ - ((reinterpret_cast< ::absl::internal::Unaligned32Struct *>(_p))->value = \ - (_val)) +#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \ + ((reinterpret_cast< ::absl::base_internal::Unaligned16Struct *>(_p)) \ + ->value = (_val)) +#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \ + ((reinterpret_cast< ::absl::base_internal::Unaligned32Struct *>(_p)) \ + ->value = (_val)) namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { +namespace base_internal { inline uint64_t UnalignedLoad64(const void *p) { uint64_t t; @@ -200,12 +256,14 @@ inline uint64_t UnalignedLoad64(const void *p) { inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); } -} // inline namespace lts_2018_06_20 +} // namespace base_internal +} // inline namespace lts_2018_12_18 } // namespace absl -#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) (absl::UnalignedLoad64(_p)) +#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) \ + (absl::base_internal::UnalignedLoad64(_p)) #define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \ - (absl::UnalignedStore64(_p, _val)) + (absl::base_internal::UnalignedStore64(_p, _val)) #else @@ -217,7 +275,8 @@ inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); } // unaligned loads and stores. namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { +namespace base_internal { inline uint16_t UnalignedLoad16(const void *p) { uint16_t t; @@ -243,19 +302,23 @@ inline void UnalignedStore32(void *p, uint32_t v) { memcpy(p, &v, sizeof v); } inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); } -} // inline namespace lts_2018_06_20 +} // namespace base_internal +} // inline namespace lts_2018_12_18 } // namespace absl -#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) (absl::UnalignedLoad16(_p)) -#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) (absl::UnalignedLoad32(_p)) -#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) (absl::UnalignedLoad64(_p)) +#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \ + (absl::base_internal::UnalignedLoad16(_p)) +#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \ + (absl::base_internal::UnalignedLoad32(_p)) +#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) \ + (absl::base_internal::UnalignedLoad64(_p)) #define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \ - (absl::UnalignedStore16(_p, _val)) + (absl::base_internal::UnalignedStore16(_p, _val)) #define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \ - (absl::UnalignedStore32(_p, _val)) + (absl::base_internal::UnalignedStore32(_p, _val)) #define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \ - (absl::UnalignedStore64(_p, _val)) + (absl::base_internal::UnalignedStore64(_p, _val)) #endif diff --git a/absl/base/internal/unscaledcycleclock.cc b/absl/base/internal/unscaledcycleclock.cc index e0798eb9..888caf1e 100644 --- a/absl/base/internal/unscaledcycleclock.cc +++ b/absl/base/internal/unscaledcycleclock.cc @@ -27,7 +27,7 @@ #include "absl/base/internal/sysinfo.h" namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace base_internal { #if defined(__i386__) @@ -97,7 +97,7 @@ double UnscaledCycleClock::Frequency() { #endif } // namespace base_internal -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl #endif // ABSL_USE_UNSCALED_CYCLECLOCK diff --git a/absl/base/internal/unscaledcycleclock.h b/absl/base/internal/unscaledcycleclock.h index 9da14d0b..c71674f3 100644 --- a/absl/base/internal/unscaledcycleclock.h +++ b/absl/base/internal/unscaledcycleclock.h @@ -84,7 +84,7 @@ #define ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY #endif namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace time_internal { class UnscaledCycleClockWrapperForGetCurrentTime; } // namespace time_internal @@ -114,7 +114,7 @@ class UnscaledCycleClock { }; } // namespace base_internal -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl #endif // ABSL_USE_UNSCALED_CYCLECLOCK |