From 322ae2420d27fc96d0a8ab1167d7de33671048df Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Tue, 12 Jan 2021 07:36:20 -0800 Subject: Export of internal Abseil changes -- 1609589925459c2c0b2a17912c0d65227f709db9 by Abseil Team : Clarify the "Potential Mutex deadlock" reason message. PiperOrigin-RevId: 351367862 -- 88bf28863db2c2d2d48767c3e4dfab6a48bdff79 by Abseil Team : Print CPU number is fault handler. This CL adds code to print CPU number inside the fault handler. This is only supported on Linux. The CPU number is also a hint only. There is no guarantee that it is indeed the CPU on which a fault happened. PiperOrigin-RevId: 351238373 -- 66a9c8e44b5744fec1ca0d7b8db7e1d50772d9a2 by Samuel Benzaquen : Add better error message for ODR violations of flags. PiperOrigin-RevId: 351197423 -- 6efd1efb341563148dd43255aaa4bf959dfd9554 by Chris Kennelly : Assume bitwise builtins are available on GCC. These are long-standing builtins but are not consistently detected by ABSL_HAVE_BUILTIN. PiperOrigin-RevId: 350814036 GitOrigin-RevId: 1609589925459c2c0b2a17912c0d65227f709db9 Change-Id: Ied3fd2f135187f2c316b403fba45f3bbaea54138 --- absl/base/config.h | 9 +++++++ absl/debugging/failure_signal_handler.cc | 36 +++++++++++++++++++-------- absl/debugging/failure_signal_handler_test.cc | 6 +++++ absl/flags/flag.h | 10 +++++--- absl/flags/flag_test.cc | 2 +- absl/flags/internal/flag.h | 5 ++-- absl/flags/internal/registry.h | 2 +- absl/flags/reflection.cc | 23 +++++++++++++---- absl/numeric/bits_test.cc | 8 ++++++ absl/numeric/internal/bits.h | 29 +++++++++++++-------- absl/synchronization/mutex.cc | 4 ++- 11 files changed, 100 insertions(+), 34 deletions(-) diff --git a/absl/base/config.h b/absl/base/config.h index c9a06f1d..f6ddf0c5 100644 --- a/absl/base/config.h +++ b/absl/base/config.h @@ -379,6 +379,15 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || #define ABSL_HAVE_PTHREAD_GETSCHEDPARAM 1 #endif +// ABSL_HAVE_SCHED_GETCPU +// +// Checks whether sched_getcpu is available. +#ifdef ABSL_HAVE_SCHED_GETCPU +#error ABSL_HAVE_SCHED_GETCPU cannot be directly set +#elif defined(__linux__) +#define ABSL_HAVE_SCHED_GETCPU 1 +#endif + // ABSL_HAVE_SCHED_YIELD // // Checks whether the platform implements sched_yield(2) as defined in diff --git a/absl/debugging/failure_signal_handler.cc b/absl/debugging/failure_signal_handler.cc index 5d13bdbb..a9ed6ef9 100644 --- a/absl/debugging/failure_signal_handler.cc +++ b/absl/debugging/failure_signal_handler.cc @@ -21,6 +21,7 @@ #ifdef _WIN32 #include #else +#include #include #endif @@ -219,17 +220,24 @@ static void WriteToStderr(const char* data) { absl::raw_logging_internal::SafeWriteToStderr(data, strlen(data)); } -static void WriteSignalMessage(int signo, void (*writerfn)(const char*)) { - char buf[64]; +static void WriteSignalMessage(int signo, int cpu, + void (*writerfn)(const char*)) { + char buf[96]; + char on_cpu[32] = {0}; + if (cpu != -1) { + snprintf(on_cpu, sizeof(on_cpu), " on cpu %d", cpu); + } const char* const signal_string = debugging_internal::FailureSignalToString(signo); if (signal_string != nullptr && signal_string[0] != '\0') { - snprintf(buf, sizeof(buf), "*** %s received at time=%ld ***\n", + snprintf(buf, sizeof(buf), "*** %s received at time=%ld%s ***\n", signal_string, - static_cast(time(nullptr))); // NOLINT(runtime/int) + static_cast(time(nullptr)), // NOLINT(runtime/int) + on_cpu); } else { - snprintf(buf, sizeof(buf), "*** Signal %d received at time=%ld ***\n", - signo, static_cast(time(nullptr))); // NOLINT(runtime/int) + snprintf(buf, sizeof(buf), "*** Signal %d received at time=%ld%s ***\n", + signo, static_cast(time(nullptr)), // NOLINT(runtime/int) + on_cpu); } writerfn(buf); } @@ -269,10 +277,10 @@ ABSL_ATTRIBUTE_NOINLINE static void WriteStackTrace( // Called by AbslFailureSignalHandler() to write the failure info. It is // called once with writerfn set to WriteToStderr() and then possibly // with writerfn set to the user provided function. -static void WriteFailureInfo(int signo, void* ucontext, +static void WriteFailureInfo(int signo, void* ucontext, int cpu, void (*writerfn)(const char*)) { WriterFnStruct writerfn_struct{writerfn}; - WriteSignalMessage(signo, writerfn); + WriteSignalMessage(signo, cpu, writerfn); WriteStackTrace(ucontext, fsh_options.symbolize_stacktrace, WriterFnWrapper, &writerfn_struct); } @@ -334,6 +342,14 @@ static void AbslFailureSignalHandler(int signo, siginfo_t*, void* ucontext) { } } + // Increase the chance that the CPU we report was the same CPU on which the + // signal was received by doing this as early as possible, i.e. after + // verifying that this is not a recursive signal handler invocation. + int my_cpu = -1; +#ifdef ABSL_HAVE_SCHED_GETCPU + my_cpu = sched_getcpu(); +#endif + #ifdef ABSL_HAVE_ALARM // Set an alarm to abort the program in case this code hangs or deadlocks. if (fsh_options.alarm_on_failure_secs > 0) { @@ -344,12 +360,12 @@ static void AbslFailureSignalHandler(int signo, siginfo_t*, void* ucontext) { #endif // First write to stderr. - WriteFailureInfo(signo, ucontext, WriteToStderr); + WriteFailureInfo(signo, ucontext, my_cpu, WriteToStderr); // Riskier code (because it is less likely to be async-signal-safe) // goes after this point. if (fsh_options.writerfn != nullptr) { - WriteFailureInfo(signo, ucontext, fsh_options.writerfn); + WriteFailureInfo(signo, ucontext, my_cpu, fsh_options.writerfn); } if (fsh_options.call_previous_handler) { diff --git a/absl/debugging/failure_signal_handler_test.cc b/absl/debugging/failure_signal_handler_test.cc index d8283b2f..6a62428b 100644 --- a/absl/debugging/failure_signal_handler_test.cc +++ b/absl/debugging/failure_signal_handler_test.cc @@ -122,6 +122,12 @@ TEST_P(FailureSignalHandlerDeathTest, AbslFatalSignalsWithWriterFn) { "*** ", absl::debugging_internal::FailureSignalToString(signo), " received at "))); + // On platforms where it is possible to get the current CPU, the + // CPU number is also logged. Check that it is present in output. +#if defined(__linux__) + EXPECT_THAT(error_line, testing::HasSubstr(" on cpu ")); +#endif + if (absl::debugging_internal::StackTraceWorksForTest()) { std::getline(error_output, error_line); EXPECT_THAT(error_line, StartsWith("PC: ")); diff --git a/absl/flags/flag.h b/absl/flags/flag.h index a9cb2b79..f09580b0 100644 --- a/absl/flags/flag.h +++ b/absl/flags/flag.h @@ -301,13 +301,15 @@ ABSL_NAMESPACE_END #if ABSL_FLAGS_STRIP_NAMES #define ABSL_FLAG_IMPL_FLAGNAME(txt) "" #define ABSL_FLAG_IMPL_FILENAME() "" -#define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \ - absl::flags_internal::FlagRegistrar(ABSL_FLAG_IMPL_FLAG_PTR(flag)) +#define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \ + absl::flags_internal::FlagRegistrar(ABSL_FLAG_IMPL_FLAG_PTR(flag), \ + nullptr) #else #define ABSL_FLAG_IMPL_FLAGNAME(txt) txt #define ABSL_FLAG_IMPL_FILENAME() __FILE__ -#define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \ - absl::flags_internal::FlagRegistrar(ABSL_FLAG_IMPL_FLAG_PTR(flag)) +#define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \ + absl::flags_internal::FlagRegistrar(ABSL_FLAG_IMPL_FLAG_PTR(flag), \ + __FILE__) #endif // ABSL_FLAG_IMPL macro definition conditional on ABSL_FLAGS_STRIP_HELP diff --git a/absl/flags/flag_test.cc b/absl/flags/flag_test.cc index 72507b99..6912b546 100644 --- a/absl/flags/flag_test.cc +++ b/absl/flags/flag_test.cc @@ -177,7 +177,7 @@ bool TestConstructionFor(const absl::Flag& f1, absl::Flag& f2) { EXPECT_EQ(absl::GetFlagReflectionHandle(f1).Help(), "literal help"); EXPECT_EQ(absl::GetFlagReflectionHandle(f1).Filename(), "file"); - flags::FlagRegistrar(ABSL_FLAG_IMPL_FLAG_PTR(f2)) + flags::FlagRegistrar(ABSL_FLAG_IMPL_FLAG_PTR(f2), nullptr) .OnUpdate(TestCallback); EXPECT_EQ(absl::GetFlagReflectionHandle(f2).Name(), "f2"); diff --git a/absl/flags/internal/flag.h b/absl/flags/internal/flag.h index 83548143..e6bade0a 100644 --- a/absl/flags/internal/flag.h +++ b/absl/flags/internal/flag.h @@ -721,8 +721,9 @@ struct FlagRegistrarEmpty {}; template class FlagRegistrar { public: - explicit FlagRegistrar(Flag& flag) : flag_(flag) { - if (do_register) flags_internal::RegisterCommandLineFlag(flag_.impl_); + explicit FlagRegistrar(Flag& flag, const char* filename) : flag_(flag) { + if (do_register) + flags_internal::RegisterCommandLineFlag(flag_.impl_, filename); } FlagRegistrar OnUpdate(FlagCallbackFunc cb) && { diff --git a/absl/flags/internal/registry.h b/absl/flags/internal/registry.h index a8d9eb9c..4b68c85f 100644 --- a/absl/flags/internal/registry.h +++ b/absl/flags/internal/registry.h @@ -36,7 +36,7 @@ void ForEachFlag(std::function visitor); //----------------------------------------------------------------------------- -bool RegisterCommandLineFlag(CommandLineFlag&); +bool RegisterCommandLineFlag(CommandLineFlag&, const char* filename); void FinalizeRegistry(); diff --git a/absl/flags/reflection.cc b/absl/flags/reflection.cc index c976d467..0c761101 100644 --- a/absl/flags/reflection.cc +++ b/absl/flags/reflection.cc @@ -50,7 +50,7 @@ class FlagRegistry { ~FlagRegistry() = default; // Store a flag in this registry. Takes ownership of *flag. - void RegisterFlag(CommandLineFlag& flag); + void RegisterFlag(CommandLineFlag& flag, const char* filename); void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION(lock_) { lock_.Lock(); } void Unlock() ABSL_UNLOCK_FUNCTION(lock_) { lock_.Unlock(); } @@ -110,7 +110,20 @@ CommandLineFlag* FlagRegistry::FindFlag(absl::string_view name) { return it != flags_.end() ? it->second : nullptr; } -void FlagRegistry::RegisterFlag(CommandLineFlag& flag) { +void FlagRegistry::RegisterFlag(CommandLineFlag& flag, const char* filename) { + if (filename != nullptr && + flag.Filename() != GetUsageConfig().normalize_filename(filename)) { + flags_internal::ReportUsageError( + absl::StrCat( + "Inconsistency between flag object and registration for flag '", + flag.Name(), + "', likely due to duplicate flags or an ODR violation. Relevant " + "files: ", + flag.Filename(), " and ", filename), + true); + std::exit(1); + } + FlagRegistryLock registry_lock(*this); std::pair ins = @@ -175,8 +188,8 @@ void ForEachFlag(std::function visitor) { // -------------------------------------------------------------------- -bool RegisterCommandLineFlag(CommandLineFlag& flag) { - FlagRegistry::GlobalRegistry().RegisterFlag(flag); +bool RegisterCommandLineFlag(CommandLineFlag& flag, const char* filename) { + FlagRegistry::GlobalRegistry().RegisterFlag(flag, filename); return true; } @@ -266,7 +279,7 @@ void Retire(const char* name, FlagFastTypeId type_id, char* buf) { static_assert(alignof(RetiredFlagObj) == kRetiredFlagObjAlignment, ""); auto* flag = ::new (static_cast(buf)) flags_internal::RetiredFlagObj(name, type_id); - FlagRegistry::GlobalRegistry().RegisterFlag(*flag); + FlagRegistry::GlobalRegistry().RegisterFlag(*flag, nullptr); } // -------------------------------------------------------------------- diff --git a/absl/numeric/bits_test.cc b/absl/numeric/bits_test.cc index 8bf7bc9f..7c942aae 100644 --- a/absl/numeric/bits_test.cc +++ b/absl/numeric/bits_test.cc @@ -560,6 +560,14 @@ TEST(IntegralPowersOfTwo, Width) { } } +// On GCC and Clang, anticiapte that implementations will be constexpr +#if defined(__GNUC__) +static_assert(ABSL_INTERNAL_HAS_CONSTEXPR_POPCOUNT, + "popcount should be constexpr"); +static_assert(ABSL_INTERNAL_HAS_CONSTEXPR_CLZ, "clz should be constexpr"); +static_assert(ABSL_INTERNAL_HAS_CONSTEXPR_CTZ, "ctz should be constexpr"); +#endif + } // namespace ABSL_NAMESPACE_END } // namespace absl diff --git a/absl/numeric/internal/bits.h b/absl/numeric/internal/bits.h index af45700f..e51941d7 100644 --- a/absl/numeric/internal/bits.h +++ b/absl/numeric/internal/bits.h @@ -28,8 +28,15 @@ #include "absl/base/attributes.h" #include "absl/base/config.h" -#if ABSL_HAVE_BUILTIN(__builtin_popcountl) && \ - ABSL_HAVE_BUILTIN(__builtin_popcountll) +#if defined(__GNUC__) && !defined(__clang__) +// GCC +#define ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(x) 1 +#else +#define ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(x) ABSL_HAVE_BUILTIN(x) +#endif + +#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_popcountl) && \ + ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_popcountll) #define ABSL_INTERNAL_CONSTEXPR_POPCOUNT constexpr #define ABSL_INTERNAL_HAS_CONSTEXPR_POPCOUNT 1 #else @@ -37,7 +44,8 @@ #define ABSL_INTERNAL_HAS_CONSTEXPR_POPCOUNT 0 #endif -#if ABSL_HAVE_BUILTIN(__builtin_clz) && ABSL_HAVE_BUILTIN(__builtin_clzll) +#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_clz) && \ + ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_clzll) #define ABSL_INTERNAL_CONSTEXPR_CLZ constexpr #define ABSL_INTERNAL_HAS_CONSTEXPR_CLZ 1 #else @@ -45,7 +53,8 @@ #define ABSL_INTERNAL_HAS_CONSTEXPR_CLZ 0 #endif -#if ABSL_HAVE_BUILTIN(__builtin_ctz) && ABSL_HAVE_BUILTIN(__builtin_ctzll) +#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_ctz) && \ + ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_ctzll) #define ABSL_INTERNAL_CONSTEXPR_CTZ constexpr #define ABSL_INTERNAL_HAS_CONSTEXPR_CTZ 1 #else @@ -85,7 +94,7 @@ ABSL_MUST_USE_RESULT ABSL_ATTRIBUTE_ALWAYS_INLINE constexpr T RotateLeft( ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_POPCOUNT inline int Popcount32(uint32_t x) noexcept { -#if ABSL_HAVE_BUILTIN(__builtin_popcount) +#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_popcount) static_assert(sizeof(unsigned int) == sizeof(x), "__builtin_popcount does not take 32-bit arg"); return __builtin_popcount(x); @@ -98,7 +107,7 @@ Popcount32(uint32_t x) noexcept { ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_POPCOUNT inline int Popcount64(uint64_t x) noexcept { -#if ABSL_HAVE_BUILTIN(__builtin_popcountll) +#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_popcountll) static_assert(sizeof(unsigned long long) == sizeof(x), // NOLINT(runtime/int) "__builtin_popcount does not take 64-bit arg"); return __builtin_popcountll(x); @@ -122,7 +131,7 @@ Popcount(T x) noexcept { ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline int CountLeadingZeroes32(uint32_t x) { -#if ABSL_HAVE_BUILTIN(__builtin_clz) +#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_clz) // Use __builtin_clz, which uses the following instructions: // x86: bsr, lzcnt // ARM64: clz @@ -169,7 +178,7 @@ CountLeadingZeroes16(uint16_t x) { ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline int CountLeadingZeroes64(uint64_t x) { -#if ABSL_HAVE_BUILTIN(__builtin_clzll) +#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_clzll) // Use __builtin_clzll, which uses the following instructions: // x86: bsr, lzcnt // ARM64: clz @@ -240,7 +249,7 @@ CountLeadingZeroes(T x) { ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CTZ inline int CountTrailingZeroesNonzero32(uint32_t x) { -#if ABSL_HAVE_BUILTIN(__builtin_ctz) +#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_ctz) static_assert(sizeof(unsigned int) == sizeof(x), "__builtin_ctz does not take 32-bit arg"); return __builtin_ctz(x); @@ -262,7 +271,7 @@ CountTrailingZeroesNonzero32(uint32_t x) { ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CTZ inline int CountTrailingZeroesNonzero64(uint64_t x) { -#if ABSL_HAVE_BUILTIN(__builtin_ctzll) +#if ABSL_NUMERIC_INTERNAL_HAVE_BUILTIN_OR_GCC(__builtin_ctzll) static_assert(sizeof(unsigned long long) == sizeof(x), // NOLINT(runtime/int) "__builtin_ctzll does not take 64-bit arg"); return __builtin_ctzll(x); diff --git a/absl/synchronization/mutex.cc b/absl/synchronization/mutex.cc index d2468ce5..7e66a7d0 100644 --- a/absl/synchronization/mutex.cc +++ b/absl/synchronization/mutex.cc @@ -1372,7 +1372,9 @@ static GraphId DeadlockCheck(Mutex *mu) { len += static_cast(strlen(&b->buf[len])); } } - ABSL_RAW_LOG(ERROR, "Acquiring %p Mutexes held: %s", + ABSL_RAW_LOG(ERROR, + "Acquiring absl::Mutex %p while holding %s; a cycle in the " + "historical lock ordering graph has been observed", static_cast(mu), b->buf); ABSL_RAW_LOG(ERROR, "Cycle: "); int path_len = deadlock_graph->FindPath( -- cgit v1.2.3