Commit 4b2fbb4a by Abseil Team Committed by Derek Mauro

Export of internal Abseil changes

--
a5af5874c1c5cc02bd2a748d455321f82b6f2a93 by Andy Getzendanner <durandal@google.com>:

fix compile fails with asan and -Wredundant-decls

Import of https://github.com/abseil/abseil-cpp/pull/801

PiperOrigin-RevId: 336693223

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

Fix integer conversion warning

Fixes #814

PiperOrigin-RevId: 336651814

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

Internal change

PiperOrigin-RevId: 336585378

--
eba0e3dccd52a6e91bcff84075bef0affc650b74 by Matt Kulukundis <kfm@google.com>:

Add bitset operations to Futex helper.

PiperOrigin-RevId: 336409368

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

Fix code indentation in a comment.

PiperOrigin-RevId: 336368167

--
bc3961c87a7e7760c10319a5b0349c279f7ae3ad by Samuel Benzaquen <sbenza@google.com>:

Improve performance of the registry:
 - Reduce contention
 - Reduce memory usage for each flag by `6*sizeof(void*)`.
 - Replace one immortal allocation per-flag with a single one for all the flags
 - Slightly improve single-threaded performance by avoiding the std::map indirections.

PiperOrigin-RevId: 336365904

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

Fix typo in comment on absl::Condition.

PiperOrigin-RevId: 336311680

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

Add missing Apache license headers

PiperOrigin-RevId: 336294980

--
89446c3a4793df8b95060385cf3e219357c3db1d by Andy Soffer <asoffer@google.com>:

Internal changes

PiperOrigin-RevId: 336287465

--
57c8be4e294881bc79a6a44b8e4bf7ecbb19b9b9 by Matt Kulukundis <kfm@google.com>:

Extract Futex from an implementation detail of Wait to a private interface.

PiperOrigin-RevId: 336123209
GitOrigin-RevId: a5af5874c1c5cc02bd2a748d455321f82b6f2a93
Change-Id: Ie5a0ebe28e571814e3e11d4c05ca308523ccf311
parent e493d6ac
...@@ -250,6 +250,7 @@ set(ABSL_INTERNAL_DLL_FILES ...@@ -250,6 +250,7 @@ set(ABSL_INTERNAL_DLL_FILES
"synchronization/notification.h" "synchronization/notification.h"
"synchronization/internal/create_thread_identity.cc" "synchronization/internal/create_thread_identity.cc"
"synchronization/internal/create_thread_identity.h" "synchronization/internal/create_thread_identity.h"
"synchronization/internal/futex.h"
"synchronization/internal/graphcycles.cc" "synchronization/internal/graphcycles.cc"
"synchronization/internal/graphcycles.h" "synchronization/internal/graphcycles.h"
"synchronization/internal/kernel_timeout.h" "synchronization/internal/kernel_timeout.h"
......
...@@ -123,9 +123,7 @@ double UnscaledCycleClock::Frequency() { ...@@ -123,9 +123,7 @@ double UnscaledCycleClock::Frequency() {
#pragma intrinsic(__rdtsc) #pragma intrinsic(__rdtsc)
int64_t UnscaledCycleClock::Now() { int64_t UnscaledCycleClock::Now() { return __rdtsc(); }
return __rdtsc();
}
double UnscaledCycleClock::Frequency() { double UnscaledCycleClock::Frequency() {
return base_internal::NominalCPUFrequency(); return base_internal::NominalCPUFrequency();
......
...@@ -847,7 +847,8 @@ TEST(Table, EraseMaintainsValidIterator) { ...@@ -847,7 +847,8 @@ TEST(Table, EraseMaintainsValidIterator) {
std::vector<int64_t> CollectBadMergeKeys(size_t N) { std::vector<int64_t> CollectBadMergeKeys(size_t N) {
static constexpr int kGroupSize = Group::kWidth - 1; static constexpr int kGroupSize = Group::kWidth - 1;
auto topk_range = [](size_t b, size_t e, IntTable* t) -> std::vector<int64_t> { auto topk_range = [](size_t b, size_t e,
IntTable* t) -> std::vector<int64_t> {
for (size_t i = b; i != e; ++i) { for (size_t i = b; i != e; ++i) {
t->emplace(i); t->emplace(i);
} }
...@@ -1001,8 +1002,8 @@ using ProbeStatsPerSize = std::map<size_t, ProbeStats>; ...@@ -1001,8 +1002,8 @@ using ProbeStatsPerSize = std::map<size_t, ProbeStats>;
// 1. Create new table and reserve it to keys.size() * 2 // 1. Create new table and reserve it to keys.size() * 2
// 2. Insert all keys xored with seed // 2. Insert all keys xored with seed
// 3. Collect ProbeStats from final table. // 3. Collect ProbeStats from final table.
ProbeStats CollectProbeStatsOnKeysXoredWithSeed(const std::vector<int64_t>& keys, ProbeStats CollectProbeStatsOnKeysXoredWithSeed(
size_t num_iters) { const std::vector<int64_t>& keys, size_t num_iters) {
const size_t reserve_size = keys.size() * 2; const size_t reserve_size = keys.size() * 2;
ProbeStats stats; ProbeStats stats;
......
...@@ -118,16 +118,14 @@ bool RemoveAllSymbolDecorators(void); ...@@ -118,16 +118,14 @@ bool RemoveAllSymbolDecorators(void);
// filename != nullptr // filename != nullptr
// //
// Returns true if the file was successfully registered. // Returns true if the file was successfully registered.
bool RegisterFileMappingHint( bool RegisterFileMappingHint(const void* start, const void* end,
const void* start, const void* end, uint64_t offset, const char* filename); uint64_t offset, const char* filename);
// Looks up the file mapping registered by RegisterFileMappingHint for an // Looks up the file mapping registered by RegisterFileMappingHint for an
// address range. If there is one, the file name is stored in *filename and // address range. If there is one, the file name is stored in *filename and
// *start and *end are modified to reflect the registered mapping. Returns // *start and *end are modified to reflect the registered mapping. Returns
// whether any hint was found. // whether any hint was found.
bool GetFileMappingHint(const void** start, bool GetFileMappingHint(const void** start, const void** end, uint64_t* offset,
const void** end,
uint64_t * offset,
const char** filename); const char** filename);
} // namespace debugging_internal } // namespace debugging_internal
......
...@@ -381,6 +381,8 @@ cc_binary( ...@@ -381,6 +381,8 @@ cc_binary(
deps = [ deps = [
":flag", ":flag",
":marshalling", ":marshalling",
":parse",
":reflection",
"//absl/strings", "//absl/strings",
"//absl/time", "//absl/time",
"//absl/types:optional", "//absl/types:optional",
......
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
#include "absl/flags/flag.h" #include "absl/flags/flag.h"
#include "absl/flags/marshalling.h" #include "absl/flags/marshalling.h"
#include "absl/flags/parse.h"
#include "absl/flags/reflection.h"
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
#include "absl/time/time.h" #include "absl/time/time.h"
#include "absl/types/optional.h" #include "absl/types/optional.h"
...@@ -103,6 +105,23 @@ std::string AbslUnparseFlag(const UDT&) { return ""; } ...@@ -103,6 +105,23 @@ std::string AbslUnparseFlag(const UDT&) { return ""; }
BENCHMARKED_TYPES(FLAG_DEF) BENCHMARKED_TYPES(FLAG_DEF)
// Register thousands of flags to bloat up the size of the registry.
// This mimics real life production binaries.
#define DEFINE_FLAG_0(name) ABSL_FLAG(int, name, 0, "");
#define DEFINE_FLAG_1(name) DEFINE_FLAG_0(name##0) DEFINE_FLAG_0(name##1)
#define DEFINE_FLAG_2(name) DEFINE_FLAG_1(name##0) DEFINE_FLAG_1(name##1)
#define DEFINE_FLAG_3(name) DEFINE_FLAG_2(name##0) DEFINE_FLAG_2(name##1)
#define DEFINE_FLAG_4(name) DEFINE_FLAG_3(name##0) DEFINE_FLAG_3(name##1)
#define DEFINE_FLAG_5(name) DEFINE_FLAG_4(name##0) DEFINE_FLAG_4(name##1)
#define DEFINE_FLAG_6(name) DEFINE_FLAG_5(name##0) DEFINE_FLAG_5(name##1)
#define DEFINE_FLAG_7(name) DEFINE_FLAG_6(name##0) DEFINE_FLAG_6(name##1)
#define DEFINE_FLAG_8(name) DEFINE_FLAG_7(name##0) DEFINE_FLAG_7(name##1)
#define DEFINE_FLAG_9(name) DEFINE_FLAG_8(name##0) DEFINE_FLAG_8(name##1)
#define DEFINE_FLAG_10(name) DEFINE_FLAG_9(name##0) DEFINE_FLAG_9(name##1)
#define DEFINE_FLAG_11(name) DEFINE_FLAG_10(name##0) DEFINE_FLAG_10(name##1)
#define DEFINE_FLAG_12(name) DEFINE_FLAG_11(name##0) DEFINE_FLAG_11(name##1)
DEFINE_FLAG_12(bloat_flag_);
namespace { namespace {
#define BM_GetFlag(T) \ #define BM_GetFlag(T) \
...@@ -115,6 +134,20 @@ namespace { ...@@ -115,6 +134,20 @@ namespace {
BENCHMARKED_TYPES(BM_GetFlag) BENCHMARKED_TYPES(BM_GetFlag)
void BM_ThreadedFindCommandLineFlag(benchmark::State& state) {
char dummy[] = "dummy";
char* argv[] = {dummy};
// We need to ensure that flags have been parsed. That is where the registry
// is finalized.
absl::ParseCommandLine(1, argv);
for (auto s : state) {
benchmark::DoNotOptimize(
absl::FindCommandLineFlag("bloat_flag_010101010101"));
}
}
BENCHMARK(BM_ThreadedFindCommandLineFlag)->ThreadRange(1, 16);
} // namespace } // namespace
#define InvokeGetFlag(T) \ #define InvokeGetFlag(T) \
......
...@@ -30,9 +30,6 @@ namespace absl { ...@@ -30,9 +30,6 @@ namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
namespace flags_internal { namespace flags_internal {
// Executes specified visitor for each non-retired flag in the registry.
// Requires the caller hold the registry lock.
void ForEachFlagUnlocked(std::function<void(CommandLineFlag&)> visitor);
// Executes specified visitor for each non-retired flag in the registry. While // Executes specified visitor for each non-retired flag in the registry. While
// callback are executed, the registry is locked and can't be changed. // callback are executed, the registry is locked and can't be changed.
void ForEachFlag(std::function<void(CommandLineFlag&)> visitor); void ForEachFlag(std::function<void(CommandLineFlag&)> visitor);
...@@ -41,6 +38,8 @@ void ForEachFlag(std::function<void(CommandLineFlag&)> visitor); ...@@ -41,6 +38,8 @@ void ForEachFlag(std::function<void(CommandLineFlag&)> visitor);
bool RegisterCommandLineFlag(CommandLineFlag&); bool RegisterCommandLineFlag(CommandLineFlag&);
void FinalizeRegistry();
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Retired registrations: // Retired registrations:
// //
......
...@@ -611,6 +611,11 @@ std::vector<char*> ParseCommandLineImpl(int argc, char* argv[], ...@@ -611,6 +611,11 @@ std::vector<char*> ParseCommandLineImpl(int argc, char* argv[],
OnUndefinedFlag on_undef_flag) { OnUndefinedFlag on_undef_flag) {
ABSL_INTERNAL_CHECK(argc > 0, "Missing argv[0]"); ABSL_INTERNAL_CHECK(argc > 0, "Missing argv[0]");
// Once parsing has started we will not have more flag registrations.
// If we did, they would be missing during parsing, which is a problem on
// itself.
flags_internal::FinalizeRegistry();
// This routine does not return anything since we abort on failure. // This routine does not return anything since we abort on failure.
CheckDefaultValuesParsingRoundtrip(); CheckDefaultValuesParsingRoundtrip();
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <assert.h> #include <assert.h>
#include <atomic>
#include <map> #include <map>
#include <string> #include <string>
...@@ -56,21 +57,23 @@ class FlagRegistry { ...@@ -56,21 +57,23 @@ class FlagRegistry {
// Returns the flag object for the specified name, or nullptr if not found. // Returns the flag object for the specified name, or nullptr if not found.
// Will emit a warning if a 'retired' flag is specified. // Will emit a warning if a 'retired' flag is specified.
CommandLineFlag* FindFlagLocked(absl::string_view name); CommandLineFlag* FindFlag(absl::string_view name);
static FlagRegistry& GlobalRegistry(); // returns a singleton registry static FlagRegistry& GlobalRegistry(); // returns a singleton registry
private: private:
friend class flags_internal::FlagSaverImpl; // reads all the flags in order friend class flags_internal::FlagSaverImpl; // reads all the flags in order
// to copy them // to copy them
friend void ForEachFlagUnlocked( friend void ForEachFlag(std::function<void(CommandLineFlag&)> visitor);
std::function<void(CommandLineFlag&)> visitor); friend void FinalizeRegistry();
// The map from name to flag, for FindFlagLocked(). // The map from name to flag, for FindFlag().
using FlagMap = std::map<absl::string_view, CommandLineFlag*>; using FlagMap = std::map<absl::string_view, CommandLineFlag*>;
using FlagIterator = FlagMap::iterator; using FlagIterator = FlagMap::iterator;
using FlagConstIterator = FlagMap::const_iterator; using FlagConstIterator = FlagMap::const_iterator;
FlagMap flags_; FlagMap flags_;
std::vector<CommandLineFlag*> flat_flags_;
std::atomic<bool> finalized_flags_{false};
absl::Mutex lock_; absl::Mutex lock_;
...@@ -79,15 +82,6 @@ class FlagRegistry { ...@@ -79,15 +82,6 @@ class FlagRegistry {
FlagRegistry& operator=(const FlagRegistry&); FlagRegistry& operator=(const FlagRegistry&);
}; };
CommandLineFlag* FlagRegistry::FindFlagLocked(absl::string_view name) {
FlagConstIterator i = flags_.find(name);
if (i == flags_.end()) {
return nullptr;
}
return i->second;
}
namespace { namespace {
class FlagRegistryLock { class FlagRegistryLock {
...@@ -101,8 +95,24 @@ class FlagRegistryLock { ...@@ -101,8 +95,24 @@ class FlagRegistryLock {
} // namespace } // namespace
CommandLineFlag* FlagRegistry::FindFlag(absl::string_view name) {
if (finalized_flags_.load(std::memory_order_acquire)) {
// We could save some gcus here if we make `Name()` be non-virtual.
// We could move the `const char*` name to the base class.
auto it = std::partition_point(
flat_flags_.begin(), flat_flags_.end(),
[=](CommandLineFlag* f) { return f->Name() < name; });
if (it != flat_flags_.end() && (*it)->Name() == name) return *it;
}
FlagRegistryLock frl(*this);
auto it = flags_.find(name);
return it != flags_.end() ? it->second : nullptr;
}
void FlagRegistry::RegisterFlag(CommandLineFlag& flag) { void FlagRegistry::RegisterFlag(CommandLineFlag& flag) {
FlagRegistryLock registry_lock(*this); FlagRegistryLock registry_lock(*this);
std::pair<FlagIterator, bool> ins = std::pair<FlagIterator, bool> ins =
flags_.insert(FlagMap::value_type(flag.Name(), &flag)); flags_.insert(FlagMap::value_type(flag.Name(), &flag));
if (ins.second == false) { // means the name was already in the map if (ins.second == false) { // means the name was already in the map
...@@ -152,18 +162,15 @@ FlagRegistry& FlagRegistry::GlobalRegistry() { ...@@ -152,18 +162,15 @@ FlagRegistry& FlagRegistry::GlobalRegistry() {
// -------------------------------------------------------------------- // --------------------------------------------------------------------
void ForEachFlagUnlocked(std::function<void(CommandLineFlag&)> visitor) { void ForEachFlag(std::function<void(CommandLineFlag&)> visitor) {
FlagRegistry& registry = FlagRegistry::GlobalRegistry(); FlagRegistry& registry = FlagRegistry::GlobalRegistry();
for (FlagRegistry::FlagConstIterator i = registry.flags_.begin();
i != registry.flags_.end(); ++i) { if (registry.finalized_flags_.load(std::memory_order_acquire)) {
visitor(*i->second); for (const auto& i : registry.flat_flags_) visitor(*i);
} }
}
void ForEachFlag(std::function<void(CommandLineFlag&)> visitor) {
FlagRegistry& registry = FlagRegistry::GlobalRegistry();
FlagRegistryLock frl(registry); FlagRegistryLock frl(registry);
ForEachFlagUnlocked(visitor); for (const auto& i : registry.flags_) visitor(*i.second);
} }
// -------------------------------------------------------------------- // --------------------------------------------------------------------
...@@ -173,6 +180,21 @@ bool RegisterCommandLineFlag(CommandLineFlag& flag) { ...@@ -173,6 +180,21 @@ bool RegisterCommandLineFlag(CommandLineFlag& flag) {
return true; return true;
} }
void FinalizeRegistry() {
auto& registry = FlagRegistry::GlobalRegistry();
FlagRegistryLock frl(registry);
if (registry.finalized_flags_.load(std::memory_order_relaxed)) {
// Was already finalized. Ignore the second time.
return;
}
registry.flat_flags_.reserve(registry.flags_.size());
for (const auto& f : registry.flags_) {
registry.flat_flags_.push_back(f.second);
}
registry.flags_.clear();
registry.finalized_flags_.store(true, std::memory_order_release);
}
// -------------------------------------------------------------------- // --------------------------------------------------------------------
namespace { namespace {
...@@ -298,9 +320,7 @@ CommandLineFlag* FindCommandLineFlag(absl::string_view name) { ...@@ -298,9 +320,7 @@ CommandLineFlag* FindCommandLineFlag(absl::string_view name) {
if (name.empty()) return nullptr; if (name.empty()) return nullptr;
flags_internal::FlagRegistry& registry = flags_internal::FlagRegistry& registry =
flags_internal::FlagRegistry::GlobalRegistry(); flags_internal::FlagRegistry::GlobalRegistry();
flags_internal::FlagRegistryLock frl(registry); return registry.FindFlag(name);
return registry.FindFlagLocked(name);
} }
// -------------------------------------------------------------------- // --------------------------------------------------------------------
......
...@@ -82,8 +82,8 @@ TYPED_TEST_P(HashValueIntTest, FastPath) { ...@@ -82,8 +82,8 @@ TYPED_TEST_P(HashValueIntTest, FastPath) {
} }
REGISTER_TYPED_TEST_CASE_P(HashValueIntTest, BasicUsage, FastPath); REGISTER_TYPED_TEST_CASE_P(HashValueIntTest, BasicUsage, FastPath);
using IntTypes = testing::Types<unsigned char, char, int, int32_t, int64_t, uint32_t, using IntTypes = testing::Types<unsigned char, char, int, int32_t, int64_t,
uint64_t, size_t>; uint32_t, uint64_t, size_t>;
INSTANTIATE_TYPED_TEST_CASE_P(My, HashValueIntTest, IntTypes); INSTANTIATE_TYPED_TEST_CASE_P(My, HashValueIntTest, IntTypes);
enum LegacyEnum { kValue1, kValue2, kValue3 }; enum LegacyEnum { kValue1, kValue2, kValue3 };
...@@ -819,8 +819,8 @@ TYPED_TEST_P(HashIntTest, BasicUsage) { ...@@ -819,8 +819,8 @@ TYPED_TEST_P(HashIntTest, BasicUsage) {
} }
REGISTER_TYPED_TEST_CASE_P(HashIntTest, BasicUsage); REGISTER_TYPED_TEST_CASE_P(HashIntTest, BasicUsage);
using IntTypes = testing::Types<unsigned char, char, int, int32_t, int64_t, uint32_t, using IntTypes = testing::Types<unsigned char, char, int, int32_t, int64_t,
uint64_t, size_t>; uint32_t, uint64_t, size_t>;
INSTANTIATE_TYPED_TEST_CASE_P(My, HashIntTest, IntTypes); INSTANTIATE_TYPED_TEST_CASE_P(My, HashIntTest, IntTypes);
struct StructWithPadding { struct StructWithPadding {
......
...@@ -253,9 +253,8 @@ static uint64_t HashLen17to32(const char *s, size_t len) { ...@@ -253,9 +253,8 @@ static uint64_t HashLen17to32(const char *s, size_t len) {
// Return a 16-byte hash for 48 bytes. Quick and dirty. // Return a 16-byte hash for 48 bytes. Quick and dirty.
// Callers do best to use "random-looking" values for a and b. // Callers do best to use "random-looking" values for a and b.
static std::pair<uint64_t, uint64_t> WeakHashLen32WithSeeds(uint64_t w, uint64_t x, static std::pair<uint64_t, uint64_t> WeakHashLen32WithSeeds(
uint64_t y, uint64_t z, uint64_t w, uint64_t x, uint64_t y, uint64_t z, uint64_t a, uint64_t b) {
uint64_t a, uint64_t b) {
a += w; a += w;
b = Rotate(b + a + z, 21); b = Rotate(b + a + z, 21);
uint64_t c = a; uint64_t c = a;
...@@ -266,7 +265,8 @@ static std::pair<uint64_t, uint64_t> WeakHashLen32WithSeeds(uint64_t w, uint64_t ...@@ -266,7 +265,8 @@ static std::pair<uint64_t, uint64_t> WeakHashLen32WithSeeds(uint64_t w, uint64_t
} }
// Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty. // Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty.
static std::pair<uint64_t, uint64_t> WeakHashLen32WithSeeds(const char *s, uint64_t a, static std::pair<uint64_t, uint64_t> WeakHashLen32WithSeeds(const char *s,
uint64_t a,
uint64_t b) { uint64_t b) {
return WeakHashLen32WithSeeds(Fetch64(s), Fetch64(s + 8), Fetch64(s + 16), return WeakHashLen32WithSeeds(Fetch64(s), Fetch64(s + 8), Fetch64(s + 16),
Fetch64(s + 24), a, b); Fetch64(s + 24), a, b);
...@@ -310,8 +310,10 @@ uint64_t CityHash64(const char *s, size_t len) { ...@@ -310,8 +310,10 @@ uint64_t CityHash64(const char *s, size_t len) {
uint64_t x = Fetch64(s + len - 40); uint64_t x = Fetch64(s + len - 40);
uint64_t y = Fetch64(s + len - 16) + Fetch64(s + len - 56); uint64_t y = Fetch64(s + len - 16) + Fetch64(s + len - 56);
uint64_t z = HashLen16(Fetch64(s + len - 48) + len, Fetch64(s + len - 24)); uint64_t z = HashLen16(Fetch64(s + len - 48) + len, Fetch64(s + len - 24));
std::pair<uint64_t, uint64_t> v = WeakHashLen32WithSeeds(s + len - 64, len, z); std::pair<uint64_t, uint64_t> v =
std::pair<uint64_t, uint64_t> w = WeakHashLen32WithSeeds(s + len - 32, y + k1, x); WeakHashLen32WithSeeds(s + len - 64, len, z);
std::pair<uint64_t, uint64_t> w =
WeakHashLen32WithSeeds(s + len - 32, y + k1, x);
x = x * k1 + Fetch64(s); x = x * k1 + Fetch64(s);
// Decrease len to the nearest multiple of 64, and operate on 64-byte chunks. // Decrease len to the nearest multiple of 64, and operate on 64-byte chunks.
......
...@@ -419,8 +419,8 @@ TEST(GenerateRealTest, ExhaustiveFloat) { ...@@ -419,8 +419,8 @@ TEST(GenerateRealTest, ExhaustiveFloat) {
}; };
// Rely on RandU64ToFloat generating values from greatest to least when // Rely on RandU64ToFloat generating values from greatest to least when
// supplied with uint64_t values from greatest (0xfff...) to least (0x0). Thus, // supplied with uint64_t values from greatest (0xfff...) to least (0x0).
// this algorithm stores the previous value, and if the new value is at // Thus, this algorithm stores the previous value, and if the new value is at
// greater than or equal to the previous value, then there is a collision in // greater than or equal to the previous value, then there is a collision in
// the generation algorithm. // the generation algorithm.
// //
......
// 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/strings/cord.h" #include "absl/strings/cord.h"
#include <algorithm> #include <algorithm>
......
// 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.
// //
// POSIX spec: // POSIX spec:
// http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html // http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html
......
// 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.
#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_ #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_
#define ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_ #define ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_
......
// 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/strings/internal/str_format/bind.h" #include "absl/strings/internal/str_format/bind.h"
#include <cerrno> #include <cerrno>
......
// 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.
#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_ #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_
#define ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_ #define ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_
......
// 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/strings/internal/str_format/bind.h" #include "absl/strings/internal/str_format/bind.h"
#include <string.h> #include <string.h>
......
// 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.
#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_ #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_
#define ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_ #define ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_
......
// 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 <string> #include <string>
#include "gmock/gmock.h" #include "gmock/gmock.h"
......
// 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 <errno.h> #include <errno.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
......
// 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/strings/internal/str_format/float_conversion.h" #include "absl/strings/internal/str_format/float_conversion.h"
#include <string.h> #include <string.h>
......
// 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.
#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_ #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_
#define ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_ #define ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_
......
// 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/strings/internal/str_format/parser.h" #include "absl/strings/internal/str_format/parser.h"
#include <assert.h> #include <assert.h>
......
// 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.
#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_ #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_
#define ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_ #define ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_
......
// 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/strings/internal/str_format/parser.h" #include "absl/strings/internal/str_format/parser.h"
#include <string.h> #include <string.h>
......
// 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/strings/str_format.h" #include "absl/strings/str_format.h"
......
...@@ -80,6 +80,7 @@ cc_library( ...@@ -80,6 +80,7 @@ cc_library(
"barrier.h", "barrier.h",
"blocking_counter.h", "blocking_counter.h",
"internal/create_thread_identity.h", "internal/create_thread_identity.h",
"internal/futex.h",
"internal/per_thread_sem.h", "internal/per_thread_sem.h",
"internal/waiter.h", "internal/waiter.h",
"mutex.h", "mutex.h",
......
...@@ -52,6 +52,7 @@ absl_cc_library( ...@@ -52,6 +52,7 @@ absl_cc_library(
"barrier.h" "barrier.h"
"blocking_counter.h" "blocking_counter.h"
"internal/create_thread_identity.h" "internal/create_thread_identity.h"
"internal/futex.h"
"internal/per_thread_sem.h" "internal/per_thread_sem.h"
"internal/waiter.h" "internal/waiter.h"
"mutex.h" "mutex.h"
......
// 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.
#ifndef ABSL_SYNCHRONIZATION_INTERNAL_FUTEX_H_
#define ABSL_SYNCHRONIZATION_INTERNAL_FUTEX_H_
#include "absl/base/config.h"
#ifdef _WIN32
#include <windows.h>
#else
#include <sys/time.h>
#include <unistd.h>
#endif
#ifdef __linux__
#include <linux/futex.h>
#include <sys/syscall.h>
#endif
#include <errno.h>
#include <stdio.h>
#include <time.h>
#include <atomic>
#include <cstdint>
#include "absl/base/optimization.h"
#include "absl/synchronization/internal/kernel_timeout.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace synchronization_internal {
// 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_WAIT_BITSET
#define FUTEX_WAIT_BITSET 9
#endif
#ifndef FUTEX_PRIVATE_FLAG
#define FUTEX_PRIVATE_FLAG 128
#endif
#ifndef FUTEX_CLOCK_REALTIME
#define FUTEX_CLOCK_REALTIME 256
#endif
#ifndef FUTEX_BITSET_MATCH_ANY
#define FUTEX_BITSET_MATCH_ANY 0xFFFFFFFF
#endif
#endif
#if defined(__NR_futex_time64) && !defined(SYS_futex_time64)
#define SYS_futex_time64 __NR_futex_time64
#endif
#if defined(SYS_futex_time64) && !defined(SYS_futex)
#define SYS_futex SYS_futex_time64
#endif
class FutexImpl {
public:
static int WaitUntil(std::atomic<int32_t> *v, int32_t val,
KernelTimeout t) {
int err = 0;
if (t.has_timeout()) {
// https://locklessinc.com/articles/futex_cheat_sheet/
// Unlike FUTEX_WAIT, FUTEX_WAIT_BITSET uses absolute time.
struct timespec abs_timeout = t.MakeAbsTimespec();
// Atomically check that the futex value is still 0, and if it
// is, sleep until abs_timeout or until woken by FUTEX_WAKE.
err = syscall(
SYS_futex, reinterpret_cast<int32_t *>(v),
FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME, val,
&abs_timeout, nullptr, FUTEX_BITSET_MATCH_ANY);
} else {
// Atomically check that the futex value is still 0, and if it
// is, sleep until woken by FUTEX_WAKE.
err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
FUTEX_WAIT | FUTEX_PRIVATE_FLAG, val, nullptr);
}
if (ABSL_PREDICT_FALSE(err != 0)) {
err = -errno;
}
return err;
}
static int WaitBitsetAbsoluteTimeout(std::atomic<int32_t> *v, int32_t val,
int32_t bits,
const struct timespec *abstime) {
int err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG, val, abstime,
nullptr, bits);
if (ABSL_PREDICT_FALSE(err != 0)) {
err = -errno;
}
return err;
}
static int Wake(std::atomic<int32_t> *v, int32_t count) {
int err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
FUTEX_WAKE | FUTEX_PRIVATE_FLAG, count);
if (ABSL_PREDICT_FALSE(err < 0)) {
err = -errno;
}
return err;
}
// FUTEX_WAKE_BITSET
static int WakeBitset(std::atomic<int32_t> *v, int32_t count, int32_t bits) {
int err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
FUTEX_WAKE_BITSET | FUTEX_PRIVATE_FLAG, count, nullptr,
nullptr, bits);
if (ABSL_PREDICT_FALSE(err < 0)) {
err = -errno;
}
return err;
}
};
class Futex : public FutexImpl {};
} // namespace synchronization_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_SYNCHRONIZATION_INTERNAL_FUTEX_H_
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#define ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_ #define ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_
#include <time.h> #include <time.h>
#include <algorithm> #include <algorithm>
#include <limits> #include <limits>
......
...@@ -48,6 +48,11 @@ ...@@ -48,6 +48,11 @@
#include "absl/base/optimization.h" #include "absl/base/optimization.h"
#include "absl/synchronization/internal/kernel_timeout.h" #include "absl/synchronization/internal/kernel_timeout.h"
#if ABSL_WAITER_MODE == ABSL_WAITER_MODE_FUTEX
#include "absl/synchronization/internal/futex.h"
#endif
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
namespace synchronization_internal { namespace synchronization_internal {
...@@ -66,71 +71,6 @@ static void MaybeBecomeIdle() { ...@@ -66,71 +71,6 @@ static void MaybeBecomeIdle() {
#if ABSL_WAITER_MODE == ABSL_WAITER_MODE_FUTEX #if ABSL_WAITER_MODE == ABSL_WAITER_MODE_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_WAIT_BITSET
#define FUTEX_WAIT_BITSET 9
#endif
#ifndef FUTEX_PRIVATE_FLAG
#define FUTEX_PRIVATE_FLAG 128
#endif
#ifndef FUTEX_CLOCK_REALTIME
#define FUTEX_CLOCK_REALTIME 256
#endif
#ifndef FUTEX_BITSET_MATCH_ANY
#define FUTEX_BITSET_MATCH_ANY 0xFFFFFFFF
#endif
#endif
#if defined(__NR_futex_time64) && !defined(SYS_futex_time64)
#define SYS_futex_time64 __NR_futex_time64
#endif
#if defined(SYS_futex_time64) && !defined(SYS_futex)
#define SYS_futex SYS_futex_time64
#endif
class Futex {
public:
static int WaitUntil(std::atomic<int32_t> *v, int32_t val,
KernelTimeout t) {
int err = 0;
if (t.has_timeout()) {
// https://locklessinc.com/articles/futex_cheat_sheet/
// Unlike FUTEX_WAIT, FUTEX_WAIT_BITSET uses absolute time.
struct timespec abs_timeout = t.MakeAbsTimespec();
// Atomically check that the futex value is still 0, and if it
// is, sleep until abs_timeout or until woken by FUTEX_WAKE.
err = syscall(
SYS_futex, reinterpret_cast<int32_t *>(v),
FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME, val,
&abs_timeout, nullptr, FUTEX_BITSET_MATCH_ANY);
} else {
// Atomically check that the futex value is still 0, and if it
// is, sleep until woken by FUTEX_WAKE.
err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
FUTEX_WAIT | FUTEX_PRIVATE_FLAG, val, nullptr);
}
if (err != 0) {
err = -errno;
}
return err;
}
static int Wake(std::atomic<int32_t> *v, int32_t count) {
int err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
FUTEX_WAKE | FUTEX_PRIVATE_FLAG, count);
if (ABSL_PREDICT_FALSE(err < 0)) {
err = -errno;
}
return err;
}
};
Waiter::Waiter() { Waiter::Waiter() {
futex_.store(0, std::memory_order_relaxed); futex_.store(0, std::memory_order_relaxed);
} }
......
...@@ -88,7 +88,7 @@ ABSL_CONST_INIT std::atomic<OnDeadlockCycle> synch_deadlock_detection( ...@@ -88,7 +88,7 @@ ABSL_CONST_INIT std::atomic<OnDeadlockCycle> synch_deadlock_detection(
ABSL_CONST_INIT std::atomic<bool> synch_check_invariants(false); ABSL_CONST_INIT std::atomic<bool> synch_check_invariants(false);
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;
ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES absl::base_internal::AtomicHook<void (*)( ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES absl::base_internal::AtomicHook<void (*)(
const char *msg, const void *obj, int64_t wait_cycles)> const char *msg, const void *obj, int64_t wait_cycles)>
...@@ -2311,7 +2311,8 @@ ABSL_ATTRIBUTE_NOINLINE void Mutex::UnlockSlow(SynchWaitParams *waitp) { ...@@ -2311,7 +2311,8 @@ ABSL_ATTRIBUTE_NOINLINE void Mutex::UnlockSlow(SynchWaitParams *waitp) {
if (!cond_waiter) { if (!cond_waiter) {
// Sample lock contention events only if the (first) waiter was trying to // Sample lock contention events only if the (first) waiter was trying to
// acquire the lock, not waiting on a condition variable or Condition. // acquire the lock, not waiting on a condition variable or Condition.
int64_t wait_cycles = base_internal::CycleClock::Now() - enqueue_timestamp; int64_t wait_cycles =
base_internal::CycleClock::Now() - enqueue_timestamp;
mutex_tracer("slow release", this, wait_cycles); mutex_tracer("slow release", this, wait_cycles);
ABSL_TSAN_MUTEX_PRE_DIVERT(this, 0); ABSL_TSAN_MUTEX_PRE_DIVERT(this, 0);
submit_profile_data(enqueue_timestamp); submit_profile_data(enqueue_timestamp);
......
...@@ -667,10 +667,10 @@ class Condition { ...@@ -667,10 +667,10 @@ class Condition {
// }; // };
// mu_.Await(Condition(&reached)); // mu_.Await(Condition(&reached));
// //
// NOTE: never use "mu_.AssertHeld()" instead of "mu_.AssertReadHeld()" in the // NOTE: never use "mu_.AssertHeld()" instead of "mu_.AssertReaderHeld()" in
// lambda as it may be called when the mutex is being unlocked from a scope // the lambda as it may be called when the mutex is being unlocked from a
// holding only a reader lock, which will make the assertion not fulfilled and // scope holding only a reader lock, which will make the assertion not
// crash the binary. // fulfilled and crash the binary.
// See class comment for performance advice. In particular, if there // See class comment for performance advice. In particular, if there
// might be more than one waiter for the same condition, make sure // might be more than one waiter for the same condition, make sure
......
...@@ -74,9 +74,7 @@ ABSL_NAMESPACE_END ...@@ -74,9 +74,7 @@ ABSL_NAMESPACE_END
#if !ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS #if !ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
int64_t GetCurrentTimeNanos() { int64_t GetCurrentTimeNanos() { return GET_CURRENT_TIME_NANOS_FROM_SYSTEM(); }
return GET_CURRENT_TIME_NANOS_FROM_SYSTEM();
}
ABSL_NAMESPACE_END ABSL_NAMESPACE_END
} // namespace absl } // namespace absl
#else // Use the cyclecounter-based implementation below. #else // Use the cyclecounter-based implementation below.
......
...@@ -60,9 +60,10 @@ inline cctz::time_point<cctz::seconds> unix_epoch() { ...@@ -60,9 +60,10 @@ inline cctz::time_point<cctz::seconds> unix_epoch() {
inline int64_t FloorToUnit(absl::Duration d, absl::Duration unit) { inline int64_t FloorToUnit(absl::Duration d, absl::Duration unit) {
absl::Duration rem; absl::Duration rem;
int64_t q = absl::IDivDuration(d, unit, &rem); int64_t q = absl::IDivDuration(d, unit, &rem);
return (q > 0 || return (q > 0 || rem >= ZeroDuration() ||
rem >= ZeroDuration() || q == std::numeric_limits<int64_t>::min())
q == std::numeric_limits<int64_t>::min()) ? q : q - 1; ? q
: q - 1;
} }
inline absl::Time::Breakdown InfiniteFutureBreakdown() { inline absl::Time::Breakdown InfiniteFutureBreakdown() {
......
...@@ -1494,12 +1494,10 @@ constexpr Duration Hours(int64_t n) { ...@@ -1494,12 +1494,10 @@ constexpr Duration Hours(int64_t n) {
constexpr bool operator<(Duration lhs, Duration rhs) { constexpr bool operator<(Duration lhs, Duration rhs) {
return time_internal::GetRepHi(lhs) != time_internal::GetRepHi(rhs) return time_internal::GetRepHi(lhs) != time_internal::GetRepHi(rhs)
? time_internal::GetRepHi(lhs) < time_internal::GetRepHi(rhs) ? time_internal::GetRepHi(lhs) < time_internal::GetRepHi(rhs)
: time_internal::GetRepHi(lhs) == : time_internal::GetRepHi(lhs) == (std::numeric_limits<int64_t>::min)()
(std::numeric_limits<int64_t>::min)()
? time_internal::GetRepLo(lhs) + 1 < ? time_internal::GetRepLo(lhs) + 1 <
time_internal::GetRepLo(rhs) + 1 time_internal::GetRepLo(rhs) + 1
: time_internal::GetRepLo(lhs) < : time_internal::GetRepLo(lhs) < time_internal::GetRepLo(rhs);
time_internal::GetRepLo(rhs);
} }
constexpr bool operator==(Duration lhs, Duration rhs) { constexpr bool operator==(Duration lhs, Duration rhs) {
......
...@@ -1070,7 +1070,8 @@ TEST(Time, ConversionSaturation) { ...@@ -1070,7 +1070,8 @@ TEST(Time, ConversionSaturation) {
EXPECT_EQ("292277026596-12-04T15:30:07+00:00", EXPECT_EQ("292277026596-12-04T15:30:07+00:00",
absl::FormatTime(absl::RFC3339_full, t, utc)); absl::FormatTime(absl::RFC3339_full, t, utc));
EXPECT_EQ( EXPECT_EQ(
absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::max()), t); absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::max()),
t);
// Checks that we can also get the maximal Time value for a far-east zone. // Checks that we can also get the maximal Time value for a far-east zone.
const absl::TimeZone plus14 = absl::FixedTimeZone(14 * 60 * 60); const absl::TimeZone plus14 = absl::FixedTimeZone(14 * 60 * 60);
...@@ -1078,7 +1079,8 @@ TEST(Time, ConversionSaturation) { ...@@ -1078,7 +1079,8 @@ TEST(Time, ConversionSaturation) {
EXPECT_EQ("292277026596-12-05T05:30:07+14:00", EXPECT_EQ("292277026596-12-05T05:30:07+14:00",
absl::FormatTime(absl::RFC3339_full, t, plus14)); absl::FormatTime(absl::RFC3339_full, t, plus14));
EXPECT_EQ( EXPECT_EQ(
absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::max()), t); absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::max()),
t);
// One second later should push us to infinity. // One second later should push us to infinity.
t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 4, 15, 30, 8), utc); t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 4, 15, 30, 8), utc);
...@@ -1092,7 +1094,8 @@ TEST(Time, ConversionSaturation) { ...@@ -1092,7 +1094,8 @@ TEST(Time, ConversionSaturation) {
EXPECT_EQ("-292277022657-01-27T08:29:52+00:00", EXPECT_EQ("-292277022657-01-27T08:29:52+00:00",
absl::FormatTime(absl::RFC3339_full, t, utc)); absl::FormatTime(absl::RFC3339_full, t, utc));
EXPECT_EQ( EXPECT_EQ(
absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::min()), t); absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::min()),
t);
// Checks that we can also get the minimal Time value for a far-west zone. // Checks that we can also get the minimal Time value for a far-west zone.
const absl::TimeZone minus12 = absl::FixedTimeZone(-12 * 60 * 60); const absl::TimeZone minus12 = absl::FixedTimeZone(-12 * 60 * 60);
...@@ -1101,7 +1104,8 @@ TEST(Time, ConversionSaturation) { ...@@ -1101,7 +1104,8 @@ TEST(Time, ConversionSaturation) {
EXPECT_EQ("-292277022657-01-26T20:29:52-12:00", EXPECT_EQ("-292277022657-01-26T20:29:52-12:00",
absl::FormatTime(absl::RFC3339_full, t, minus12)); absl::FormatTime(absl::RFC3339_full, t, minus12));
EXPECT_EQ( EXPECT_EQ(
absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::min()), t); absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::min()),
t);
// One second before should push us to -infinity. // One second before should push us to -infinity.
t = absl::FromCivil(absl::CivilSecond(-292277022657, 1, 27, 8, 29, 51), utc); t = absl::FromCivil(absl::CivilSecond(-292277022657, 1, 27, 8, 29, 51), utc);
......
...@@ -45,7 +45,7 @@ ABSL_NAMESPACE_BEGIN ...@@ -45,7 +45,7 @@ ABSL_NAMESPACE_BEGIN
template <class... Types> template <class... Types>
class variant; class variant;
ABSL_INTERNAL_INLINE_CONSTEXPR(size_t, variant_npos, -1); ABSL_INTERNAL_INLINE_CONSTEXPR(size_t, variant_npos, static_cast<size_t>(-1));
template <class T> template <class T>
struct variant_size; struct variant_size;
......
...@@ -2311,7 +2311,8 @@ TEST(VariantTest, TestRvalueConversion) { ...@@ -2311,7 +2311,8 @@ TEST(VariantTest, TestRvalueConversion) {
ASSERT_TRUE(absl::holds_alternative<int32_t>(variant2)); ASSERT_TRUE(absl::holds_alternative<int32_t>(variant2));
EXPECT_EQ(42, absl::get<int32_t>(variant2)); EXPECT_EQ(42, absl::get<int32_t>(variant2));
variant2 = ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42)); variant2 =
ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42));
ASSERT_TRUE(absl::holds_alternative<uint32_t>(variant2)); ASSERT_TRUE(absl::holds_alternative<uint32_t>(variant2));
EXPECT_EQ(42, absl::get<uint32_t>(variant2)); EXPECT_EQ(42, absl::get<uint32_t>(variant2));
#endif // !ABSL_USES_STD_VARIANT #endif // !ABSL_USES_STD_VARIANT
...@@ -2453,7 +2454,8 @@ TEST(VariantTest, TestRvalueConversionViaConvertVariantTo) { ...@@ -2453,7 +2454,8 @@ TEST(VariantTest, TestRvalueConversionViaConvertVariantTo) {
ConvertVariantTo<variant<int32_t, uint32_t>>(variant<int32_t>(42))); ConvertVariantTo<variant<int32_t, uint32_t>>(variant<int32_t>(42)));
EXPECT_THAT(absl::get_if<int32_t>(&variant2), Pointee(42)); EXPECT_THAT(absl::get_if<int32_t>(&variant2), Pointee(42));
variant2 = ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42)); variant2 =
ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42));
EXPECT_THAT(absl::get_if<uint32_t>(&variant2), Pointee(42)); EXPECT_THAT(absl::get_if<uint32_t>(&variant2), Pointee(42));
#endif #endif
......
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