diff options
Diffstat (limited to 'absl/base')
57 files changed, 1569 insertions, 760 deletions
diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel index d117a4fe..4566c697 100644 --- a/absl/base/BUILD.bazel +++ b/absl/base/BUILD.bazel @@ -19,6 +19,7 @@ load( "ABSL_DEFAULT_COPTS", "ABSL_TEST_COPTS", "ABSL_EXCEPTIONS_FLAG", + "ABSL_EXCEPTIONS_FLAG_LINKOPTS", ) package(default_visibility = ["//visibility:public"]) @@ -29,6 +30,7 @@ cc_library( name = "spinlock_wait", srcs = [ "internal/spinlock_akaros.inc", + "internal/spinlock_linux.inc", "internal/spinlock_posix.inc", "internal/spinlock_wait.cc", "internal/spinlock_win32.inc", @@ -73,7 +75,6 @@ cc_library( copts = ABSL_DEFAULT_COPTS, deps = [ ":config", - ":dynamic_annotations", ], ) @@ -106,6 +107,7 @@ cc_library( "internal/identity.h", "internal/inline_variable.h", "internal/invoke.h", + "internal/scheduling_mode.h", ], copts = ABSL_DEFAULT_COPTS, visibility = [ @@ -179,13 +181,13 @@ cc_library( srcs = ["internal/throw_delegate.cc"], hdrs = ["internal/throw_delegate.h"], copts = ABSL_DEFAULT_COPTS + ABSL_EXCEPTIONS_FLAG, + linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS, visibility = [ "//absl:__subpackages__", ], deps = [ ":base", ":config", - ":core_headers", ], ) @@ -193,6 +195,7 @@ cc_test( name = "throw_delegate_test", srcs = ["throw_delegate_test.cc"], copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, + linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS, deps = [ ":throw_delegate", "@com_google_googletest//:gtest_main", @@ -225,6 +228,7 @@ cc_library( srcs = ["internal/exception_safety_testing.cc"], hdrs = ["internal/exception_safety_testing.h"], copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, + linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS, deps = [ ":base", ":config", @@ -232,7 +236,7 @@ cc_library( "//absl/memory", "//absl/meta:type_traits", "//absl/strings", - "//absl/types:optional", + "//absl/utility", "@com_google_googletest//:gtest", ], ) @@ -241,6 +245,7 @@ cc_test( name = "exception_safety_testing_test", srcs = ["exception_safety_testing_test.cc"], copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, + linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS, deps = [ ":exception_safety_testing", "//absl/memory", @@ -299,6 +304,7 @@ cc_test( size = "medium", srcs = ["spinlock_test_common.cc"], copts = ABSL_TEST_COPTS, + tags = ["no_test_wasm"], deps = [ ":base", ":core_headers", @@ -309,6 +315,33 @@ cc_test( ) cc_library( + name = "spinlock_benchmark_common", + testonly = 1, + srcs = ["internal/spinlock_benchmark.cc"], + copts = ABSL_DEFAULT_COPTS, + visibility = [ + "//absl/base:__pkg__", + ], + deps = [ + ":base", + ":base_internal", + "//absl/synchronization", + "@com_github_google_benchmark//:benchmark_main", + ], + alwayslink = 1, +) + +cc_binary( + name = "spinlock_benchmark", + testonly = 1, + copts = ABSL_DEFAULT_COPTS, + visibility = ["//visibility:private"], + deps = [ + ":spinlock_benchmark_common", + ], +) + +cc_library( name = "endian", hdrs = [ "internal/endian.h", @@ -337,6 +370,9 @@ cc_test( name = "config_test", srcs = ["config_test.cc"], copts = ABSL_TEST_COPTS, + tags = [ + "no_test_wasm", + ], deps = [ ":config", "//absl/synchronization:thread_pool", @@ -348,6 +384,9 @@ cc_test( name = "call_once_test", srcs = ["call_once_test.cc"], copts = ABSL_TEST_COPTS, + tags = [ + "no_test_wasm", + ], deps = [ ":base", ":core_headers", @@ -362,6 +401,7 @@ cc_test( copts = ABSL_TEST_COPTS, deps = [ ":base", + "//absl/strings", "@com_google_googletest//:gtest_main", ], ) @@ -387,6 +427,7 @@ cc_test( "//absl:windows": [], "//conditions:default": ["-pthread"], }), + tags = ["no_test_ios_x86_64"], deps = [":malloc_internal"], ) @@ -399,6 +440,9 @@ cc_test( "//absl:windows": [], "//conditions:default": ["-pthread"], }), + tags = [ + "no_test_wasm", + ], deps = [ ":base", ":core_headers", @@ -419,3 +463,23 @@ cc_test( "@com_github_google_benchmark//:benchmark_main", ], ) + +cc_library( + name = "bits", + hdrs = ["internal/bits.h"], + visibility = [ + "//absl:__subpackages__", + ], + deps = [":core_headers"], +) + +cc_test( + name = "bits_test", + size = "small", + srcs = ["internal/bits_test.cc"], + copts = ABSL_TEST_COPTS, + deps = [ + ":bits", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/absl/base/CMakeLists.txt b/absl/base/CMakeLists.txt index 303533e2..212dd083 100644 --- a/absl/base/CMakeLists.txt +++ b/absl/base/CMakeLists.txt @@ -14,373 +14,401 @@ # limitations under the License. # -list(APPEND BASE_PUBLIC_HEADERS - "attributes.h" - "call_once.h" - "casts.h" - "config.h" - "dynamic_annotations.h" - "log_severity.h" - "macros.h" - "optimization.h" - "policy_checks.h" - "port.h" - "thread_annotations.h" +absl_cc_library( + NAME + spinlock_wait + HDRS + "internal/scheduling_mode.h" + "internal/spinlock_wait.h" + SRCS + "internal/spinlock_akaros.inc" + "internal/spinlock_linux.inc" + "internal/spinlock_posix.inc" + "internal/spinlock_wait.cc" + "internal/spinlock_win32.inc" + DEPS + absl::core_headers ) +absl_cc_library( + NAME + config + HDRS + "config.h" + "policy_checks.h" + COPTS + ${ABSL_DEFAULT_COPTS} + PUBLIC +) + +absl_cc_library( + NAME + dynamic_annotations + HDRS + "dynamic_annotations.h" + SRCS + "dynamic_annotations.cc" + COPTS + ${ABSL_DEFAULT_COPTS} + DEFINES + "__CLANG_SUPPORT_DYN_ANNOTATION__" + PUBLIC +) -list(APPEND BASE_INTERNAL_HEADERS - "internal/atomic_hook.h" - "internal/cycleclock.h" - "internal/direct_mmap.h" - "internal/endian.h" - "internal/exception_testing.h" - "internal/exception_safety_testing.h" - "internal/hide_ptr.h" - "internal/identity.h" - "internal/invoke.h" - "internal/inline_variable.h" - "internal/low_level_alloc.h" - "internal/low_level_scheduling.h" - "internal/per_thread_tls.h" - "internal/pretty_function.h" - "internal/raw_logging.h" - "internal/scheduling_mode.h" - "internal/spinlock.h" - "internal/spinlock_wait.h" - "internal/sysinfo.h" - "internal/thread_identity.h" - "internal/throw_delegate.h" - "internal/tsan_mutex_interface.h" - "internal/unaligned_access.h" - "internal/unscaledcycleclock.h" +absl_cc_library( + NAME + core_headers + HDRS + "attributes.h" + "macros.h" + "optimization.h" + "port.h" + "thread_annotations.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::config + PUBLIC ) +absl_cc_library( + NAME + malloc_internal + HDRS + "internal/direct_mmap.h" + "internal/low_level_alloc.h" + SRCS + "internal/low_level_alloc.cc" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::base + absl::config + absl::core_headers + absl::dynamic_annotations + absl::spinlock_wait +) -# absl_base main library -list(APPEND BASE_SRC - "internal/cycleclock.cc" - "internal/raw_logging.cc" - "internal/spinlock.cc" - "internal/sysinfo.cc" - "internal/thread_identity.cc" - "internal/unscaledcycleclock.cc" - "internal/low_level_alloc.cc" - ${BASE_PUBLIC_HEADERS} - ${BASE_INTERNAL_HEADERS} +absl_cc_library( + NAME + base_internal + HDRS + "internal/hide_ptr.h" + "internal/identity.h" + "internal/inline_variable.h" + "internal/invoke.h" + COPTS + ${ABSL_DEFAULT_COPTS} ) -absl_library( - TARGET - absl_base - SOURCES - ${BASE_SRC} - PUBLIC_LIBRARIES - absl_dynamic_annotations - absl_spinlock_wait - EXPORT_NAME +absl_cc_library( + NAME base + HDRS + "call_once.h" + "casts.h" + "internal/atomic_hook.h" + "internal/cycleclock.h" + "internal/low_level_scheduling.h" + "internal/per_thread_tls.h" + "internal/raw_logging.h" + "internal/spinlock.h" + "internal/sysinfo.h" + "internal/thread_identity.h" + "internal/tsan_mutex_interface.h" + "internal/unscaledcycleclock.h" + "log_severity.h" + SRCS + "internal/cycleclock.cc" + "internal/raw_logging.cc" + "internal/spinlock.cc" + "internal/sysinfo.cc" + "internal/thread_identity.cc" + "internal/unscaledcycleclock.cc" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::base_internal + absl::config + absl::core_headers + absl::dynamic_annotations + absl::spinlock_wait + PUBLIC ) -# throw delegate library -set(THROW_DELEGATE_SRC "internal/throw_delegate.cc") - -absl_library( - TARGET - absl_throw_delegate - SOURCES - ${THROW_DELEGATE_SRC} - PUBLIC_LIBRARIES - ${THROW_DELEGATE_PUBLIC_LIBRARIES} - PRIVATE_COMPILE_FLAGS - ${ABSL_EXCEPTIONS_FLAG} - EXPORT_NAME +absl_cc_library( + NAME throw_delegate + HDRS + "internal/throw_delegate.h" + SRCS + "internal/throw_delegate.cc" + COPTS + ${ABSL_DEFAULT_COPTS} + ${ABSL_EXCEPTIONS_FLAG} + DEPS + absl::base +) + +absl_cc_library( + NAME + exception_testing + HDRS + "internal/exception_testing.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::config + gtest + TESTONLY +) + +absl_cc_library( + NAME + pretty_function + HDRS + "internal/pretty_function.h" + COPTS + ${ABSL_DEFAULT_COPTS} ) -if(BUILD_TESTING) - # exception-safety testing library - set(EXCEPTION_SAFETY_TESTING_SRC +absl_cc_library( + NAME + exception_safety_testing + HDRS "internal/exception_safety_testing.h" + SRCS "internal/exception_safety_testing.cc" - ) - set(EXCEPTION_SAFETY_TESTING_PUBLIC_LIBRARIES - ${ABSL_TEST_COMMON_LIBRARIES} + COPTS + ${ABSL_DEFAULT_COPTS} + ${ABSL_EXCEPTIONS_FLAG} + DEPS absl::base + absl::config + absl::pretty_function absl::memory absl::meta absl::strings - absl::optional + absl::utility gtest - ) - -absl_library( - TARGET - absl_base_internal_exception_safety_testing - SOURCES - ${EXCEPTION_SAFETY_TESTING_SRC} - PUBLIC_LIBRARIES - ${EXCEPTION_SAFETY_TESTING_PUBLIC_LIBRARIES} - PRIVATE_COMPILE_FLAGS - ${ABSL_EXCEPTIONS_FLAG} -) -endif() - - -# dynamic_annotations library -set(DYNAMIC_ANNOTATIONS_SRC "dynamic_annotations.cc") - -absl_library( - TARGET - absl_dynamic_annotations - SOURCES - ${DYNAMIC_ANNOTATIONS_SRC} -) - - -# spinlock_wait library -set(SPINLOCK_WAIT_SRC "internal/spinlock_wait.cc") - -absl_library( - TARGET - absl_spinlock_wait - SOURCES - ${SPINLOCK_WAIT_SRC} -) - - -# malloc_internal library -list(APPEND MALLOC_INTERNAL_SRC - "internal/low_level_alloc.cc" + TESTONLY ) -absl_library( - TARGET - absl_malloc_internal - SOURCES - ${MALLOC_INTERNAL_SRC} - PUBLIC_LIBRARIES - absl_dynamic_annotations +absl_cc_test( + NAME + absl_exception_safety_testing_test + SRCS + "exception_safety_testing_test.cc" + COPTS + ${ABSL_EXCEPTIONS_FLAG} + LINKOPTS + ${ABSL_EXCEPTIONS_FLAG_LINKOPTS} + DEPS + absl::exception_safety_testing + absl::memory + gtest_main ) - - -# -## TESTS -# - -# call once test -set(ATOMIC_HOOK_TEST_SRC "internal/atomic_hook_test.cc") -set(ATOMIC_HOOK_TEST_PUBLIC_LIBRARIES absl::base) - -absl_test( - TARGET +absl_cc_test( + NAME atomic_hook_test - SOURCES - ${ATOMIC_HOOK_TEST_SRC} - PUBLIC_LIBRARIES - ${ATOMIC_HOOK_TEST_PUBLIC_LIBRARIES} -) - - -# call once test -set(CALL_ONCE_TEST_SRC "call_once_test.cc") -set(CALL_ONCE_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization) - -absl_test( - TARGET - call_once_test - SOURCES - ${CALL_ONCE_TEST_SRC} - PUBLIC_LIBRARIES - ${CALL_ONCE_TEST_PUBLIC_LIBRARIES} + SRCS + "internal/atomic_hook_test.cc" + DEPS + absl::base + absl::core_headers + gtest_main ) - -# test bit_cast_test -set(BIT_CAST_TEST_SRC "bit_cast_test.cc") - -absl_test( - TARGET +absl_cc_test( + NAME bit_cast_test - SOURCES - ${BIT_CAST_TEST_SRC} + SRCS + "bit_cast_test.cc" + DEPS + absl::base + absl::core_headers + gtest_main ) - -# test absl_throw_delegate_test -set(THROW_DELEGATE_TEST_SRC "throw_delegate_test.cc") -set(THROW_DELEGATE_TEST_PUBLIC_LIBRARIES absl::base absl_throw_delegate) - -absl_test( - TARGET +absl_cc_test( + NAME throw_delegate_test - SOURCES - ${THROW_DELEGATE_TEST_SRC} - PUBLIC_LIBRARIES - ${THROW_DELEGATE_TEST_PUBLIC_LIBRARIES} -) - - -# test invoke_test -set(INVOKE_TEST_SRC "invoke_test.cc") -set(INVOKE_TEST_PUBLIC_LIBRARIES absl::strings) - -absl_test( - TARGET - invoke_test - SOURCES - ${INVOKE_TEST_SRC} - PUBLIC_LIBRARIES - ${INVOKE_TEST_PUBLIC_LIBRARIES} -) - - -# test inline_variable_test -list(APPEND INLINE_VARIABLE_TEST_SRC - "internal/inline_variable_testing.h" - "inline_variable_test.cc" - "inline_variable_test_a.cc" - "inline_variable_test_b.cc" + SRCS + "throw_delegate_test.cc" + DEPS + absl::base + absl_internal_throw_delegate + gtest_main ) -set(INLINE_VARIABLE_TEST_PUBLIC_LIBRARIES absl::base) - -absl_test( - TARGET +absl_cc_test( + NAME inline_variable_test - SOURCES - ${INLINE_VARIABLE_TEST_SRC} - PUBLIC_LIBRARIES - ${INLINE_VARIABLE_TEST_PUBLIC_LIBRARIES} + SRCS + "internal/inline_variable_testing.h" + "inline_variable_test.cc" + "inline_variable_test_a.cc" + "inline_variable_test_b.cc" + DEPS + absl::base_internal + gtest_main ) +absl_cc_test( + NAME + invoke_test + SRCS + "invoke_test.cc" + DEPS + absl::base_internal + absl::memory + absl::strings + gmock + gtest_main +) -# test spinlock_test_common -set(SPINLOCK_TEST_COMMON_SRC "spinlock_test_common.cc") -set(SPINLOCK_TEST_COMMON_PUBLIC_LIBRARIES absl::base absl::synchronization) - -absl_test( - TARGET +absl_cc_library( + NAME spinlock_test_common - SOURCES - ${SPINLOCK_TEST_COMMON_SRC} - PUBLIC_LIBRARIES - ${SPINLOCK_TEST_COMMON_PUBLIC_LIBRARIES} + SRCS + "spinlock_test_common.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::base + absl::core_headers + absl::spinlock_wait + absl::synchronization + gtest + TESTONLY ) - -# test spinlock_test -set(SPINLOCK_TEST_SRC "spinlock_test_common.cc") -set(SPINLOCK_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization) - -absl_test( - TARGET +# On bazel BUILD this target use "alwayslink = 1" which is not implemented here +absl_cc_test( + NAME spinlock_test - SOURCES - ${SPINLOCK_TEST_SRC} - PUBLIC_LIBRARIES - ${SPINLOCK_TEST_PUBLIC_LIBRARIES} + SRCS + "spinlock_test_common.cc" + DEPS + absl::base + absl::core_headers + absl::spinlock_wait + absl::synchronization + gtest_main ) +absl_cc_library( + NAME + endian + HDRS + "internal/endian.h" + "internal/unaligned_access.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::config + absl::core_headers + PUBLIC +) -# test endian_test -set(ENDIAN_TEST_SRC "internal/endian_test.cc") - -absl_test( - TARGET +absl_cc_test( + NAME endian_test - SOURCES - ${ENDIAN_TEST_SRC} + SRCS + "internal/endian_test.cc" + DEPS + absl::base + absl::config + absl::endian + gtest_main ) - -# test config_test -set(CONFIG_TEST_SRC "config_test.cc") -set(CONFIG_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization) -absl_test( - TARGET +absl_cc_test( + NAME config_test - SOURCES - ${CONFIG_TEST_SRC} - PUBLIC_LIBRARIES - ${CONFIG_TEST_PUBLIC_LIBRARIES} + SRCS + "config_test.cc" + DEPS + absl::config + absl::synchronization + gtest_main ) +absl_cc_test( + NAME + call_once_test + SRCS + "call_once_test.cc" + DEPS + absl::base + absl::core_headers + absl::synchronization + gtest_main +) -# test raw_logging_test -set(RAW_LOGGING_TEST_SRC "raw_logging_test.cc") -set(RAW_LOGGING_TEST_PUBLIC_LIBRARIES absl::base) - -absl_test( - TARGET +absl_cc_test( + NAME raw_logging_test - SOURCES - ${RAW_LOGGING_TEST_SRC} - PUBLIC_LIBRARIES - ${RAW_LOGGING_TEST_PUBLIC_LIBRARIES} + SRCS + "raw_logging_test.cc" + DEPS + absl::base + absl::strings + gtest_main ) - -# test sysinfo_test -set(SYSINFO_TEST_SRC "internal/sysinfo_test.cc") -set(SYSINFO_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization) - -absl_test( - TARGET +absl_cc_test( + NAME sysinfo_test - SOURCES - ${SYSINFO_TEST_SRC} - PUBLIC_LIBRARIES - ${SYSINFO_TEST_PUBLIC_LIBRARIES} + SRCS + "internal/sysinfo_test.cc" + DEPS + absl::base + absl::synchronization + gtest_main ) - -# test low_level_alloc_test -set(LOW_LEVEL_ALLOC_TEST_SRC "internal/low_level_alloc_test.cc") -set(LOW_LEVEL_ALLOC_TEST_PUBLIC_LIBRARIES absl::base) - -absl_test( - TARGET +absl_cc_test( + NAME low_level_alloc_test - SOURCES - ${LOW_LEVEL_ALLOC_TEST_SRC} - PUBLIC_LIBRARIES - ${LOW_LEVEL_ALLOC_TEST_PUBLIC_LIBRARIES} + SRCS + "internal/low_level_alloc_test.cc" + DEPS + absl::malloc_internal + Threads::Threads ) - -# test thread_identity_test -set(THREAD_IDENTITY_TEST_SRC "internal/thread_identity_test.cc") -set(THREAD_IDENTITY_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization) - -absl_test( - TARGET +absl_cc_test( + NAME thread_identity_test - SOURCES - ${THREAD_IDENTITY_TEST_SRC} - PUBLIC_LIBRARIES - ${THREAD_IDENTITY_TEST_PUBLIC_LIBRARIES} + SRCS + "internal/thread_identity_test.cc" + DEPS + absl::base + absl::core_headers + absl::synchronization + Threads::Threads + gtest_main ) -#test exceptions_safety_testing_test -set(EXCEPTION_SAFETY_TESTING_TEST_SRC "exception_safety_testing_test.cc") -set(EXCEPTION_SAFETY_TESTING_TEST_PUBLIC_LIBRARIES - absl::base - absl_base_internal_exception_safety_testing - absl::memory - absl::meta - absl::strings - absl::optional +absl_cc_library( + NAME + bits + HDRS + "internal/bits.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::core_headers ) -absl_test( - TARGET - absl_exception_safety_testing_test - SOURCES - ${EXCEPTION_SAFETY_TESTING_TEST_SRC} - PUBLIC_LIBRARIES - ${EXCEPTION_SAFETY_TESTING_TEST_PUBLIC_LIBRARIES} - PRIVATE_COMPILE_FLAGS - ${ABSL_EXCEPTIONS_FLAG} +absl_cc_test( + NAME + bits_test + SRCS + "internal/bits_test.cc" + DEPS + absl::bits + gtest_main ) diff --git a/absl/base/attributes.h b/absl/base/attributes.h index b1883b6d..291ad89e 100644 --- a/absl/base/attributes.h +++ b/absl/base/attributes.h @@ -100,7 +100,7 @@ // ABSL_PRINTF_ATTRIBUTE // ABSL_SCANF_ATTRIBUTE // -// Tells the compiler to perform `printf` format std::string checking if the +// Tells the compiler to perform `printf` format string checking if the // compiler supports it; see the 'format' attribute in // <http://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html>. // @@ -155,7 +155,12 @@ // ABSL_ATTRIBUTE_WEAK // // Tags a function as weak for the purposes of compilation and linking. -#if ABSL_HAVE_ATTRIBUTE(weak) || (defined(__GNUC__) && !defined(__clang__)) +// Weak attributes currently do not work properly in LLVM's Windows backend, +// so disable them there. See https://bugs.llvm.org/show_bug.cgi?id=37598 +// for futher information. +#if (ABSL_HAVE_ATTRIBUTE(weak) || \ + (defined(__GNUC__) && !defined(__clang__))) && \ + !(defined(__llvm__) && defined(_WIN32)) #undef ABSL_ATTRIBUTE_WEAK #define ABSL_ATTRIBUTE_WEAK __attribute__((weak)) #define ABSL_HAVE_ATTRIBUTE_WEAK 1 @@ -296,13 +301,13 @@ // ABSL_HAVE_ATTRIBUTE_SECTION // -// Indicates whether labeled sections are supported. Labeled sections are not -// supported on Darwin/iOS. +// Indicates whether labeled sections are supported. Weak symbol support is +// a prerequisite. Labeled sections are not supported on Darwin/iOS. #ifdef ABSL_HAVE_ATTRIBUTE_SECTION #error ABSL_HAVE_ATTRIBUTE_SECTION cannot be directly set #elif (ABSL_HAVE_ATTRIBUTE(section) || \ (defined(__GNUC__) && !defined(__clang__))) && \ - !defined(__APPLE__) + !defined(__APPLE__) && ABSL_HAVE_ATTRIBUTE_WEAK #define ABSL_HAVE_ATTRIBUTE_SECTION 1 // ABSL_ATTRIBUTE_SECTION @@ -397,17 +402,28 @@ // ABSL_MUST_USE_RESULT // -// Tells the compiler to warn about unused return values for functions declared -// with this macro. The macro must appear as the very first part of a function -// declaration or definition: +// Tells the compiler to warn about unused results. // -// Example: +// When annotating a function, it must appear as the first part of the +// declaration or definition. The compiler will warn if the return value from +// such a function is unused: // // ABSL_MUST_USE_RESULT Sprocket* AllocateSprocket(); +// AllocateSprocket(); // Triggers a warning. +// +// When annotating a class, it is equivalent to annotating every function which +// returns an instance. +// +// class ABSL_MUST_USE_RESULT Sprocket {}; +// Sprocket(); // Triggers a warning. +// +// Sprocket MakeSprocket(); +// MakeSprocket(); // Triggers a warning. +// +// Note that references and pointers are not instances: // -// This placement has the broadest compatibility with GCC, Clang, and MSVC, with -// both defs and decls, and with GCC-style attributes, MSVC declspec, C++11 -// and C++17 attributes. +// Sprocket* SprocketPointer(); +// SprocketPointer(); // Does *not* trigger a warning. // // ABSL_MUST_USE_RESULT allows using cast-to-void to suppress the unused result // warning. For that, warn_unused_result is used only for clang but not for gcc. @@ -494,14 +510,27 @@ #define ABSL_XRAY_LOG_ARGS(N) #endif +// ABSL_ATTRIBUTE_REINITIALIZES +// +// Indicates that a member function reinitializes the entire object to a known +// state, independent of the previous state of the object. +// +// The clang-tidy check bugprone-use-after-move allows member functions marked +// with this attribute to be called on objects that have been moved from; +// without the attribute, this would result in a use-after-move warning. +#if ABSL_HAVE_CPP_ATTRIBUTE(clang::reinitializes) +#define ABSL_ATTRIBUTE_REINITIALIZES [[clang::reinitializes]] +#else +#define ABSL_ATTRIBUTE_REINITIALIZES +#endif + // ----------------------------------------------------------------------------- // Variable Attributes // ----------------------------------------------------------------------------- // ABSL_ATTRIBUTE_UNUSED // -// Prevents the compiler from complaining about or optimizing away variables -// that appear unused. +// Prevents the compiler from complaining about variables that appear unused. #if ABSL_HAVE_ATTRIBUTE(unused) || (defined(__GNUC__) && !defined(__clang__)) #undef ABSL_ATTRIBUTE_UNUSED #define ABSL_ATTRIBUTE_UNUSED __attribute__((__unused__)) diff --git a/absl/base/bit_cast_test.cc b/absl/base/bit_cast_test.cc index 71bb368f..5af036df 100644 --- a/absl/base/bit_cast_test.cc +++ b/absl/base/bit_cast_test.cc @@ -22,7 +22,7 @@ #include "absl/base/macros.h" namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace { template <int N> @@ -105,5 +105,5 @@ TEST(BitCast, Double) { } } // namespace -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl diff --git a/absl/base/call_once.h b/absl/base/call_once.h index 37b6608a..aea9197b 100644 --- a/absl/base/call_once.h +++ b/absl/base/call_once.h @@ -39,7 +39,7 @@ #include "absl/base/port.h" namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { class once_flag; @@ -151,12 +151,8 @@ void CallOnceImpl(std::atomic<uint32_t>* control, old_control != kOnceRunning && old_control != kOnceWaiter && old_control != kOnceDone) { - ABSL_RAW_LOG( - FATAL, - "Unexpected value for control word: %lx. Either the control word " - "has non-static storage duration (where GoogleOnceDynamic might " - "be appropriate), or there's been a memory corruption.", - static_cast<unsigned long>(old_control)); // NOLINT + ABSL_RAW_LOG(FATAL, "Unexpected value for control word: 0x%lx", + static_cast<unsigned long>(old_control)); // NOLINT } } #endif // NDEBUG @@ -212,7 +208,7 @@ void call_once(absl::once_flag& flag, Callable&& fn, Args&&... args) { } } -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl #endif // ABSL_BASE_CALL_ONCE_H_ diff --git a/absl/base/call_once_test.cc b/absl/base/call_once_test.cc index 43a71656..4d98a405 100644 --- a/absl/base/call_once_test.cc +++ b/absl/base/call_once_test.cc @@ -22,7 +22,7 @@ #include "absl/synchronization/mutex.h" namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace { absl::once_flag once; @@ -100,5 +100,5 @@ TEST(CallOnceTest, ExecutionCount) { } } // namespace -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl diff --git a/absl/base/casts.h b/absl/base/casts.h index cd07d8f6..bba623b4 100644 --- a/absl/base/casts.h +++ b/absl/base/casts.h @@ -25,12 +25,36 @@ #define ABSL_BASE_CASTS_H_ #include <cstring> +#include <memory> #include <type_traits> #include "absl/base/internal/identity.h" +#include "absl/base/macros.h" namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { + +namespace internal_casts { + +// NOTE: Not a fully compliant implementation of `std::is_trivially_copyable`. +// TODO(calabrese) Branch on implementations that directly provide +// `std::is_trivially_copyable`, create a more rigorous workaround, and publicly +// expose in meta/type_traits. +template <class T> +struct is_trivially_copyable + : std::integral_constant< + bool, std::is_destructible<T>::value&& __has_trivial_destructor(T) && + __has_trivial_copy(T) && __has_trivial_assign(T)> {}; + +template <class Dest, class Source> +struct is_bitcastable + : std::integral_constant<bool, + sizeof(Dest) == sizeof(Source) && + is_trivially_copyable<Source>::value && + is_trivially_copyable<Dest>::value && + std::is_default_constructible<Dest>::value> {}; + +} // namespace internal_casts // implicit_cast() // @@ -82,7 +106,7 @@ inline namespace lts_2018_06_20 { // // Such implicit cast chaining may be useful within template logic. template <typename To> -inline To implicit_cast(typename absl::internal::identity_t<To> to) { +constexpr To implicit_cast(typename absl::internal::identity_t<To> to) { return to; } @@ -126,7 +150,32 @@ inline To implicit_cast(typename absl::internal::identity_t<To> to) { // and reading its bits back using a different type. A `bit_cast()` avoids this // issue by implementing its casts using `memcpy()`, which avoids introducing // this undefined behavior. -template <typename Dest, typename Source> +// +// NOTE: The requirements here are more strict than the bit_cast of standard +// proposal p0476 due to the need for workarounds and lack of intrinsics. +// Specifically, this implementation also requires `Dest` to be +// default-constructible. +template < + typename Dest, typename Source, + typename std::enable_if<internal_casts::is_bitcastable<Dest, Source>::value, + int>::type = 0> +inline Dest bit_cast(const Source& source) { + Dest dest; + memcpy(static_cast<void*>(std::addressof(dest)), + static_cast<const void*>(std::addressof(source)), sizeof(dest)); + return dest; +} + +// NOTE: This overload is only picked if the requirements of bit_cast are not +// met. It is therefore UB, but is provided temporarily as previous versions of +// this function template were unchecked. Do not use this in new code. +template < + typename Dest, typename Source, + typename std::enable_if< + !internal_casts::is_bitcastable<Dest, Source>::value, int>::type = 0> +ABSL_DEPRECATED( + "absl::bit_cast type requirements were violated. Update the types being " + "used such that they are the same size and are both TriviallyCopyable.") inline Dest bit_cast(const Source& source) { static_assert(sizeof(Dest) == sizeof(Source), "Source and destination types should have equal sizes."); @@ -136,7 +185,7 @@ inline Dest bit_cast(const Source& source) { return dest; } -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl #endif // ABSL_BASE_CASTS_H_ diff --git a/absl/base/config.h b/absl/base/config.h index 2f5f1595..db4c4539 100644 --- a/absl/base/config.h +++ b/absl/base/config.h @@ -139,12 +139,18 @@ #ifdef ABSL_HAVE_THREAD_LOCAL #error ABSL_HAVE_THREAD_LOCAL cannot be directly set #elif defined(__APPLE__) -// Notes: Xcode's clang did not support `thread_local` until version -// 8, and even then not for all iOS < 9.0. Also, Xcode 9.3 started disallowing -// `thread_local` for 32-bit iOS simulator targeting iOS 9.x. -// `__has_feature` is only supported by Clang so it has be inside +// Notes: +// * Xcode's clang did not support `thread_local` until version 8, and +// even then not for all iOS < 9.0. +// * Xcode 9.3 started disallowing `thread_local` for 32-bit iOS simulator +// targeting iOS 9.x. +// * Xcode 10 moves the deployment target check for iOS < 9.0 to link time +// making __has_feature unreliable there. +// +// Otherwise, `__has_feature` is only supported by Clang so it has be inside // `defined(__APPLE__)` check. -#if __has_feature(cxx_thread_local) +#if __has_feature(cxx_thread_local) && \ + !(TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0) #define ABSL_HAVE_THREAD_LOCAL 1 #endif #else // !defined(__APPLE__) @@ -199,7 +205,7 @@ #define ABSL_HAVE_INTRINSIC_INT128 1 #elif defined(__CUDACC__) // __CUDACC_VER__ is a full version number before CUDA 9, and is defined to a -// std::string explaining that it has been removed starting with CUDA 9. We use +// string explaining that it has been removed starting with CUDA 9. We use // nested #ifs because there is no short-circuiting in the preprocessor. // NOTE: `__CUDACC__` could be undefined while `__CUDACC_VER__` is defined. #if __CUDACC_VER__ >= 70000 @@ -268,7 +274,8 @@ #error ABSL_HAVE_MMAP cannot be directly set #elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \ defined(__ros__) || defined(__native_client__) || defined(__asmjs__) || \ - defined(__wasm__) || defined(__Fuchsia__) + defined(__wasm__) || defined(__Fuchsia__) || defined(__sun) || \ + defined(__ASYLO__) #define ABSL_HAVE_MMAP 1 #endif @@ -322,6 +329,8 @@ #define ABSL_HAVE_ALARM 1 #elif defined(_MSC_VER) // feature tests for Microsoft's library +#elif defined(__EMSCRIPTEN__) +// emscripten doesn't support signals #elif defined(__native_client__) #else // other standard libraries @@ -356,6 +365,18 @@ #error "absl endian detection needs to be set up for your compiler" #endif +// MacOS 10.13 doesn't let you use <any>, <optional>, or <variant> even though +// the headers exist and are publicly noted to work. See +// https://github.com/abseil/abseil-cpp/issues/207 and +// https://developer.apple.com/documentation/xcode_release_notes/xcode_10_release_notes +#if defined(__APPLE__) && defined(_LIBCPP_VERSION) && \ + defined(__MAC_OS_X_VERSION_MIN_REQUIRED__) && \ + __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101400 +#define ABSL_INTERNAL_MACOS_HAS_CXX_17_TYPES 1 +#else +#define ABSL_INTERNAL_MACOS_HAS_CXX_17_TYPES 0 +#endif + // ABSL_HAVE_STD_ANY // // Checks whether C++17 std::any is available by checking whether <any> exists. @@ -364,7 +385,8 @@ #endif #ifdef __has_include -#if __has_include(<any>) && __cplusplus >= 201703L +#if __has_include(<any>) && __cplusplus >= 201703L && \ + ABSL_INTERNAL_MACOS_HAS_CXX_17_TYPES #define ABSL_HAVE_STD_ANY 1 #endif #endif @@ -377,7 +399,8 @@ #endif #ifdef __has_include -#if __has_include(<optional>) && __cplusplus >= 201703L +#if __has_include(<optional>) && __cplusplus >= 201703L && \ + ABSL_INTERNAL_MACOS_HAS_CXX_17_TYPES #define ABSL_HAVE_STD_OPTIONAL 1 #endif #endif @@ -390,7 +413,8 @@ #endif #ifdef __has_include -#if __has_include(<variant>) && __cplusplus >= 201703L +#if __has_include(<variant>) && __cplusplus >= 201703L && \ + ABSL_INTERNAL_MACOS_HAS_CXX_17_TYPES #define ABSL_HAVE_STD_VARIANT 1 #endif #endif @@ -414,14 +438,21 @@ // <string_view>, <variant> is implemented) or higher. Also, `__cplusplus` is // not correctly set by MSVC, so we use `_MSVC_LANG` to check the language // version. -// TODO(zhangxy): fix tests before enabling aliasing for `std::any`, -// `std::string_view`. +// TODO(zhangxy): fix tests before enabling aliasing for `std::any`. #if defined(_MSC_VER) && _MSC_VER >= 1910 && \ ((defined(_MSVC_LANG) && _MSVC_LANG > 201402) || __cplusplus > 201402) // #define ABSL_HAVE_STD_ANY 1 #define ABSL_HAVE_STD_OPTIONAL 1 #define ABSL_HAVE_STD_VARIANT 1 -// #define ABSL_HAVE_STD_STRING_VIEW 1 +#define ABSL_HAVE_STD_STRING_VIEW 1 +#endif + +// In debug mode, MSVC 2017's std::variant throws a EXCEPTION_ACCESS_VIOLATION +// SEH exception from emplace for variant<SomeStruct> when constructing the +// struct can throw. This defeats some of variant_test and +// variant_exception_safety_test. +#if defined(_MSC_VER) && _MSC_VER >= 1700 && defined(_DEBUG) +#define ABSL_INTERNAL_MSVC_2017_DBG_MODE #endif #endif // ABSL_BASE_CONFIG_H_ diff --git a/absl/base/exception_safety_testing_test.cc b/absl/base/exception_safety_testing_test.cc index 97c8d6f8..7518264d 100644 --- a/absl/base/exception_safety_testing_test.cc +++ b/absl/base/exception_safety_testing_test.cc @@ -38,7 +38,7 @@ template <typename F> void ExpectNoThrow(const F& f) { try { f(); - } catch (TestException e) { + } catch (const TestException& e) { ADD_FAILURE() << "Unexpected exception thrown from " << e.what(); } } @@ -179,7 +179,7 @@ TEST(ThrowingValueTest, ThrowingStreamOps) { } // Tests the operator<< of ThrowingValue by forcing ConstructorTracker to emit -// a nonfatal failure that contains the std::string representation of the Thrower +// a nonfatal failure that contains the string representation of the Thrower TEST(ThrowingValueTest, StreamOpsOutput) { using ::testing::TypeSpec; exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown); @@ -548,21 +548,21 @@ TEST(ExceptionSafetyTesterTest, IncompleteTypesAreNotTestable) { // Test that providing operation and inveriants still does not allow for the // the invocation of .Test() and .Test(op) because it lacks a factory auto without_fac = - testing::MakeExceptionSafetyTester().WithOperation(op).WithInvariants( + testing::MakeExceptionSafetyTester().WithOperation(op).WithContracts( inv, testing::strong_guarantee); EXPECT_FALSE(HasNullaryTest(without_fac)); EXPECT_FALSE(HasUnaryTest(without_fac)); - // Test that providing invariants and factory allows the invocation of + // Test that providing contracts and factory allows the invocation of // .Test(op) but does not allow for .Test() because it lacks an operation auto without_op = testing::MakeExceptionSafetyTester() - .WithInvariants(inv, testing::strong_guarantee) + .WithContracts(inv, testing::strong_guarantee) .WithFactory(fac); EXPECT_FALSE(HasNullaryTest(without_op)); EXPECT_TRUE(HasUnaryTest(without_op)); // Test that providing operation and factory still does not allow for the - // the invocation of .Test() and .Test(op) because it lacks invariants + // the invocation of .Test() and .Test(op) because it lacks contracts auto without_inv = testing::MakeExceptionSafetyTester().WithOperation(op).WithFactory(fac); EXPECT_FALSE(HasNullaryTest(without_inv)); @@ -577,7 +577,7 @@ std::unique_ptr<ExampleStruct> ExampleFunctionFactory() { void ExampleFunctionOperation(ExampleStruct*) {} -testing::AssertionResult ExampleFunctionInvariant(ExampleStruct*) { +testing::AssertionResult ExampleFunctionContract(ExampleStruct*) { return testing::AssertionSuccess(); } @@ -593,16 +593,16 @@ struct { struct { testing::AssertionResult operator()(ExampleStruct* example_struct) const { - return ExampleFunctionInvariant(example_struct); + return ExampleFunctionContract(example_struct); } -} example_struct_invariant; +} example_struct_contract; auto example_lambda_factory = []() { return ExampleFunctionFactory(); }; auto example_lambda_operation = [](ExampleStruct*) {}; -auto example_lambda_invariant = [](ExampleStruct* example_struct) { - return ExampleFunctionInvariant(example_struct); +auto example_lambda_contract = [](ExampleStruct* example_struct) { + return ExampleFunctionContract(example_struct); }; // Testing that function references, pointers, structs with operator() and @@ -612,28 +612,28 @@ TEST(ExceptionSafetyTesterTest, MixedFunctionTypes) { EXPECT_TRUE(testing::MakeExceptionSafetyTester() .WithFactory(ExampleFunctionFactory) .WithOperation(ExampleFunctionOperation) - .WithInvariants(ExampleFunctionInvariant) + .WithContracts(ExampleFunctionContract) .Test()); // function pointer EXPECT_TRUE(testing::MakeExceptionSafetyTester() .WithFactory(&ExampleFunctionFactory) .WithOperation(&ExampleFunctionOperation) - .WithInvariants(&ExampleFunctionInvariant) + .WithContracts(&ExampleFunctionContract) .Test()); // struct EXPECT_TRUE(testing::MakeExceptionSafetyTester() .WithFactory(example_struct_factory) .WithOperation(example_struct_operation) - .WithInvariants(example_struct_invariant) + .WithContracts(example_struct_contract) .Test()); // lambda EXPECT_TRUE(testing::MakeExceptionSafetyTester() .WithFactory(example_lambda_factory) .WithOperation(example_lambda_operation) - .WithInvariants(example_lambda_invariant) + .WithContracts(example_lambda_contract) .Test()); } @@ -658,9 +658,9 @@ struct { } invoker; auto tester = - testing::MakeExceptionSafetyTester().WithOperation(invoker).WithInvariants( + testing::MakeExceptionSafetyTester().WithOperation(invoker).WithContracts( CheckNonNegativeInvariants); -auto strong_tester = tester.WithInvariants(testing::strong_guarantee); +auto strong_tester = tester.WithContracts(testing::strong_guarantee); struct FailsBasicGuarantee : public NonNegative { void operator()() { @@ -690,7 +690,7 @@ TEST(ExceptionCheckTest, StrongGuaranteeFailure) { EXPECT_FALSE(strong_tester.WithInitialValue(FollowsBasicGuarantee{}).Test()); } -struct BasicGuaranteeWithExtraInvariants : public NonNegative { +struct BasicGuaranteeWithExtraContracts : public NonNegative { // After operator(), i is incremented. If operator() throws, i is set to 9999 void operator()() { int old_i = i; @@ -701,21 +701,21 @@ struct BasicGuaranteeWithExtraInvariants : public NonNegative { static constexpr int kExceptionSentinel = 9999; }; -constexpr int BasicGuaranteeWithExtraInvariants::kExceptionSentinel; +constexpr int BasicGuaranteeWithExtraContracts::kExceptionSentinel; -TEST(ExceptionCheckTest, BasicGuaranteeWithExtraInvariants) { +TEST(ExceptionCheckTest, BasicGuaranteeWithExtraContracts) { auto tester_with_val = - tester.WithInitialValue(BasicGuaranteeWithExtraInvariants{}); + tester.WithInitialValue(BasicGuaranteeWithExtraContracts{}); EXPECT_TRUE(tester_with_val.Test()); EXPECT_TRUE( tester_with_val - .WithInvariants([](BasicGuaranteeWithExtraInvariants* o) { - if (o->i == BasicGuaranteeWithExtraInvariants::kExceptionSentinel) { + .WithContracts([](BasicGuaranteeWithExtraContracts* o) { + if (o->i == BasicGuaranteeWithExtraContracts::kExceptionSentinel) { return testing::AssertionSuccess(); } return testing::AssertionFailure() << "i should be " - << BasicGuaranteeWithExtraInvariants::kExceptionSentinel + << BasicGuaranteeWithExtraContracts::kExceptionSentinel << ", but is " << o->i; }) .Test()); @@ -740,7 +740,7 @@ struct HasReset : public NonNegative { void reset() { i = 0; } }; -testing::AssertionResult CheckHasResetInvariants(HasReset* h) { +testing::AssertionResult CheckHasResetContracts(HasReset* h) { h->reset(); return testing::AssertionResult(h->i == 0); } @@ -759,17 +759,29 @@ TEST(ExceptionCheckTest, ModifyingChecker) { }; EXPECT_FALSE(tester.WithInitialValue(FollowsBasicGuarantee{}) - .WithInvariants(set_to_1000, is_1000) + .WithContracts(set_to_1000, is_1000) .Test()); EXPECT_TRUE(strong_tester.WithInitialValue(FollowsStrongGuarantee{}) - .WithInvariants(increment) + .WithContracts(increment) .Test()); EXPECT_TRUE(testing::MakeExceptionSafetyTester() .WithInitialValue(HasReset{}) - .WithInvariants(CheckHasResetInvariants) + .WithContracts(CheckHasResetContracts) .Test(invoker)); } +TEST(ExceptionSafetyTesterTest, ResetsCountdown) { + auto test = + testing::MakeExceptionSafetyTester() + .WithInitialValue(ThrowingValue<>()) + .WithContracts([](ThrowingValue<>*) { return AssertionSuccess(); }) + .WithOperation([](ThrowingValue<>*) {}); + ASSERT_TRUE(test.Test()); + // If the countdown isn't reset because there were no exceptions thrown, then + // this will fail with a termination from an unhandled exception + EXPECT_TRUE(test.Test()); +} + struct NonCopyable : public NonNegative { NonCopyable(const NonCopyable&) = delete; NonCopyable() : NonNegative{0} {} @@ -799,7 +811,7 @@ TEST(ExceptionCheckTest, NonEqualityComparable) { return testing::AssertionResult(nec->i == NonEqualityComparable().i); }; auto strong_nec_tester = tester.WithInitialValue(NonEqualityComparable{}) - .WithInvariants(nec_is_strong); + .WithContracts(nec_is_strong); EXPECT_TRUE(strong_nec_tester.Test()); EXPECT_FALSE(strong_nec_tester.Test( @@ -833,14 +845,14 @@ struct { testing::AssertionResult operator()(ExhaustivenessTester<T>*) const { return testing::AssertionSuccess(); } -} CheckExhaustivenessTesterInvariants; +} CheckExhaustivenessTesterContracts; template <typename T> unsigned char ExhaustivenessTester<T>::successes = 0; TEST(ExceptionCheckTest, Exhaustiveness) { auto exhaust_tester = testing::MakeExceptionSafetyTester() - .WithInvariants(CheckExhaustivenessTesterInvariants) + .WithContracts(CheckExhaustivenessTesterContracts) .WithOperation(invoker); EXPECT_TRUE( @@ -849,7 +861,7 @@ TEST(ExceptionCheckTest, Exhaustiveness) { EXPECT_TRUE( exhaust_tester.WithInitialValue(ExhaustivenessTester<ThrowingValue<>>{}) - .WithInvariants(testing::strong_guarantee) + .WithContracts(testing::strong_guarantee) .Test()); EXPECT_EQ(ExhaustivenessTester<ThrowingValue<>>::successes, 0xF); } @@ -931,8 +943,8 @@ TEST(ThrowingValueTraitsTest, RelationalOperators) { } TEST(ThrowingAllocatorTraitsTest, Assignablility) { - EXPECT_TRUE(std::is_move_assignable<ThrowingAllocator<int>>::value); - EXPECT_TRUE(std::is_copy_assignable<ThrowingAllocator<int>>::value); + EXPECT_TRUE(absl::is_move_assignable<ThrowingAllocator<int>>::value); + EXPECT_TRUE(absl::is_copy_assignable<ThrowingAllocator<int>>::value); EXPECT_TRUE(std::is_nothrow_move_assignable<ThrowingAllocator<int>>::value); EXPECT_TRUE(std::is_nothrow_copy_assignable<ThrowingAllocator<int>>::value); } diff --git a/absl/base/inline_variable_test.cc b/absl/base/inline_variable_test.cc index b34aebd8..b968b10f 100644 --- a/absl/base/inline_variable_test.cc +++ b/absl/base/inline_variable_test.cc @@ -20,7 +20,7 @@ #include "gtest/gtest.h" namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace inline_variable_testing_internal { namespace { @@ -60,5 +60,5 @@ TEST(InlineVariableTest, FunPtrType) { } // namespace } // namespace inline_variable_testing_internal -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl diff --git a/absl/base/inline_variable_test_a.cc b/absl/base/inline_variable_test_a.cc index 0ea363af..a51b1d81 100644 --- a/absl/base/inline_variable_test_a.cc +++ b/absl/base/inline_variable_test_a.cc @@ -15,7 +15,7 @@ #include "absl/base/internal/inline_variable_testing.h" namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace inline_variable_testing_internal { const Foo& get_foo_a() { return inline_variable_foo; } @@ -23,5 +23,5 @@ const Foo& get_foo_a() { return inline_variable_foo; } const int& get_int_a() { return inline_variable_int; } } // namespace inline_variable_testing_internal -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl diff --git a/absl/base/inline_variable_test_b.cc b/absl/base/inline_variable_test_b.cc index 32704cf1..5041e20a 100644 --- a/absl/base/inline_variable_test_b.cc +++ b/absl/base/inline_variable_test_b.cc @@ -15,7 +15,7 @@ #include "absl/base/internal/inline_variable_testing.h" namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace inline_variable_testing_internal { const Foo& get_foo_b() { return inline_variable_foo; } @@ -23,5 +23,5 @@ const Foo& get_foo_b() { return inline_variable_foo; } const int& get_int_b() { return inline_variable_int; } } // namespace inline_variable_testing_internal -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl 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 diff --git a/absl/base/invoke_test.cc b/absl/base/invoke_test.cc index 2c04b591..4df637ac 100644 --- a/absl/base/invoke_test.cc +++ b/absl/base/invoke_test.cc @@ -25,7 +25,7 @@ #include "absl/strings/str_cat.h" namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace base_internal { namespace { @@ -198,5 +198,5 @@ TEST(InvokeTest, SfinaeFriendly) { } // namespace } // namespace base_internal -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl diff --git a/absl/base/log_severity.h b/absl/base/log_severity.h index 8b7a66ba..c24fad79 100644 --- a/absl/base/log_severity.h +++ b/absl/base/log_severity.h @@ -21,7 +21,7 @@ #include "absl/base/attributes.h" namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { // Four severity levels are defined. Logging APIs should terminate the program // when a message is logged at severity `kFatal`; the other levels have no @@ -40,7 +40,7 @@ constexpr std::array<absl::LogSeverity, 4> LogSeverities() { absl::LogSeverity::kError, absl::LogSeverity::kFatal}}; } -// Returns the all-caps std::string representation (e.g. "INFO") of the specified +// Returns the all-caps string representation (e.g. "INFO") of the specified // severity level if it is one of the normal levels and "UNKNOWN" otherwise. constexpr const char* LogSeverityName(absl::LogSeverity s) { return s == absl::LogSeverity::kInfo @@ -63,7 +63,7 @@ constexpr absl::LogSeverity NormalizeLogSeverity(int s) { return NormalizeLogSeverity(static_cast<absl::LogSeverity>(s)); } -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl #endif // ABSL_BASE_INTERNAL_LOG_SEVERITY_H_ diff --git a/absl/base/macros.h b/absl/base/macros.h index aabe8db4..14c4b0a3 100644 --- a/absl/base/macros.h +++ b/absl/base/macros.h @@ -43,14 +43,14 @@ (sizeof(::absl::macros_internal::ArraySizeHelper(array))) namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace macros_internal { // Note: this internal template function declaration is used by ABSL_ARRAYSIZE. // The function doesn't need a definition, as we only use its type. template <typename T, size_t N> auto ArraySizeHelper(const T (&array)[N]) -> char (&)[N]; } // namespace macros_internal -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl // kLinkerInitialized @@ -74,13 +74,13 @@ auto ArraySizeHelper(const T (&array)[N]) -> char (&)[N]; // // Invocation // static MyClass my_global(absl::base_internal::kLinkerInitialized); namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace base_internal { enum LinkerInitialized { kLinkerInitialized = 0, }; } // namespace base_internal -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl // ABSL_FALLTHROUGH_INTENDED @@ -203,4 +203,14 @@ enum LinkerInitialized { : [] { assert(false && #expr); }()) // NOLINT #endif +#ifdef ABSL_HAVE_EXCEPTIONS +#define ABSL_INTERNAL_TRY try +#define ABSL_INTERNAL_CATCH_ANY catch (...) +#define ABSL_INTERNAL_RETHROW do { throw; } while (false) +#else // ABSL_HAVE_EXCEPTIONS +#define ABSL_INTERNAL_TRY if (true) +#define ABSL_INTERNAL_CATCH_ANY else if (false) +#define ABSL_INTERNAL_RETHROW do {} while (false) +#endif // ABSL_HAVE_EXCEPTIONS + #endif // ABSL_BASE_MACROS_H_ diff --git a/absl/base/raw_logging_test.cc b/absl/base/raw_logging_test.cc index dae4b351..b21cf651 100644 --- a/absl/base/raw_logging_test.cc +++ b/absl/base/raw_logging_test.cc @@ -18,12 +18,20 @@ #include "absl/base/internal/raw_logging.h" +#include <tuple> + #include "gtest/gtest.h" +#include "absl/strings/str_cat.h" namespace { TEST(RawLoggingCompilationTest, Log) { ABSL_RAW_LOG(INFO, "RAW INFO: %d", 1); + ABSL_RAW_LOG(INFO, "RAW INFO: %d %d", 1, 2); + ABSL_RAW_LOG(INFO, "RAW INFO: %d %d %d", 1, 2, 3); + ABSL_RAW_LOG(INFO, "RAW INFO: %d %d %d %d", 1, 2, 3, 4); + ABSL_RAW_LOG(INFO, "RAW INFO: %d %d %d %d %d", 1, 2, 3, 4, 5); + ABSL_RAW_LOG(WARNING, "RAW WARNING: %d", 1); ABSL_RAW_LOG(ERROR, "RAW ERROR: %d", 1); } @@ -32,7 +40,7 @@ TEST(RawLoggingCompilationTest, PassingCheck) { } // Not all platforms support output from raw log, so we don't verify any -// particular output for RAW check failures (expecting the empty std::string +// particular output for RAW check failures (expecting the empty string // accomplishes this). This test is primarily a compilation test, but we // are verifying process death when EXPECT_DEATH works for a platform. const char kExpectedDeathOutput[] = ""; @@ -47,4 +55,25 @@ TEST(RawLoggingDeathTest, LogFatal) { kExpectedDeathOutput); } +TEST(InternalLog, CompilationTest) { + ABSL_INTERNAL_LOG(INFO, "Internal Log"); + std::string log_msg = "Internal Log"; + ABSL_INTERNAL_LOG(INFO, log_msg); + + ABSL_INTERNAL_LOG(INFO, log_msg + " 2"); + + float d = 1.1f; + ABSL_INTERNAL_LOG(INFO, absl::StrCat("Internal log ", 3, " + ", d)); +} + +TEST(InternalLogDeathTest, FailingCheck) { + EXPECT_DEATH_IF_SUPPORTED(ABSL_INTERNAL_CHECK(1 == 0, "explanation"), + kExpectedDeathOutput); +} + +TEST(InternalLogDeathTest, LogFatal) { + EXPECT_DEATH_IF_SUPPORTED(ABSL_INTERNAL_LOG(FATAL, "my dog has fleas"), + kExpectedDeathOutput); +} + } // namespace diff --git a/absl/base/spinlock_test_common.cc b/absl/base/spinlock_test_common.cc index d04ee366..95382977 100644 --- a/absl/base/spinlock_test_common.cc +++ b/absl/base/spinlock_test_common.cc @@ -36,7 +36,7 @@ constexpr int32_t kNumThreads = 10; constexpr int32_t kIters = 1000; namespace absl { -inline namespace lts_2018_06_20 { +inline namespace lts_2018_12_18 { namespace base_internal { // This is defined outside of anonymous namespace so that it can be @@ -156,7 +156,8 @@ TEST(SpinLock, WaitCyclesEncoding) { // Test corner cases int64_t start_time = time_distribution(generator); - EXPECT_EQ(0, SpinLockTest::EncodeWaitCycles(start_time, start_time)); + EXPECT_EQ(kSpinLockSleeper, + SpinLockTest::EncodeWaitCycles(start_time, start_time)); EXPECT_EQ(0, SpinLockTest::DecodeWaitCycles(0)); EXPECT_EQ(0, SpinLockTest::DecodeWaitCycles(kLockwordReservedMask)); EXPECT_EQ(kMaxCycles & ~kProfileTimestampMask, @@ -264,5 +265,5 @@ TEST(SpinLockWithThreads, DoesNotDeadlock) { } // namespace } // namespace base_internal -} // inline namespace lts_2018_06_20 +} // inline namespace lts_2018_12_18 } // namespace absl diff --git a/absl/base/thread_annotations.h b/absl/base/thread_annotations.h index 8d30b932..2241ace4 100644 --- a/absl/base/thread_annotations.h +++ b/absl/base/thread_annotations.h @@ -31,7 +31,6 @@ // that evaluate to a concrete mutex object whenever possible. If the mutex // you want to refer to is not in scope, you may use a member pointer // (e.g. &MyClass::mutex_) to refer to a mutex in some (unknown) object. -// #ifndef ABSL_BASE_THREAD_ANNOTATIONS_H_ #define ABSL_BASE_THREAD_ANNOTATIONS_H_ @@ -109,13 +108,23 @@ // The mutex is expected to be held both on entry to, and exit from, the // function. // +// An exclusive lock allows read-write access to the guarded data member(s), and +// only one thread can acquire a lock exclusively at any one time. A shared lock +// allows read-only access, and any number of threads can acquire a shared lock +// concurrently. +// +// Generally, non-const methods should be annotated with +// EXCLUSIVE_LOCKS_REQUIRED, while const methods should be annotated with +// SHARED_LOCKS_REQUIRED. +// // Example: // // Mutex mu1, mu2; // int a GUARDED_BY(mu1); // int b GUARDED_BY(mu2); // -// void foo() EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... }; +// void foo() EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... } +// void bar() const SHARED_LOCKS_REQUIRED(mu1, mu2) { ... } #define EXCLUSIVE_LOCKS_REQUIRED(...) \ THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__)) |