Commit 81f34df8 by Abseil Team Committed by Derek Mauro

Export of internal Abseil changes

--
739f9fb80212c21c015fec473e9e29803a156ef9 by Derek Mauro <dmauro@google.com>:

Define FlagStateInterface::~FlagStateInterface() in the translation
unit in which it is actually declared

Fixes #717

PiperOrigin-RevId: 319083605

--
913ef1f23113268b22d636d3ae3b992862efdb1a by Derek Mauro <dmauro@google.com>:

Fix ABSL_LOCK_RETURNED statement

PiperOrigin-RevId: 319078667

--
a43b1413da1770d638147c73e7e1693cfaf869c7 by Derek Mauro <dmauro@google.com>:

Fix redeclaration ‘absl::Cord::InlineRep::kMaxInline’, which differs in ‘constexpr’
Fixes #725

PiperOrigin-RevId: 319060910

--
1ad7d491a80f6c9de78a6fc20f09b7765d224503 by Abseil Team <absl-team@google.com>:

Make absl SpinLock trivially destructible when possible

PiperOrigin-RevId: 319049456

--
659ecad3578dfa669854a82279fa590002bdb37f by Derek Mauro <dmauro@google.com>:

Remove the static initialization of global variables used by absl::Mutex
as requested by Chromium

PiperOrigin-RevId: 319031204

--
609c491d8bb4f8bb3b44c5a4c0bee51c583df24c by Abseil Team <absl-team@google.com>:

Add implementation of %a and %A to absl::StrFormat.

Prior to this it just fell back to sprintf.

PiperOrigin-RevId: 318888039

--
5e8ae6392bcd135248aac14c4b9f2a5116868678 by Abseil Team <absl-team@google.com>:

Google-internal changes only.

PiperOrigin-RevId: 318857077

--
4a2578e33e8442954e29e5f0380ddfcf0f033f0d by Greg Falcon <gfalcon@google.com>:

Change of enum constants to accommodate internal change.

PiperOrigin-RevId: 318844716

--
4b578b102816260c213675759f4c15911735578a by Abseil Team <absl-team@google.com>:

Internal change

PiperOrigin-RevId: 318704453

--
0ee82fd24d548b260c9229fa1f54571dae1dfa24 by Gennadiy Rozental <rogeeff@google.com>:

Allow lookup of retired flags.

At the moment we issue warning on attempt to find a retired flag. This way we can't even check if flag is retired without issuing the warning.

With this change we will only issue the warning if one tries to access any functionality of retired flag but it's name "is retired" status, and type.

PiperOrigin-RevId: 318605017

--
3e35fe9b4c79f636fa328c59e2aabb93e29b7c99 by Abseil Team <absl-team@google.com>:

Fix error return from InstallSymbolDecorator().

PiperOrigin-RevId: 318490405

--
ae46063f3eb2998cb961f62a359d932e5908a4bc by Abseil Team <absl-team@google.com>:

Do not make copies of iterated collection elements into the loop variable.

PiperOrigin-RevId: 318423139

--
d06a075a12aab5f6ab98474677ce50d588b21de3 by Abseil Team <absl-team@google.com>:

add missing word making the error code better English

PiperOrigin-RevId: 318335052
GitOrigin-RevId: 739f9fb80212c21c015fec473e9e29803a156ef9
Change-Id: Id77a0a4b1959036b00555deef40e82d51884fbc1
parent b86fff16
...@@ -29,9 +29,6 @@ extern "C" void __google_enable_rescheduling(bool disable_result); ...@@ -29,9 +29,6 @@ extern "C" void __google_enable_rescheduling(bool disable_result);
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
class CondVar;
class Mutex;
namespace base_internal { namespace base_internal {
class SchedulingHelper; // To allow use of SchedulingGuard. class SchedulingHelper; // To allow use of SchedulingGuard.
...@@ -80,8 +77,6 @@ class SchedulingGuard { ...@@ -80,8 +77,6 @@ class SchedulingGuard {
}; };
// Access to SchedulingGuard is explicitly permitted. // Access to SchedulingGuard is explicitly permitted.
friend class absl::CondVar;
friend class absl::Mutex;
friend class SchedulingHelper; friend class SchedulingHelper;
friend class SpinLock; friend class SpinLock;
......
...@@ -64,7 +64,14 @@ class ABSL_LOCKABLE SpinLock { ...@@ -64,7 +64,14 @@ class ABSL_LOCKABLE SpinLock {
constexpr SpinLock(absl::ConstInitType, base_internal::SchedulingMode mode) constexpr SpinLock(absl::ConstInitType, base_internal::SchedulingMode mode)
: lockword_(IsCooperative(mode) ? kSpinLockCooperative : 0) {} : lockword_(IsCooperative(mode) ? kSpinLockCooperative : 0) {}
// For global SpinLock instances prefer trivial destructor when possible.
// Default but non-trivial destructor in some build configurations causes an
// extra static initializer.
#ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE
~SpinLock() { ABSL_TSAN_MUTEX_DESTROY(this, __tsan_mutex_not_static); } ~SpinLock() { ABSL_TSAN_MUTEX_DESTROY(this, __tsan_mutex_not_static); }
#else
~SpinLock() = default;
#endif
// Acquire this SpinLock. // Acquire this SpinLock.
inline void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() { inline void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() {
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <limits> #include <limits>
#include <random> #include <random>
#include <thread> // NOLINT(build/c++11) #include <thread> // NOLINT(build/c++11)
#include <type_traits>
#include <vector> #include <vector>
#include "gtest/gtest.h" #include "gtest/gtest.h"
...@@ -103,6 +104,10 @@ static void ThreadedTest(SpinLock* spinlock) { ...@@ -103,6 +104,10 @@ static void ThreadedTest(SpinLock* spinlock) {
} }
} }
#ifndef THREAD_SANITIZER
static_assert(std::is_trivially_destructible<SpinLock>(), "");
#endif
TEST(SpinLock, StackNonCooperativeDisablesScheduling) { TEST(SpinLock, StackNonCooperativeDisablesScheduling) {
SpinLock spinlock(base_internal::SCHEDULE_KERNEL_ONLY); SpinLock spinlock(base_internal::SCHEDULE_KERNEL_ONLY);
spinlock.Lock(); spinlock.Lock();
......
...@@ -337,11 +337,11 @@ ABSL_NAMESPACE_END ...@@ -337,11 +337,11 @@ ABSL_NAMESPACE_END
} // namespace absl } // namespace absl
enum Hash : size_t { enum Hash : size_t {
kStd = 0x2, // std::hash kStd = 0x1, // std::hash
#ifdef _MSC_VER #ifdef _MSC_VER
kExtension = kStd, // In MSVC, std::hash == ::hash kExtension = kStd, // In MSVC, std::hash == ::hash
#else // _MSC_VER #else // _MSC_VER
kExtension = 0x4, // ::hash (GCC extension) kExtension = 0x2, // ::hash (GCC extension)
#endif // _MSC_VER #endif // _MSC_VER
}; };
......
...@@ -1376,7 +1376,7 @@ int InstallSymbolDecorator(SymbolDecorator decorator, void *arg) { ...@@ -1376,7 +1376,7 @@ int InstallSymbolDecorator(SymbolDecorator decorator, void *arg) {
if (!g_decorators_mu.TryLock()) { if (!g_decorators_mu.TryLock()) {
// Someone else is using decorators. Get out. // Someone else is using decorators. Get out.
return false; return -2;
} }
int ret = ticket; int ret = ticket;
if (g_num_decorators >= kMaxDecorators) { if (g_num_decorators >= kMaxDecorators) {
......
...@@ -106,6 +106,9 @@ cc_library( ...@@ -106,6 +106,9 @@ cc_library(
cc_library( cc_library(
name = "commandlineflag_internal", name = "commandlineflag_internal",
srcs = [
"internal/commandlineflag.cc",
],
hdrs = [ hdrs = [
"internal/commandlineflag.h", "internal/commandlineflag.h",
], ],
......
...@@ -95,6 +95,8 @@ absl_cc_library( ...@@ -95,6 +95,8 @@ absl_cc_library(
absl_cc_library( absl_cc_library(
NAME NAME
flags_commandlineflag_internal flags_commandlineflag_internal
SRCS
"internal/commandlineflag.cc"
HDRS HDRS
"internal/commandlineflag.h" "internal/commandlineflag.h"
COPTS COPTS
......
...@@ -30,9 +30,5 @@ bool CommandLineFlag::ParseFrom(absl::string_view value, std::string* error) { ...@@ -30,9 +30,5 @@ bool CommandLineFlag::ParseFrom(absl::string_view value, std::string* error) {
flags_internal::kProgrammaticChange, *error); flags_internal::kProgrammaticChange, *error);
} }
namespace flags_internal {
FlagStateInterface::~FlagStateInterface() {}
} // namespace flags_internal
ABSL_NAMESPACE_END ABSL_NAMESPACE_END
} // namespace absl } // namespace absl
...@@ -108,6 +108,10 @@ class CommandLineFlag { ...@@ -108,6 +108,10 @@ class CommandLineFlag {
U u; U u;
Read(&u.value); Read(&u.value);
// allow retired flags to be "read", so we can report invalid access.
if (IsRetired()) {
return absl::nullopt;
}
return std::move(u.value); return std::move(u.value);
} }
......
//
// Copyright 2020 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
//
// https://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/flags/internal/commandlineflag.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace flags_internal {
FlagStateInterface::~FlagStateInterface() {}
} // namespace flags_internal
ABSL_NAMESPACE_END
} // namespace absl
...@@ -482,7 +482,8 @@ class FlagImpl final : public CommandLineFlag { ...@@ -482,7 +482,8 @@ class FlagImpl final : public CommandLineFlag {
friend class FlagState; friend class FlagState;
// Ensures that `data_guard_` is initialized and returns it. // Ensures that `data_guard_` is initialized and returns it.
absl::Mutex* DataGuard() const ABSL_LOCK_RETURNED((absl::Mutex*)&data_guard_); absl::Mutex* DataGuard() const
ABSL_LOCK_RETURNED(reinterpret_cast<absl::Mutex*>(data_guard_));
// Returns heap allocated value of type T initialized with default value. // Returns heap allocated value of type T initialized with default value.
std::unique_ptr<void, DynValueDeleter> MakeInitValue() const std::unique_ptr<void, DynValueDeleter> MakeInitValue() const
ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard()); ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard());
......
...@@ -250,14 +250,14 @@ void FlagsHelpImpl(std::ostream& out, flags_internal::FlagKindFilter filter_cb, ...@@ -250,14 +250,14 @@ void FlagsHelpImpl(std::ostream& out, flags_internal::FlagKindFilter filter_cb,
matching_flags; matching_flags;
flags_internal::ForEachFlag([&](absl::CommandLineFlag& flag) { flags_internal::ForEachFlag([&](absl::CommandLineFlag& flag) {
std::string flag_filename = flag.Filename();
// Ignore retired flags. // Ignore retired flags.
if (flag.IsRetired()) return; if (flag.IsRetired()) return;
// If the flag has been stripped, pretend that it doesn't exist. // If the flag has been stripped, pretend that it doesn't exist.
if (flag.Help() == flags_internal::kStrippedFlagHelp) return; if (flag.Help() == flags_internal::kStrippedFlagHelp) return;
std::string flag_filename = flag.Filename();
// Make sure flag satisfies the filter // Make sure flag satisfies the filter
if (!filter_cb || !filter_cb(flag_filename)) return; if (!filter_cb || !filter_cb(flag_filename)) return;
......
...@@ -729,12 +729,13 @@ std::vector<char*> ParseCommandLineImpl(int argc, char* argv[], ...@@ -729,12 +729,13 @@ std::vector<char*> ParseCommandLineImpl(int argc, char* argv[],
} }
// 100. Set the located flag to a new new value, unless it is retired. // 100. Set the located flag to a new new value, unless it is retired.
// Setting retired flag fails, but we ignoring it here. // Setting retired flag fails, but we ignoring it here while also reporting
if (flag->IsRetired()) continue; // access to retired flag.
std::string error; std::string error;
if (!flags_internal::PrivateHandleAccessor::ParseFrom( if (!flags_internal::PrivateHandleAccessor::ParseFrom(
*flag, value, SET_FLAGS_VALUE, kCommandLine, error)) { *flag, value, SET_FLAGS_VALUE, kCommandLine, error)) {
if (flag->IsRetired()) continue;
flags_internal::ReportUsageError(error, true); flags_internal::ReportUsageError(error, true);
success = false; success = false;
} else { } else {
......
...@@ -88,12 +88,6 @@ CommandLineFlag* FlagRegistry::FindFlagLocked(absl::string_view name) { ...@@ -88,12 +88,6 @@ CommandLineFlag* FlagRegistry::FindFlagLocked(absl::string_view name) {
if (i == flags_.end()) { if (i == flags_.end()) {
return nullptr; return nullptr;
} }
if (i->second->IsRetired()) {
flags_internal::ReportUsageError(
absl::StrCat("Accessing retired flag '", name, "'"), false);
}
return i->second; return i->second;
} }
...@@ -155,7 +149,7 @@ void FlagRegistry::RegisterFlag(CommandLineFlag& flag) { ...@@ -155,7 +149,7 @@ void FlagRegistry::RegisterFlag(CommandLineFlag& flag) {
} else { } else {
flags_internal::ReportUsageError( flags_internal::ReportUsageError(
absl::StrCat( absl::StrCat(
"Something wrong with flag '", flag.Name(), "' in file '", "Something is wrong with flag '", flag.Name(), "' in file '",
flag.Filename(), "'. One possibility: file '", flag.Filename(), flag.Filename(), "'. One possibility: file '", flag.Filename(),
"' is being linked both statically and dynamically into this " "' is being linked both statically and dynamically into this "
"executable. e.g. some files listed as srcs to a test and also " "executable. e.g. some files listed as srcs to a test and also "
...@@ -206,16 +200,34 @@ class RetiredFlagObj final : public CommandLineFlag { ...@@ -206,16 +200,34 @@ class RetiredFlagObj final : public CommandLineFlag {
private: private:
absl::string_view Name() const override { return name_; } absl::string_view Name() const override { return name_; }
std::string Filename() const override { return "RETIRED"; } std::string Filename() const override {
OnAccess();
return "RETIRED";
}
FlagFastTypeId TypeId() const override { return type_id_; } FlagFastTypeId TypeId() const override { return type_id_; }
std::string Help() const override { return ""; } std::string Help() const override {
OnAccess();
return "";
}
bool IsRetired() const override { return true; } bool IsRetired() const override { return true; }
bool IsSpecifiedOnCommandLine() const override { return false; } bool IsSpecifiedOnCommandLine() const override {
std::string DefaultValue() const override { return ""; } OnAccess();
std::string CurrentValue() const override { return ""; } return false;
}
std::string DefaultValue() const override {
OnAccess();
return "";
}
std::string CurrentValue() const override {
OnAccess();
return "";
}
// Any input is valid // Any input is valid
bool ValidateInputValue(absl::string_view) const override { return true; } bool ValidateInputValue(absl::string_view) const override {
OnAccess();
return true;
}
std::unique_ptr<flags_internal::FlagStateInterface> SaveState() override { std::unique_ptr<flags_internal::FlagStateInterface> SaveState() override {
return nullptr; return nullptr;
...@@ -223,12 +235,18 @@ class RetiredFlagObj final : public CommandLineFlag { ...@@ -223,12 +235,18 @@ class RetiredFlagObj final : public CommandLineFlag {
bool ParseFrom(absl::string_view, flags_internal::FlagSettingMode, bool ParseFrom(absl::string_view, flags_internal::FlagSettingMode,
flags_internal::ValueSource, std::string&) override { flags_internal::ValueSource, std::string&) override {
OnAccess();
return false; return false;
} }
void CheckDefaultValueParsingRoundtrip() const override {} void CheckDefaultValueParsingRoundtrip() const override { OnAccess(); }
void Read(void*) const override {} void Read(void*) const override { OnAccess(); }
void OnAccess() const {
flags_internal::ReportUsageError(
absl::StrCat("Accessing retired flag '", name_, "'"), false);
}
// Data members // Data members
const char* const name_; const char* const name_;
......
...@@ -199,6 +199,7 @@ cc_test( ...@@ -199,6 +199,7 @@ cc_test(
cc_test( cc_test(
name = "distributions_test", name = "distributions_test",
size = "small", size = "small",
timeout = "moderate",
srcs = [ srcs = [
"distributions_test.cc", "distributions_test.cc",
], ],
......
...@@ -720,6 +720,7 @@ cc_test( ...@@ -720,6 +720,7 @@ cc_test(
visibility = ["//visibility:private"], visibility = ["//visibility:private"],
deps = [ deps = [
":str_format_internal", ":str_format_internal",
":strings",
"//absl/base:raw_logging_internal", "//absl/base:raw_logging_internal",
"//absl/types:optional", "//absl/types:optional",
"@com_google_googletest//:gtest_main", "@com_google_googletest//:gtest_main",
......
...@@ -475,6 +475,7 @@ absl_cc_test( ...@@ -475,6 +475,7 @@ absl_cc_test(
COPTS COPTS
${ABSL_TEST_COPTS} ${ABSL_TEST_COPTS}
DEPS DEPS
absl::strings
absl::str_format_internal absl::str_format_internal
absl::raw_logging_internal absl::raw_logging_internal
absl::int128 absl::int128
......
...@@ -495,7 +495,7 @@ static CordRep* NewSubstring(CordRep* child, size_t offset, size_t length) { ...@@ -495,7 +495,7 @@ static CordRep* NewSubstring(CordRep* child, size_t offset, size_t length) {
// This will trigger LNK2005 in MSVC. // This will trigger LNK2005 in MSVC.
#ifndef COMPILER_MSVC #ifndef COMPILER_MSVC
const unsigned char Cord::InlineRep::kMaxInline; constexpr unsigned char Cord::InlineRep::kMaxInline;
#endif // COMPILER_MSVC #endif // COMPILER_MSVC
inline void Cord::InlineRep::set_data(const char* data, size_t n, inline void Cord::InlineRep::set_data(const char* data, size_t n,
......
...@@ -141,12 +141,12 @@ namespace strings_internal { ...@@ -141,12 +141,12 @@ namespace strings_internal {
std::string CatPieces(std::initializer_list<absl::string_view> pieces) { std::string CatPieces(std::initializer_list<absl::string_view> pieces) {
std::string result; std::string result;
size_t total_size = 0; size_t total_size = 0;
for (const absl::string_view piece : pieces) total_size += piece.size(); for (const absl::string_view& piece : pieces) total_size += piece.size();
strings_internal::STLStringResizeUninitialized(&result, total_size); strings_internal::STLStringResizeUninitialized(&result, total_size);
char* const begin = &result[0]; char* const begin = &result[0];
char* out = begin; char* out = begin;
for (const absl::string_view piece : pieces) { for (const absl::string_view& piece : pieces) {
const size_t this_size = piece.size(); const size_t this_size = piece.size();
if (this_size != 0) { if (this_size != 0) {
memcpy(out, piece.data(), this_size); memcpy(out, piece.data(), this_size);
...@@ -170,7 +170,7 @@ void AppendPieces(std::string* dest, ...@@ -170,7 +170,7 @@ void AppendPieces(std::string* dest,
std::initializer_list<absl::string_view> pieces) { std::initializer_list<absl::string_view> pieces) {
size_t old_size = dest->size(); size_t old_size = dest->size();
size_t total_size = old_size; size_t total_size = old_size;
for (const absl::string_view piece : pieces) { for (const absl::string_view& piece : pieces) {
ASSERT_NO_OVERLAP(*dest, piece); ASSERT_NO_OVERLAP(*dest, piece);
total_size += piece.size(); total_size += piece.size();
} }
...@@ -178,7 +178,7 @@ void AppendPieces(std::string* dest, ...@@ -178,7 +178,7 @@ void AppendPieces(std::string* dest,
char* const begin = &(*dest)[0]; char* const begin = &(*dest)[0];
char* out = begin + old_size; char* out = begin + old_size;
for (const absl::string_view piece : pieces) { for (const absl::string_view& piece : pieces) {
const size_t this_size = piece.size(); const size_t this_size = piece.size();
if (this_size != 0) { if (this_size != 0) {
memcpy(out, piece.data(), this_size); memcpy(out, piece.data(), this_size);
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include <thread> // NOLINT(build/c++11) #include <thread> // NOLINT(build/c++11)
#include "absl/base/attributes.h" #include "absl/base/attributes.h"
#include "absl/base/call_once.h"
#include "absl/base/config.h" #include "absl/base/config.h"
#include "absl/base/dynamic_annotations.h" #include "absl/base/dynamic_annotations.h"
#include "absl/base/internal/atomic_hook.h" #include "absl/base/internal/atomic_hook.h"
...@@ -58,7 +59,6 @@ ...@@ -58,7 +59,6 @@
using absl::base_internal::CurrentThreadIdentityIfPresent; using absl::base_internal::CurrentThreadIdentityIfPresent;
using absl::base_internal::PerThreadSynch; using absl::base_internal::PerThreadSynch;
using absl::base_internal::SchedulingGuard;
using absl::base_internal::ThreadIdentity; using absl::base_internal::ThreadIdentity;
using absl::synchronization_internal::GetOrCreateCurrentThreadIdentity; using absl::synchronization_internal::GetOrCreateCurrentThreadIdentity;
using absl::synchronization_internal::GraphCycles; using absl::synchronization_internal::GraphCycles;
...@@ -86,28 +86,6 @@ ABSL_CONST_INIT std::atomic<OnDeadlockCycle> synch_deadlock_detection( ...@@ -86,28 +86,6 @@ ABSL_CONST_INIT std::atomic<OnDeadlockCycle> synch_deadlock_detection(
kDeadlockDetectionDefault); kDeadlockDetectionDefault);
ABSL_CONST_INIT std::atomic<bool> synch_check_invariants(false); ABSL_CONST_INIT std::atomic<bool> synch_check_invariants(false);
// ------------------------------------------ spinlock support
// Make sure read-only globals used in the Mutex code are contained on the
// same cacheline and cacheline aligned to eliminate any false sharing with
// other globals from this and other modules.
static struct MutexGlobals {
MutexGlobals() {
// Find machine-specific data needed for Delay() and
// TryAcquireWithSpinning(). This runs in the global constructor
// sequence, and before that zeros are safe values.
num_cpus = absl::base_internal::NumCPUs();
spinloop_iterations = num_cpus > 1 ? 1500 : 0;
}
int num_cpus;
int spinloop_iterations;
// Pad this struct to a full cacheline to prevent false sharing.
char padding[ABSL_CACHELINE_SIZE - 2 * sizeof(int)];
} ABSL_CACHELINE_ALIGNED mutex_globals;
static_assert(
sizeof(MutexGlobals) == ABSL_CACHELINE_SIZE,
"MutexGlobals must occupy an entire cacheline to prevent false sharing");
ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES
absl::base_internal::AtomicHook<void (*)(int64_t wait_cycles)> absl::base_internal::AtomicHook<void (*)(int64_t wait_cycles)>
submit_profile_data; submit_profile_data;
...@@ -144,7 +122,22 @@ void RegisterSymbolizer(bool (*fn)(const void *pc, char *out, int out_size)) { ...@@ -144,7 +122,22 @@ void RegisterSymbolizer(bool (*fn)(const void *pc, char *out, int out_size)) {
symbolizer.Store(fn); symbolizer.Store(fn);
} }
// spinlock delay on iteration c. Returns new c. struct ABSL_CACHELINE_ALIGNED MutexGlobals {
absl::once_flag once;
int num_cpus = 0;
int spinloop_iterations = 0;
};
static const MutexGlobals& GetMutexGlobals() {
ABSL_CONST_INIT static MutexGlobals data;
absl::base_internal::LowLevelCallOnce(&data.once, [&]() {
data.num_cpus = absl::base_internal::NumCPUs();
data.spinloop_iterations = data.num_cpus > 1 ? 1500 : 0;
});
return data;
}
// Spinlock delay on iteration c. Returns new c.
namespace { namespace {
enum DelayMode { AGGRESSIVE, GENTLE }; enum DelayMode { AGGRESSIVE, GENTLE };
}; };
...@@ -154,22 +147,25 @@ static int Delay(int32_t c, DelayMode mode) { ...@@ -154,22 +147,25 @@ static int Delay(int32_t c, DelayMode mode) {
// gentle then spin only a few times before yielding. Aggressive spinning is // gentle then spin only a few times before yielding. Aggressive spinning is
// used to ensure that an Unlock() call, which must get the spin lock for // used to ensure that an Unlock() call, which must get the spin lock for
// any thread to make progress gets it without undue delay. // any thread to make progress gets it without undue delay.
int32_t limit = (mutex_globals.num_cpus > 1) ? const int32_t limit =
((mode == AGGRESSIVE) ? 5000 : 250) : 0; GetMutexGlobals().num_cpus > 1 ? (mode == AGGRESSIVE ? 5000 : 250) : 0;
if (c < limit) { if (c < limit) {
c++; // spin // Spin.
c++;
} else { } else {
ABSL_TSAN_MUTEX_PRE_DIVERT(nullptr, 0); ABSL_TSAN_MUTEX_PRE_DIVERT(nullptr, 0);
if (c == limit) { // yield once if (c == limit) {
// Yield once.
AbslInternalMutexYield(); AbslInternalMutexYield();
c++; c++;
} else { // then wait } else {
// Then wait.
absl::SleepFor(absl::Microseconds(10)); absl::SleepFor(absl::Microseconds(10));
c = 0; c = 0;
} }
ABSL_TSAN_MUTEX_POST_DIVERT(nullptr, 0); ABSL_TSAN_MUTEX_POST_DIVERT(nullptr, 0);
} }
return (c); return c;
} }
// --------------------------Generic atomic ops // --------------------------Generic atomic ops
...@@ -1055,7 +1051,6 @@ static PerThreadSynch *DequeueAllWakeable(PerThreadSynch *head, ...@@ -1055,7 +1051,6 @@ static PerThreadSynch *DequeueAllWakeable(PerThreadSynch *head,
// Try to remove thread s from the list of waiters on this mutex. // Try to remove thread s from the list of waiters on this mutex.
// Does nothing if s is not on the waiter list. // Does nothing if s is not on the waiter list.
void Mutex::TryRemove(PerThreadSynch *s) { void Mutex::TryRemove(PerThreadSynch *s) {
SchedulingGuard::ScopedDisable disable_rescheduling;
intptr_t v = mu_.load(std::memory_order_relaxed); intptr_t v = mu_.load(std::memory_order_relaxed);
// acquire spinlock & lock // acquire spinlock & lock
if ((v & (kMuWait | kMuSpin | kMuWriter | kMuReader)) == kMuWait && if ((v & (kMuWait | kMuSpin | kMuWriter | kMuReader)) == kMuWait &&
...@@ -1439,7 +1434,7 @@ void Mutex::AssertNotHeld() const { ...@@ -1439,7 +1434,7 @@ void Mutex::AssertNotHeld() const {
// Attempt to acquire *mu, and return whether successful. The implementation // Attempt to acquire *mu, and return whether successful. The implementation
// may spin for a short while if the lock cannot be acquired immediately. // may spin for a short while if the lock cannot be acquired immediately.
static bool TryAcquireWithSpinning(std::atomic<intptr_t>* mu) { static bool TryAcquireWithSpinning(std::atomic<intptr_t>* mu) {
int c = mutex_globals.spinloop_iterations; int c = GetMutexGlobals().spinloop_iterations;
do { // do/while somewhat faster on AMD do { // do/while somewhat faster on AMD
intptr_t v = mu->load(std::memory_order_relaxed); intptr_t v = mu->load(std::memory_order_relaxed);
if ((v & (kMuReader|kMuEvent)) != 0) { if ((v & (kMuReader|kMuEvent)) != 0) {
...@@ -1899,7 +1894,6 @@ static void CheckForMutexCorruption(intptr_t v, const char* label) { ...@@ -1899,7 +1894,6 @@ static void CheckForMutexCorruption(intptr_t v, const char* label) {
} }
void Mutex::LockSlowLoop(SynchWaitParams *waitp, int flags) { void Mutex::LockSlowLoop(SynchWaitParams *waitp, int flags) {
SchedulingGuard::ScopedDisable disable_rescheduling;
int c = 0; int c = 0;
intptr_t v = mu_.load(std::memory_order_relaxed); intptr_t v = mu_.load(std::memory_order_relaxed);
if ((v & kMuEvent) != 0) { if ((v & kMuEvent) != 0) {
...@@ -2019,7 +2013,6 @@ void Mutex::LockSlowLoop(SynchWaitParams *waitp, int flags) { ...@@ -2019,7 +2013,6 @@ void Mutex::LockSlowLoop(SynchWaitParams *waitp, int flags) {
// or it is in the process of blocking on a condition variable; it must requeue // or it is in the process of blocking on a condition variable; it must requeue
// itself on the mutex/condvar to wait for its condition to become true. // itself on the mutex/condvar to wait for its condition to become true.
ABSL_ATTRIBUTE_NOINLINE void Mutex::UnlockSlow(SynchWaitParams *waitp) { ABSL_ATTRIBUTE_NOINLINE void Mutex::UnlockSlow(SynchWaitParams *waitp) {
SchedulingGuard::ScopedDisable disable_rescheduling;
intptr_t v = mu_.load(std::memory_order_relaxed); intptr_t v = mu_.load(std::memory_order_relaxed);
this->AssertReaderHeld(); this->AssertReaderHeld();
CheckForMutexCorruption(v, "Unlock"); CheckForMutexCorruption(v, "Unlock");
...@@ -2335,7 +2328,6 @@ void Mutex::Trans(MuHow how) { ...@@ -2335,7 +2328,6 @@ void Mutex::Trans(MuHow how) {
// It will later acquire the mutex with high probability. Otherwise, we // It will later acquire the mutex with high probability. Otherwise, we
// enqueue thread w on this mutex. // enqueue thread w on this mutex.
void Mutex::Fer(PerThreadSynch *w) { void Mutex::Fer(PerThreadSynch *w) {
SchedulingGuard::ScopedDisable disable_rescheduling;
int c = 0; int c = 0;
ABSL_RAW_CHECK(w->waitp->cond == nullptr, ABSL_RAW_CHECK(w->waitp->cond == nullptr,
"Mutex::Fer while waiting on Condition"); "Mutex::Fer while waiting on Condition");
...@@ -2434,7 +2426,6 @@ CondVar::~CondVar() { ...@@ -2434,7 +2426,6 @@ CondVar::~CondVar() {
// Remove thread s from the list of waiters on this condition variable. // Remove thread s from the list of waiters on this condition variable.
void CondVar::Remove(PerThreadSynch *s) { void CondVar::Remove(PerThreadSynch *s) {
SchedulingGuard::ScopedDisable disable_rescheduling;
intptr_t v; intptr_t v;
int c = 0; int c = 0;
for (v = cv_.load(std::memory_order_relaxed);; for (v = cv_.load(std::memory_order_relaxed);;
...@@ -2595,7 +2586,6 @@ void CondVar::Wakeup(PerThreadSynch *w) { ...@@ -2595,7 +2586,6 @@ void CondVar::Wakeup(PerThreadSynch *w) {
} }
void CondVar::Signal() { void CondVar::Signal() {
SchedulingGuard::ScopedDisable disable_rescheduling;
ABSL_TSAN_MUTEX_PRE_SIGNAL(nullptr, 0); ABSL_TSAN_MUTEX_PRE_SIGNAL(nullptr, 0);
intptr_t v; intptr_t v;
int c = 0; int c = 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment