summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Abseil Team <absl-team@google.com>2021-10-27 13:22:18 -0700
committerGravatar Andy Getz <durandal@google.com>2021-10-28 00:09:21 -0400
commitcc413f8b674d61e3aa948386432e526e051afca0 (patch)
tree87292c6510661a0443c346c7b8be360c824647a4
parentf70eadadd7767c3a97774b63c4c23981fa89af9f (diff)
Export of internal Abseil changes
-- 05a099a580753f8e96cee38572e94dcdc079361b by Abseil Team <absl-team@google.com>: Import of CCTZ from GitHub. PiperOrigin-RevId: 405966217 -- c6b81e9ebc183d8389f14ecd091c8bad08cfe0aa by Abseil Team <absl-team@google.com>: Add `inline_element_size` to hashtablez (so that we can compute the weighted load factors properly e.g., in b/187896534). PiperOrigin-RevId: 405917711 -- 3e3673de4e54e4142c54b09e1644dfa3de4bb296 by Abseil Team <absl-team@google.com>: align indent of code comment in mutex.h PiperOrigin-RevId: 405871997 -- 2248301a5b14f8d2be5b2e9088f3528a353ea491 by Derek Mauro <dmauro@google.com>: Internal change PiperOrigin-RevId: 405639236 -- bc7d3c56fdad3dde4b89324af142529f2afe5f1b by Abseil Team <absl-team@google.com>: Import of CCTZ from GitHub. PiperOrigin-RevId: 405508045 -- 66472387276ef02505d99195747be862768bb35b by Laramie Leavitt <lar@google.com>: Also use uint8_t golden values in randen_test.cc This makes randen_test, randen_slow_test, and randen_hwaes_test essentially identical, as is the intent. PiperOrigin-RevId: 405484423 GitOrigin-RevId: 05a099a580753f8e96cee38572e94dcdc079361b Change-Id: I3dd5b0cfdb98d6e1ab02266194ba67d15428c2f8
-rw-r--r--absl/container/BUILD.bazel16
-rw-r--r--absl/container/CMakeLists.txt15
-rw-r--r--absl/container/internal/hashtablez_sampler.cc15
-rw-r--r--absl/container/internal/hashtablez_sampler.h9
-rw-r--r--absl/container/internal/hashtablez_sampler_test.cc19
-rw-r--r--absl/container/internal/raw_hash_set.h2
-rw-r--r--absl/container/internal/raw_hash_set_test.cc1
-rw-r--r--absl/container/sample_element_size_test.cc114
-rw-r--r--absl/random/internal/randen_test.cc45
-rw-r--r--absl/synchronization/mutex.h6
-rw-r--r--absl/time/internal/cctz/src/time_zone_info.cc69
-rw-r--r--absl/time/internal/cctz/src/time_zone_lookup.cc49
-rw-r--r--absl/time/internal/cctz/src/time_zone_lookup_test.cc4
-rw-r--r--absl/time/internal/cctz/testdata/version2
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Gazabin1213 -> 1230 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Hebronbin1231 -> 1248 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fijibin419 -> 428 bytes
17 files changed, 329 insertions, 37 deletions
diff --git a/absl/container/BUILD.bazel b/absl/container/BUILD.bazel
index d1df524a..ffaee19c 100644
--- a/absl/container/BUILD.bazel
+++ b/absl/container/BUILD.bazel
@@ -876,6 +876,22 @@ cc_test(
],
)
+cc_test(
+ name = "sample_element_size_test",
+ srcs = ["sample_element_size_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ tags = NOTEST_TAGS_NONMOBILE,
+ visibility = ["//visibility:private"],
+ deps = [
+ ":flat_hash_map",
+ ":flat_hash_set",
+ ":node_hash_map",
+ ":node_hash_set",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
cc_library(
name = "btree",
srcs = [
diff --git a/absl/container/CMakeLists.txt b/absl/container/CMakeLists.txt
index 9b8a7509..78584d2c 100644
--- a/absl/container/CMakeLists.txt
+++ b/absl/container/CMakeLists.txt
@@ -894,3 +894,18 @@ absl_cc_test(
absl::unordered_map_modifiers_test
GTest::gmock_main
)
+
+absl_cc_test(
+ NAME
+ sample_element_size_test
+ SRCS
+ "sample_element_size_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::flat_hash_map
+ absl::flat_hash_set
+ absl::node_hash_map
+ absl::node_hash_set
+ GTest::gmock_main
+)
diff --git a/absl/container/internal/hashtablez_sampler.cc b/absl/container/internal/hashtablez_sampler.cc
index 7070912e..40cce047 100644
--- a/absl/container/internal/hashtablez_sampler.cc
+++ b/absl/container/internal/hashtablez_sampler.cc
@@ -55,6 +55,9 @@ HashtablezSampler& GlobalHashtablezSampler() {
return *sampler;
}
+// TODO(bradleybear): The comments at this constructors declaration say that the
+// fields are not initialized, but this definition does initialize the fields.
+// Something needs to be cleaned up.
HashtablezInfo::HashtablezInfo() { PrepareForSampling(); }
HashtablezInfo::~HashtablezInfo() = default;
@@ -98,10 +101,12 @@ static bool ShouldForceSampling() {
return state == kForce;
}
-HashtablezInfo* SampleSlow(int64_t* next_sample) {
+HashtablezInfo* SampleSlow(int64_t* next_sample, size_t inline_element_size) {
if (ABSL_PREDICT_FALSE(ShouldForceSampling())) {
*next_sample = 1;
- return GlobalHashtablezSampler().Register();
+ HashtablezInfo* result = GlobalHashtablezSampler().Register();
+ result->inline_element_size = inline_element_size;
+ return result;
}
#if !defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
@@ -123,10 +128,12 @@ HashtablezInfo* SampleSlow(int64_t* next_sample) {
// that case.
if (first) {
if (ABSL_PREDICT_TRUE(--*next_sample > 0)) return nullptr;
- return SampleSlow(next_sample);
+ return SampleSlow(next_sample, inline_element_size);
}
- return GlobalHashtablezSampler().Register();
+ HashtablezInfo* result = GlobalHashtablezSampler().Register();
+ result->inline_element_size = inline_element_size;
+ return result;
#endif
}
diff --git a/absl/container/internal/hashtablez_sampler.h b/absl/container/internal/hashtablez_sampler.h
index 812118e3..91fcdb34 100644
--- a/absl/container/internal/hashtablez_sampler.h
+++ b/absl/container/internal/hashtablez_sampler.h
@@ -91,6 +91,7 @@ struct HashtablezInfo : public profiling_internal::Sample<HashtablezInfo> {
absl::Time create_time;
int32_t depth;
void* stack[kMaxStackDepth];
+ size_t inline_element_size;
};
inline void RecordRehashSlow(HashtablezInfo* info, size_t total_probe_length) {
@@ -143,7 +144,7 @@ inline void RecordEraseSlow(HashtablezInfo* info) {
std::memory_order_relaxed);
}
-HashtablezInfo* SampleSlow(int64_t* next_sample);
+HashtablezInfo* SampleSlow(int64_t* next_sample, size_t inline_element_size);
void UnsampleSlow(HashtablezInfo* info);
#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
@@ -238,12 +239,14 @@ extern ABSL_PER_THREAD_TLS_KEYWORD int64_t global_next_sample;
// Returns an RAII sampling handle that manages registration and unregistation
// with the global sampler.
-inline HashtablezInfoHandle Sample() {
+inline HashtablezInfoHandle Sample(
+ size_t inline_element_size ABSL_ATTRIBUTE_UNUSED) {
#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
if (ABSL_PREDICT_TRUE(--global_next_sample > 0)) {
return HashtablezInfoHandle(nullptr);
}
- return HashtablezInfoHandle(SampleSlow(&global_next_sample));
+ return HashtablezInfoHandle(
+ SampleSlow(&global_next_sample, inline_element_size));
#else
return HashtablezInfoHandle(nullptr);
#endif // !ABSL_PER_THREAD_TLS
diff --git a/absl/container/internal/hashtablez_sampler_test.cc b/absl/container/internal/hashtablez_sampler_test.cc
index f053c19b..449619a3 100644
--- a/absl/container/internal/hashtablez_sampler_test.cc
+++ b/absl/container/internal/hashtablez_sampler_test.cc
@@ -78,10 +78,12 @@ HashtablezInfo* Register(HashtablezSampler* s, size_t size) {
TEST(HashtablezInfoTest, PrepareForSampling) {
absl::Time test_start = absl::Now();
+ const size_t test_element_size = 17;
HashtablezInfo info;
absl::MutexLock l(&info.init_mu);
info.PrepareForSampling();
+ info.inline_element_size = test_element_size;
EXPECT_EQ(info.capacity.load(), 0);
EXPECT_EQ(info.size.load(), 0);
EXPECT_EQ(info.num_erases.load(), 0);
@@ -93,6 +95,7 @@ TEST(HashtablezInfoTest, PrepareForSampling) {
EXPECT_EQ(info.hashes_bitwise_xor.load(), 0);
EXPECT_EQ(info.max_reserve.load(), 0);
EXPECT_GE(info.create_time, test_start);
+ EXPECT_EQ(info.inline_element_size, test_element_size);
info.capacity.store(1, std::memory_order_relaxed);
info.size.store(1, std::memory_order_relaxed);
@@ -116,6 +119,7 @@ TEST(HashtablezInfoTest, PrepareForSampling) {
EXPECT_EQ(info.hashes_bitwise_and.load(), ~size_t{});
EXPECT_EQ(info.hashes_bitwise_xor.load(), 0);
EXPECT_EQ(info.max_reserve.load(), 0);
+ EXPECT_EQ(info.inline_element_size, test_element_size);
EXPECT_GE(info.create_time, test_start);
}
@@ -154,9 +158,11 @@ TEST(HashtablezInfoTest, RecordInsert) {
}
TEST(HashtablezInfoTest, RecordErase) {
+ const size_t test_element_size = 29;
HashtablezInfo info;
absl::MutexLock l(&info.init_mu);
info.PrepareForSampling();
+ info.inline_element_size = test_element_size;
EXPECT_EQ(info.num_erases.load(), 0);
EXPECT_EQ(info.size.load(), 0);
RecordInsertSlow(&info, 0x0000FF00, 6 * kProbeLength);
@@ -164,12 +170,15 @@ TEST(HashtablezInfoTest, RecordErase) {
RecordEraseSlow(&info);
EXPECT_EQ(info.size.load(), 0);
EXPECT_EQ(info.num_erases.load(), 1);
+ EXPECT_EQ(info.inline_element_size, test_element_size);
}
TEST(HashtablezInfoTest, RecordRehash) {
+ const size_t test_element_size = 31;
HashtablezInfo info;
absl::MutexLock l(&info.init_mu);
info.PrepareForSampling();
+ info.inline_element_size = test_element_size;
RecordInsertSlow(&info, 0x1, 0);
RecordInsertSlow(&info, 0x2, kProbeLength);
RecordInsertSlow(&info, 0x4, kProbeLength);
@@ -188,6 +197,7 @@ TEST(HashtablezInfoTest, RecordRehash) {
EXPECT_EQ(info.total_probe_length.load(), 3);
EXPECT_EQ(info.num_erases.load(), 0);
EXPECT_EQ(info.num_rehashes.load(), 1);
+ EXPECT_EQ(info.inline_element_size, test_element_size);
}
TEST(HashtablezInfoTest, RecordReservation) {
@@ -208,12 +218,13 @@ TEST(HashtablezInfoTest, RecordReservation) {
#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
TEST(HashtablezSamplerTest, SmallSampleParameter) {
+ const size_t test_element_size = 31;
SetHashtablezEnabled(true);
SetHashtablezSampleParameter(100);
for (int i = 0; i < 1000; ++i) {
int64_t next_sample = 0;
- HashtablezInfo* sample = SampleSlow(&next_sample);
+ HashtablezInfo* sample = SampleSlow(&next_sample, test_element_size);
EXPECT_GT(next_sample, 0);
EXPECT_NE(sample, nullptr);
UnsampleSlow(sample);
@@ -221,12 +232,13 @@ TEST(HashtablezSamplerTest, SmallSampleParameter) {
}
TEST(HashtablezSamplerTest, LargeSampleParameter) {
+ const size_t test_element_size = 31;
SetHashtablezEnabled(true);
SetHashtablezSampleParameter(std::numeric_limits<int32_t>::max());
for (int i = 0; i < 1000; ++i) {
int64_t next_sample = 0;
- HashtablezInfo* sample = SampleSlow(&next_sample);
+ HashtablezInfo* sample = SampleSlow(&next_sample, test_element_size);
EXPECT_GT(next_sample, 0);
EXPECT_NE(sample, nullptr);
UnsampleSlow(sample);
@@ -234,13 +246,14 @@ TEST(HashtablezSamplerTest, LargeSampleParameter) {
}
TEST(HashtablezSamplerTest, Sample) {
+ const size_t test_element_size = 31;
SetHashtablezEnabled(true);
SetHashtablezSampleParameter(100);
int64_t num_sampled = 0;
int64_t total = 0;
double sample_rate = 0.0;
for (int i = 0; i < 1000000; ++i) {
- HashtablezInfoHandle h = Sample();
+ HashtablezInfoHandle h = Sample(test_element_size);
++total;
if (HashtablezInfoHandlePeer::IsSampled(h)) {
++num_sampled;
diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h
index 47e5a228..12682b35 100644
--- a/absl/container/internal/raw_hash_set.h
+++ b/absl/container/internal/raw_hash_set.h
@@ -1643,7 +1643,7 @@ class raw_hash_set {
// bound more carefully.
if (std::is_same<SlotAlloc, std::allocator<slot_type>>::value &&
slots_ == nullptr) {
- infoz() = Sample();
+ infoz() = Sample(sizeof(slot_type));
}
char* mem = static_cast<char*>(Allocate<alignof(slot_type)>(
diff --git a/absl/container/internal/raw_hash_set_test.cc b/absl/container/internal/raw_hash_set_test.cc
index b46c4920..362b3cae 100644
--- a/absl/container/internal/raw_hash_set_test.cc
+++ b/absl/container/internal/raw_hash_set_test.cc
@@ -2075,6 +2075,7 @@ TEST(RawHashSamplerTest, Sample) {
std::memory_order_relaxed)]++;
reservations[info.max_reserve.load(std::memory_order_relaxed)]++;
}
+ EXPECT_EQ(info.inline_element_size, sizeof(int64_t));
++end_size;
});
diff --git a/absl/container/sample_element_size_test.cc b/absl/container/sample_element_size_test.cc
new file mode 100644
index 00000000..b23626b4
--- /dev/null
+++ b/absl/container/sample_element_size_test.cc
@@ -0,0 +1,114 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// 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 "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/container/flat_hash_map.h"
+#include "absl/container/flat_hash_set.h"
+#include "absl/container/node_hash_map.h"
+#include "absl/container/node_hash_set.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+namespace {
+
+#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
+// Create some tables of type `Table`, then look at all the new
+// `HashtablezInfo`s to make sure that the `inline_element_size ==
+// expected_element_size`. The `inline_element_size` is the amount of memory
+// allocated for each slot of a hash table, that is `sizeof(slot_type)`. Add
+// the new `HashtablezInfo`s to `preexisting_info`. Store all the new tables
+// into `tables`.
+template <class Table>
+void TestInlineElementSize(
+ HashtablezSampler& sampler,
+ // clang-tidy gives a false positive on this declaration. This unordered
+ // set cannot be flat_hash_set, however, since that would introduce a mutex
+ // deadlock.
+ std::unordered_set<const HashtablezInfo*>& preexisting_info, // NOLINT
+ std::vector<Table>& tables, const typename Table::value_type& elt,
+ size_t expected_element_size) {
+ for (int i = 0; i < 10; ++i) {
+ // We create a new table and must store it somewhere so that when we store
+ // a pointer to the resulting `HashtablezInfo` into `preexisting_info`
+ // that we aren't storing a dangling pointer.
+ tables.emplace_back();
+ // We must insert an element to get a hashtablez to instantiate.
+ tables.back().insert(elt);
+ }
+ size_t new_count = 0;
+ sampler.Iterate([&](const HashtablezInfo& info) {
+ if (preexisting_info.insert(&info).second) {
+ EXPECT_EQ(info.inline_element_size, expected_element_size);
+ ++new_count;
+ }
+ });
+ // Make sure we actually did get a new hashtablez.
+ EXPECT_GT(new_count, 0);
+}
+
+struct bigstruct {
+ char a[1000];
+ friend bool operator==(const bigstruct& x, const bigstruct& y) {
+ return memcmp(x.a, y.a, sizeof(x.a)) == 0;
+ }
+ template <typename H>
+ friend H AbslHashValue(H h, const bigstruct& c) {
+ return H::combine_contiguous(std::move(h), c.a, sizeof(c.a));
+ }
+};
+#endif
+
+TEST(FlatHashMap, SampleElementSize) {
+#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
+ // Enable sampling even if the prod default is off.
+ SetHashtablezEnabled(true);
+ SetHashtablezSampleParameter(1);
+
+ auto& sampler = GlobalHashtablezSampler();
+ std::vector<flat_hash_map<int, bigstruct>> flat_map_tables;
+ std::vector<flat_hash_set<bigstruct>> flat_set_tables;
+ std::vector<node_hash_map<int, bigstruct>> node_map_tables;
+ std::vector<node_hash_set<bigstruct>> node_set_tables;
+
+ // It takes thousands of new tables after changing the sampling parameters
+ // before you actually get some instrumentation. And if you must actually
+ // put something into those tables.
+ for (int i = 0; i < 10000; ++i) {
+ flat_map_tables.emplace_back();
+ flat_map_tables.back()[i] = bigstruct{};
+ }
+
+ // clang-tidy gives a false positive on this declaration. This unordered set
+ // cannot be a flat_hash_set, however, since that would introduce a mutex
+ // deadlock.
+ std::unordered_set<const HashtablezInfo*> preexisting_info; // NOLINT
+ sampler.Iterate(
+ [&](const HashtablezInfo& info) { preexisting_info.insert(&info); });
+ TestInlineElementSize(sampler, preexisting_info, flat_map_tables,
+ {0, bigstruct{}}, sizeof(int) + sizeof(bigstruct));
+ TestInlineElementSize(sampler, preexisting_info, node_map_tables,
+ {0, bigstruct{}}, sizeof(void*));
+ TestInlineElementSize(sampler, preexisting_info, flat_set_tables, //
+ bigstruct{}, sizeof(bigstruct));
+ TestInlineElementSize(sampler, preexisting_info, node_set_tables, //
+ bigstruct{}, sizeof(void*));
+#endif
+}
+
+} // namespace
+} // namespace container_internal
+ABSL_NAMESPACE_END
+} // namespace absl
diff --git a/absl/random/internal/randen_test.cc b/absl/random/internal/randen_test.cc
index c186fe0d..92773b8d 100644
--- a/absl/random/internal/randen_test.cc
+++ b/absl/random/internal/randen_test.cc
@@ -23,9 +23,6 @@ namespace {
using absl::random_internal::Randen;
-// Local state parameters.
-constexpr size_t kStateSizeT = Randen::kStateBytes / sizeof(uint64_t);
-
TEST(RandenTest, CopyAndMove) {
static_assert(std::is_copy_constructible<Randen>::value,
"Randen must be copy constructible");
@@ -41,30 +38,38 @@ TEST(RandenTest, CopyAndMove) {
}
TEST(RandenTest, Default) {
- constexpr uint64_t kGolden[] = {
- 0x6c6534090ee6d3ee, 0x044e2b9b9d5333c6, 0xc3c14f134e433977,
- 0xdda9f47cd90410ee, 0x887bf3087fd8ca10, 0xf0b780f545c72912,
- 0x15dbb1d37696599f, 0x30ec63baff3c6d59, 0xb29f73606f7f20a6,
- 0x02808a316f49a54c, 0x3b8feaf9d5c8e50e, 0x9cbf605e3fd9de8a,
- 0xc970ae1a78183bbb, 0xd8b2ffd356301ed5, 0xf4b327fe0fc73c37,
- 0xcdfd8d76eb8f9a19, 0xc3a506eb91420c9d, 0xd5af05dd3eff9556,
- 0x48db1bb78f83c4a1, 0x7023920e0d6bfe8c, 0x58d3575834956d42,
- 0xed1ef4c26b87b840, 0x8eef32a23e0b2df3, 0x497cabf3431154fc,
- 0x4e24370570029a8b, 0xd88b5749f090e5ea, 0xc651a582a970692f,
- 0x78fcec2cbb6342f5, 0x463cb745612f55db, 0x352ee4ad1816afe3,
- 0x026ff374c101da7e, 0x811ef0821c3de851,
+ constexpr uint8_t kGolden[] = {
+ 0xee, 0xd3, 0xe6, 0x0e, 0x09, 0x34, 0x65, 0x6c, 0xc6, 0x33, 0x53, 0x9d,
+ 0x9b, 0x2b, 0x4e, 0x04, 0x77, 0x39, 0x43, 0x4e, 0x13, 0x4f, 0xc1, 0xc3,
+ 0xee, 0x10, 0x04, 0xd9, 0x7c, 0xf4, 0xa9, 0xdd, 0x10, 0xca, 0xd8, 0x7f,
+ 0x08, 0xf3, 0x7b, 0x88, 0x12, 0x29, 0xc7, 0x45, 0xf5, 0x80, 0xb7, 0xf0,
+ 0x9f, 0x59, 0x96, 0x76, 0xd3, 0xb1, 0xdb, 0x15, 0x59, 0x6d, 0x3c, 0xff,
+ 0xba, 0x63, 0xec, 0x30, 0xa6, 0x20, 0x7f, 0x6f, 0x60, 0x73, 0x9f, 0xb2,
+ 0x4c, 0xa5, 0x49, 0x6f, 0x31, 0x8a, 0x80, 0x02, 0x0e, 0xe5, 0xc8, 0xd5,
+ 0xf9, 0xea, 0x8f, 0x3b, 0x8a, 0xde, 0xd9, 0x3f, 0x5e, 0x60, 0xbf, 0x9c,
+ 0xbb, 0x3b, 0x18, 0x78, 0x1a, 0xae, 0x70, 0xc9, 0xd5, 0x1e, 0x30, 0x56,
+ 0xd3, 0xff, 0xb2, 0xd8, 0x37, 0x3c, 0xc7, 0x0f, 0xfe, 0x27, 0xb3, 0xf4,
+ 0x19, 0x9a, 0x8f, 0xeb, 0x76, 0x8d, 0xfd, 0xcd, 0x9d, 0x0c, 0x42, 0x91,
+ 0xeb, 0x06, 0xa5, 0xc3, 0x56, 0x95, 0xff, 0x3e, 0xdd, 0x05, 0xaf, 0xd5,
+ 0xa1, 0xc4, 0x83, 0x8f, 0xb7, 0x1b, 0xdb, 0x48, 0x8c, 0xfe, 0x6b, 0x0d,
+ 0x0e, 0x92, 0x23, 0x70, 0x42, 0x6d, 0x95, 0x34, 0x58, 0x57, 0xd3, 0x58,
+ 0x40, 0xb8, 0x87, 0x6b, 0xc2, 0xf4, 0x1e, 0xed, 0xf3, 0x2d, 0x0b, 0x3e,
+ 0xa2, 0x32, 0xef, 0x8e, 0xfc, 0x54, 0x11, 0x43, 0xf3, 0xab, 0x7c, 0x49,
+ 0x8b, 0x9a, 0x02, 0x70, 0x05, 0x37, 0x24, 0x4e, 0xea, 0xe5, 0x90, 0xf0,
+ 0x49, 0x57, 0x8b, 0xd8, 0x2f, 0x69, 0x70, 0xa9, 0x82, 0xa5, 0x51, 0xc6,
+ 0xf5, 0x42, 0x63, 0xbb, 0x2c, 0xec, 0xfc, 0x78, 0xdb, 0x55, 0x2f, 0x61,
+ 0x45, 0xb7, 0x3c, 0x46, 0xe3, 0xaf, 0x16, 0x18, 0xad, 0xe4, 0x2e, 0x35,
+ 0x7e, 0xda, 0x01, 0xc1, 0x74, 0xf3, 0x6f, 0x02, 0x51, 0xe8, 0x3d, 0x1c,
+ 0x82, 0xf0, 0x1e, 0x81,
};
- alignas(16) uint64_t state[kStateSizeT];
+ alignas(16) uint8_t state[Randen::kStateBytes];
std::memset(state, 0, sizeof(state));
Randen r;
r.Generate(state);
- auto id = std::begin(state);
- for (const auto& elem : kGolden) {
- EXPECT_EQ(elem, *id++);
- }
+ EXPECT_EQ(0, std::memcmp(state, kGolden, sizeof(state)));
}
} // namespace
diff --git a/absl/synchronization/mutex.h b/absl/synchronization/mutex.h
index f49e0c83..38338f24 100644
--- a/absl/synchronization/mutex.h
+++ b/absl/synchronization/mutex.h
@@ -778,9 +778,9 @@ class Condition {
//
// Usage to wake T is:
// mu.Lock();
-// // process data, possibly establishing C
-// if (C) { cv->Signal(); }
-// mu.Unlock();
+// // process data, possibly establishing C
+// if (C) { cv->Signal(); }
+// mu.Unlock();
//
// If C may be useful to more than one waiter, use `SignalAll()` instead of
// `Signal()`.
diff --git a/absl/time/internal/cctz/src/time_zone_info.cc b/absl/time/internal/cctz/src/time_zone_info.cc
index f2777d91..4f175d95 100644
--- a/absl/time/internal/cctz/src/time_zone_info.cc
+++ b/absl/time/internal/cctz/src/time_zone_info.cc
@@ -39,6 +39,7 @@
#include <cstdio>
#include <cstdlib>
#include <cstring>
+#include <fstream>
#include <functional>
#include <memory>
#include <sstream>
@@ -649,7 +650,7 @@ std::unique_ptr<ZoneInfoSource> FileZoneInfoSource::Open(
// Open the zoneinfo file.
auto fp = FOpen(path.c_str(), "rb");
- if (fp.get() == nullptr) return nullptr;
+ if (fp == nullptr) return nullptr;
return std::unique_ptr<ZoneInfoSource>(new FileZoneInfoSource(std::move(fp)));
}
@@ -674,7 +675,7 @@ std::unique_ptr<ZoneInfoSource> AndroidZoneInfoSource::Open(
for (const char* tzdata : {"/data/misc/zoneinfo/current/tzdata",
"/system/usr/share/zoneinfo/tzdata"}) {
auto fp = FOpen(tzdata, "rb");
- if (fp.get() == nullptr) continue;
+ if (fp == nullptr) continue;
char hbuf[24]; // covers header.zonetab_offset too
if (fread(hbuf, 1, sizeof(hbuf), fp.get()) != sizeof(hbuf)) continue;
@@ -708,6 +709,69 @@ std::unique_ptr<ZoneInfoSource> AndroidZoneInfoSource::Open(
return nullptr;
}
+// A zoneinfo source for use inside Fuchsia components. This attempts to
+// read zoneinfo files from one of several known paths in a component's
+// incoming namespace. [Config data][1] is preferred, but package-specific
+// resources are also supported.
+//
+// Fuchsia's implementation supports `FileZoneInfoSource::Version()`.
+//
+// [1]:
+// https://fuchsia.dev/fuchsia-src/development/components/data#using_config_data_in_your_component
+class FuchsiaZoneInfoSource : public FileZoneInfoSource {
+ public:
+ static std::unique_ptr<ZoneInfoSource> Open(const std::string& name);
+ std::string Version() const override { return version_; }
+
+ private:
+ explicit FuchsiaZoneInfoSource(FilePtr fp, std::string version)
+ : FileZoneInfoSource(std::move(fp)), version_(std::move(version)) {}
+ std::string version_;
+};
+
+std::unique_ptr<ZoneInfoSource> FuchsiaZoneInfoSource::Open(
+ const std::string& name) {
+ // Use of the "file:" prefix is intended for testing purposes only.
+ const std::size_t pos = (name.compare(0, 5, "file:") == 0) ? 5 : 0;
+
+ // Prefixes where a Fuchsia component might find zoneinfo files,
+ // in descending order of preference.
+ const auto kTzdataPrefixes = {
+ "/config/data/tzdata/",
+ "/pkg/data/tzdata/",
+ "/data/tzdata/",
+ };
+ const auto kEmptyPrefix = {""};
+ const bool name_absolute = (pos != name.size() && name[pos] == '/');
+ const auto prefixes = name_absolute ? kEmptyPrefix : kTzdataPrefixes;
+
+ // Fuchsia builds place zoneinfo files at "<prefix><format><name>".
+ for (const std::string prefix : prefixes) {
+ std::string path = prefix;
+ if (!prefix.empty()) path += "zoneinfo/tzif2/"; // format
+ path.append(name, pos, std::string::npos);
+
+ auto fp = FOpen(path.c_str(), "rb");
+ if (fp == nullptr) continue;
+
+ std::string version;
+ if (!prefix.empty()) {
+ // Fuchsia builds place the version in "<prefix>revision.txt".
+ std::ifstream version_stream(prefix + "revision.txt");
+ if (version_stream.is_open()) {
+ // revision.txt should contain no newlines, but to be
+ // defensive we read just the first line.
+ std::getline(version_stream, version);
+ }
+ }
+
+ return std::unique_ptr<ZoneInfoSource>(
+ new FuchsiaZoneInfoSource(std::move(fp), std::move(version)));
+ }
+
+ return nullptr;
+}
+
} // namespace
bool TimeZoneInfo::Load(const std::string& name) {
@@ -725,6 +789,7 @@ bool TimeZoneInfo::Load(const std::string& name) {
name, [](const std::string& n) -> std::unique_ptr<ZoneInfoSource> {
if (auto z = FileZoneInfoSource::Open(n)) return z;
if (auto z = AndroidZoneInfoSource::Open(n)) return z;
+ if (auto z = FuchsiaZoneInfoSource::Open(n)) return z;
return nullptr;
});
return zip != nullptr && Load(zip.get());
diff --git a/absl/time/internal/cctz/src/time_zone_lookup.cc b/absl/time/internal/cctz/src/time_zone_lookup.cc
index efdea64b..898d04c1 100644
--- a/absl/time/internal/cctz/src/time_zone_lookup.cc
+++ b/absl/time/internal/cctz/src/time_zone_lookup.cc
@@ -28,6 +28,13 @@
#include <vector>
#endif
+#if defined(__Fuchsia__)
+#include <fuchsia/intl/cpp/fidl.h>
+#include <lib/async-loop/cpp/loop.h>
+#include <lib/sys/cpp/component_context.h>
+#include <zircon/types.h>
+#endif
+
#include <cstdlib>
#include <cstring>
#include <string>
@@ -140,6 +147,48 @@ time_zone local_time_zone() {
}
CFRelease(tz_default);
#endif
+#if defined(__Fuchsia__)
+ std::string primary_tz;
+ [&]() {
+ // Note: We can't use the synchronous FIDL API here because it doesn't
+ // allow timeouts; if the FIDL call failed, local_time_zone() would never
+ // return.
+
+ const zx::duration kTimeout = zx::msec(500);
+
+ // Don't attach to the thread because otherwise the thread's dispatcher
+ // would be set to null when the loop is destroyed, causing any other FIDL
+ // code running on the same thread to crash.
+ async::Loop loop(&kAsyncLoopConfigNeverAttachToThread);
+ std::unique_ptr<sys::ComponentContext> context =
+ sys::ComponentContext::Create();
+
+ fuchsia::intl::PropertyProviderHandle handle;
+ zx_status_t status = context->svc()->Connect(handle.NewRequest());
+ if (status != ZX_OK) {
+ return;
+ }
+
+ fuchsia::intl::PropertyProviderPtr intl_provider;
+ status = intl_provider.Bind(std::move(handle), loop.dispatcher());
+ if (status != ZX_OK) {
+ return;
+ }
+
+ intl_provider->GetProfile(
+ [&loop, &primary_tz](fuchsia::intl::Profile profile) {
+ if (!profile.time_zones().empty()) {
+ primary_tz = profile.time_zones()[0].id;
+ }
+ loop.Quit();
+ });
+ loop.Run(zx::deadline_after(kTimeout));
+ }();
+
+ if (!primary_tz.empty()) {
+ zone = primary_tz.c_str();
+ }
+#endif
// Allow ${TZ} to override to default zone.
char* tz_env = nullptr;
diff --git a/absl/time/internal/cctz/src/time_zone_lookup_test.cc b/absl/time/internal/cctz/src/time_zone_lookup_test.cc
index 8751b346..0226ab71 100644
--- a/absl/time/internal/cctz/src/time_zone_lookup_test.cc
+++ b/absl/time/internal/cctz/src/time_zone_lookup_test.cc
@@ -1027,8 +1027,12 @@ TEST(MakeTime, SysSecondsLimits) {
#endif
const year_t min_tm_year = year_t{std::numeric_limits<int>::min()} + 1900;
tp = convert(civil_second(min_tm_year, 1, 1, 0, 0, 0), cut);
+#if defined(__Fuchsia__)
+ // Fuchsia's gmtime_r() fails on extreme negative values (fxbug.dev/78527).
+#else
EXPECT_EQ("-2147481748-01-01T00:00:00+00:00", format(RFC3339, tp, cut));
#endif
+#endif
}
}
diff --git a/absl/time/internal/cctz/testdata/version b/absl/time/internal/cctz/testdata/version
index 51191b57..8ee898ba 100644
--- a/absl/time/internal/cctz/testdata/version
+++ b/absl/time/internal/cctz/testdata/version
@@ -1 +1 @@
-2021c
+2021e
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Gaza b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Gaza
index 58e9fdf4..ccc57c9c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Gaza
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Gaza
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hebron b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hebron
index aeda06b5..906d8d5c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hebron
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hebron
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fiji b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fiji
index e3934e42..8b2dd52b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fiji
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fiji
Binary files differ