mirror of
https://github.com/abseil/abseil-cpp.git
synced 2026-06-04 12:07:05 +08:00
Export of internal Abseil changes
-- 69b3ab092ee0fef3d27f589e709280c341f006c6 by Greg Falcon <gfalcon@google.com>: Import of CCTZ from GitHub. PiperOrigin-RevId: 321005878 -- 3a4038cd0cea6455453a7ae82f2de7e91d7e2bc1 by Abseil Team <absl-team@google.com>: Google-internal changes only. PiperOrigin-RevId: 320994821 -- f9d9a93782924df6ffc351a271c239ca4bdff3c8 by Derek Mauro <dmauro@google.com>: Update Linux latest toolchains, most notably to GCC 10.1 This create a new "hybrid" docker image that includes the latest versions of both GCC and LLVM. Since the LLVM build targets Debian 10, but Debian 10 uses an older version of libstdc++ that doesn't have full C++20 support, the easiest solution is to use the GCC/Debian 10 base image from DockerHub and copy LLVM into it. This also includes fixes to get the build working with the new toolchains. PiperOrigin-RevId: 320991795 -- 43129cd66dc4439b36d85030800a3929f20d9f86 by Abseil Team <absl-team@google.com>: Rollback import of CCTZ from GitHub (breaks MSAN tests) - e87b391f0d10ae9c3d2e70e4a3633337d2c5e643 handle "slim" TZif files in TimeZoneInfo::ExtendTransitio... by Bradley White <14679271+devbww@users.noreply.github.com> PiperOrigin-RevId: 320978767 -- 2a343a55f297d433c1521920f0bd20ddd2dc71e8 by Derek Mauro <dmauro@google.com>: Use ABSL_HAVE_ATTRIBUTE in thread_annotations.h PiperOrigin-RevId: 320956378 -- f6f3e8333c9ef6e6441586be6587bbfb1c8c8127 by Gennadiy Rozental <rogeeff@google.com>: Import of CCTZ from GitHub. PiperOrigin-RevId: 320952592 -- 3cc2bcce3533ac1233c0536232b07eea45fe8ed0 by Derek Mauro <dmauro@google.com>: Internal change PiperOrigin-RevId: 320862698 -- 4e22066476744609e42c475b55e3cbd874f04c39 by Gennadiy Rozental <rogeeff@google.com>: Internal change PiperOrigin-RevId: 320461277 GitOrigin-RevId: 69b3ab092ee0fef3d27f589e709280c341f006c6 Change-Id: I36f547711e7078d52f2e0a1ff3f4c903056a2b9e
This commit is contained in:
@@ -20,9 +20,9 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
||||
# GoogleTest/GoogleMock framework. Used by most unit-tests.
|
||||
http_archive(
|
||||
name = "com_google_googletest",
|
||||
urls = ["https://github.com/google/googletest/archive/011959aafddcd30611003de96cfd8d7a7685c700.zip"], # 2020-05-14T00:36:05Z
|
||||
strip_prefix = "googletest-011959aafddcd30611003de96cfd8d7a7685c700",
|
||||
sha256 = "6a5d7d63cd6e0ad2a7130471105a3b83799a7a2b14ef7ec8d742b54f01a4833c",
|
||||
urls = ["https://github.com/google/googletest/archive/8567b09290fe402cf01923e2131c5635b8ed851b.zip"], # 2020-06-12T22:24:28Z
|
||||
strip_prefix = "googletest-8567b09290fe402cf01923e2131c5635b8ed851b",
|
||||
sha256 = "9a8a166eb6a56c7b3d7b19dc2c946fe4778fd6f21c7a12368ad3b836d8f1be48",
|
||||
)
|
||||
|
||||
# Google benchmark.
|
||||
|
||||
@@ -61,5 +61,8 @@ config_setting(
|
||||
|
||||
config_setting(
|
||||
name = "wasm",
|
||||
values = {"cpu": "wasm32"},
|
||||
values = {
|
||||
"cpu": "wasm32",
|
||||
},
|
||||
visibility = [":__subpackages__"],
|
||||
)
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#ifndef ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_
|
||||
#define ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_
|
||||
|
||||
#include "absl/base/internal/raw_logging.h"
|
||||
#include "absl/base/internal/scheduling_mode.h"
|
||||
#include "absl/base/macros.h"
|
||||
|
||||
@@ -29,6 +30,13 @@ extern "C" void __google_enable_rescheduling(bool disable_result);
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
class CondVar;
|
||||
class Mutex;
|
||||
|
||||
namespace synchronization_internal {
|
||||
int MutexDelay(int32_t c, int mode);
|
||||
} // namespace synchronization_internal
|
||||
|
||||
namespace base_internal {
|
||||
|
||||
class SchedulingHelper; // To allow use of SchedulingGuard.
|
||||
@@ -76,9 +84,23 @@ class SchedulingGuard {
|
||||
bool disabled;
|
||||
};
|
||||
|
||||
// A scoped helper to enable rescheduling temporarily.
|
||||
// REQUIRES: destructor must run in same thread as constructor.
|
||||
class ScopedEnable {
|
||||
public:
|
||||
ScopedEnable();
|
||||
~ScopedEnable();
|
||||
|
||||
private:
|
||||
int scheduling_disabled_depth_;
|
||||
};
|
||||
|
||||
// Access to SchedulingGuard is explicitly permitted.
|
||||
friend class absl::CondVar;
|
||||
friend class absl::Mutex;
|
||||
friend class SchedulingHelper;
|
||||
friend class SpinLock;
|
||||
friend int absl::synchronization_internal::MutexDelay(int32_t c, int mode);
|
||||
|
||||
SchedulingGuard(const SchedulingGuard&) = delete;
|
||||
SchedulingGuard& operator=(const SchedulingGuard&) = delete;
|
||||
@@ -100,6 +122,12 @@ inline void SchedulingGuard::EnableRescheduling(bool /* disable_result */) {
|
||||
return;
|
||||
}
|
||||
|
||||
inline SchedulingGuard::ScopedEnable::ScopedEnable()
|
||||
: scheduling_disabled_depth_(0) {}
|
||||
inline SchedulingGuard::ScopedEnable::~ScopedEnable() {
|
||||
ABSL_RAW_CHECK(scheduling_disabled_depth_ == 0, "disable unused warning");
|
||||
}
|
||||
|
||||
} // namespace base_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
@@ -39,12 +39,6 @@
|
||||
// TODO(mbonadei): Remove after the backward compatibility period.
|
||||
#include "absl/base/internal/thread_annotations.h" // IWYU pragma: export
|
||||
|
||||
#if defined(__clang__)
|
||||
#define ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(x) __attribute__((x))
|
||||
#else
|
||||
#define ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(x) // no-op
|
||||
#endif
|
||||
|
||||
// ABSL_GUARDED_BY()
|
||||
//
|
||||
// Documents if a shared field or global variable needs to be protected by a
|
||||
@@ -62,8 +56,11 @@
|
||||
// int p1_ ABSL_GUARDED_BY(mu_);
|
||||
// ...
|
||||
// };
|
||||
#define ABSL_GUARDED_BY(x) \
|
||||
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(guarded_by(x))
|
||||
#if ABSL_HAVE_ATTRIBUTE(guarded_by)
|
||||
#define ABSL_GUARDED_BY(x) __attribute__((guarded_by(x)))
|
||||
#else
|
||||
#define ABSL_GUARDED_BY(x)
|
||||
#endif
|
||||
|
||||
// ABSL_PT_GUARDED_BY()
|
||||
//
|
||||
@@ -85,8 +82,11 @@
|
||||
// // `q_`, guarded by `mu1_`, points to a shared memory location that is
|
||||
// // guarded by `mu2_`:
|
||||
// int *q_ ABSL_GUARDED_BY(mu1_) ABSL_PT_GUARDED_BY(mu2_);
|
||||
#define ABSL_PT_GUARDED_BY(x) \
|
||||
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(pt_guarded_by(x))
|
||||
#if ABSL_HAVE_ATTRIBUTE(pt_guarded_by)
|
||||
#define ABSL_PT_GUARDED_BY(x) __attribute__((pt_guarded_by(x)))
|
||||
#else
|
||||
#define ABSL_PT_GUARDED_BY(x)
|
||||
#endif
|
||||
|
||||
// ABSL_ACQUIRED_AFTER() / ABSL_ACQUIRED_BEFORE()
|
||||
//
|
||||
@@ -103,11 +103,17 @@
|
||||
//
|
||||
// Mutex m1_;
|
||||
// Mutex m2_ ABSL_ACQUIRED_AFTER(m1_);
|
||||
#define ABSL_ACQUIRED_AFTER(...) \
|
||||
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(acquired_after(__VA_ARGS__))
|
||||
#if ABSL_HAVE_ATTRIBUTE(acquired_after)
|
||||
#define ABSL_ACQUIRED_AFTER(...) __attribute__((acquired_after(__VA_ARGS__)))
|
||||
#else
|
||||
#define ABSL_ACQUIRED_AFTER(...)
|
||||
#endif
|
||||
|
||||
#define ABSL_ACQUIRED_BEFORE(...) \
|
||||
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(acquired_before(__VA_ARGS__))
|
||||
#if ABSL_HAVE_ATTRIBUTE(acquired_before)
|
||||
#define ABSL_ACQUIRED_BEFORE(...) __attribute__((acquired_before(__VA_ARGS__)))
|
||||
#else
|
||||
#define ABSL_ACQUIRED_BEFORE(...)
|
||||
#endif
|
||||
|
||||
// ABSL_EXCLUSIVE_LOCKS_REQUIRED() / ABSL_SHARED_LOCKS_REQUIRED()
|
||||
//
|
||||
@@ -132,20 +138,30 @@
|
||||
//
|
||||
// void foo() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... }
|
||||
// void bar() const ABSL_SHARED_LOCKS_REQUIRED(mu1, mu2) { ... }
|
||||
#define ABSL_EXCLUSIVE_LOCKS_REQUIRED(...) \
|
||||
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE( \
|
||||
exclusive_locks_required(__VA_ARGS__))
|
||||
#if ABSL_HAVE_ATTRIBUTE(exclusive_locks_required)
|
||||
#define ABSL_EXCLUSIVE_LOCKS_REQUIRED(...) \
|
||||
__attribute__((exclusive_locks_required(__VA_ARGS__)))
|
||||
#else
|
||||
#define ABSL_EXCLUSIVE_LOCKS_REQUIRED(...)
|
||||
#endif
|
||||
|
||||
#if ABSL_HAVE_ATTRIBUTE(shared_locks_required)
|
||||
#define ABSL_SHARED_LOCKS_REQUIRED(...) \
|
||||
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(shared_locks_required(__VA_ARGS__))
|
||||
__attribute__((shared_locks_required(__VA_ARGS__)))
|
||||
#else
|
||||
#define ABSL_SHARED_LOCKS_REQUIRED(...)
|
||||
#endif
|
||||
|
||||
// ABSL_LOCKS_EXCLUDED()
|
||||
//
|
||||
// Documents the locks acquired in the body of the function. These locks
|
||||
// cannot be held when calling this function (as Abseil's `Mutex` locks are
|
||||
// non-reentrant).
|
||||
#define ABSL_LOCKS_EXCLUDED(...) \
|
||||
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(locks_excluded(__VA_ARGS__))
|
||||
#if ABSL_HAVE_ATTRIBUTE(locks_excluded)
|
||||
#define ABSL_LOCKS_EXCLUDED(...) __attribute__((locks_excluded(__VA_ARGS__)))
|
||||
#else
|
||||
#define ABSL_LOCKS_EXCLUDED(...)
|
||||
#endif
|
||||
|
||||
// ABSL_LOCK_RETURNED()
|
||||
//
|
||||
@@ -153,8 +169,7 @@
|
||||
// a public getter method that returns a pointer to a private mutex should
|
||||
// be annotated with ABSL_LOCK_RETURNED.
|
||||
#if ABSL_HAVE_ATTRIBUTE(lock_returned)
|
||||
#define ABSL_LOCK_RETURNED(x) \
|
||||
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(lock_returned(x))
|
||||
#define ABSL_LOCK_RETURNED(x) __attribute__((lock_returned(x)))
|
||||
#else
|
||||
#define ABSL_LOCK_RETURNED(x)
|
||||
#endif
|
||||
@@ -162,7 +177,11 @@
|
||||
// ABSL_LOCKABLE
|
||||
//
|
||||
// Documents if a class/type is a lockable type (such as the `Mutex` class).
|
||||
#define ABSL_LOCKABLE ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(lockable)
|
||||
#if ABSL_HAVE_ATTRIBUTE(lockable)
|
||||
#define ABSL_LOCKABLE __attribute__((lockable))
|
||||
#else
|
||||
#define ABSL_LOCKABLE
|
||||
#endif
|
||||
|
||||
// ABSL_SCOPED_LOCKABLE
|
||||
//
|
||||
@@ -171,30 +190,43 @@
|
||||
// acquired, and the destructor should use `UNLOCK_FUNCTION()` with no
|
||||
// arguments; the analysis will assume that the destructor unlocks whatever the
|
||||
// constructor locked.
|
||||
#define ABSL_SCOPED_LOCKABLE \
|
||||
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(scoped_lockable)
|
||||
#if ABSL_HAVE_ATTRIBUTE(scoped_lockable)
|
||||
#define ABSL_SCOPED_LOCKABLE __attribute__((scoped_lockable))
|
||||
#else
|
||||
#define ABSL_SCOPED_LOCKABLE
|
||||
#endif
|
||||
|
||||
// ABSL_EXCLUSIVE_LOCK_FUNCTION()
|
||||
//
|
||||
// Documents functions that acquire a lock in the body of a function, and do
|
||||
// not release it.
|
||||
#define ABSL_EXCLUSIVE_LOCK_FUNCTION(...) \
|
||||
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE( \
|
||||
exclusive_lock_function(__VA_ARGS__))
|
||||
#if ABSL_HAVE_ATTRIBUTE(exclusive_lock_function)
|
||||
#define ABSL_EXCLUSIVE_LOCK_FUNCTION(...) \
|
||||
__attribute__((exclusive_lock_function(__VA_ARGS__)))
|
||||
#else
|
||||
#define ABSL_EXCLUSIVE_LOCK_FUNCTION(...)
|
||||
#endif
|
||||
|
||||
// ABSL_SHARED_LOCK_FUNCTION()
|
||||
//
|
||||
// Documents functions that acquire a shared (reader) lock in the body of a
|
||||
// function, and do not release it.
|
||||
#if ABSL_HAVE_ATTRIBUTE(shared_lock_function)
|
||||
#define ABSL_SHARED_LOCK_FUNCTION(...) \
|
||||
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(shared_lock_function(__VA_ARGS__))
|
||||
__attribute__((shared_lock_function(__VA_ARGS__)))
|
||||
#else
|
||||
#define ABSL_SHARED_LOCK_FUNCTION(...)
|
||||
#endif
|
||||
|
||||
// ABSL_UNLOCK_FUNCTION()
|
||||
//
|
||||
// Documents functions that expect a lock to be held on entry to the function,
|
||||
// and release it in the body of the function.
|
||||
#define ABSL_UNLOCK_FUNCTION(...) \
|
||||
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(unlock_function(__VA_ARGS__))
|
||||
#if ABSL_HAVE_ATTRIBUTE(unlock_function)
|
||||
#define ABSL_UNLOCK_FUNCTION(...) __attribute__((unlock_function(__VA_ARGS__)))
|
||||
#else
|
||||
#define ABSL_UNLOCK_FUNCTION(...)
|
||||
#endif
|
||||
|
||||
// ABSL_EXCLUSIVE_TRYLOCK_FUNCTION() / ABSL_SHARED_TRYLOCK_FUNCTION()
|
||||
//
|
||||
@@ -204,31 +236,49 @@
|
||||
// success, or `false` for functions that return `false` on success. The second
|
||||
// argument specifies the mutex that is locked on success. If unspecified, this
|
||||
// mutex is assumed to be `this`.
|
||||
#if ABSL_HAVE_ATTRIBUTE(exclusive_trylock_function)
|
||||
#define ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(...) \
|
||||
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE( \
|
||||
exclusive_trylock_function(__VA_ARGS__))
|
||||
__attribute__((exclusive_trylock_function(__VA_ARGS__)))
|
||||
#else
|
||||
#define ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(...)
|
||||
#endif
|
||||
|
||||
#define ABSL_SHARED_TRYLOCK_FUNCTION(...) \
|
||||
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE( \
|
||||
shared_trylock_function(__VA_ARGS__))
|
||||
#if ABSL_HAVE_ATTRIBUTE(shared_trylock_function)
|
||||
#define ABSL_SHARED_TRYLOCK_FUNCTION(...) \
|
||||
__attribute__((shared_trylock_function(__VA_ARGS__)))
|
||||
#else
|
||||
#define ABSL_SHARED_TRYLOCK_FUNCTION(...)
|
||||
#endif
|
||||
|
||||
// ABSL_ASSERT_EXCLUSIVE_LOCK() / ABSL_ASSERT_SHARED_LOCK()
|
||||
//
|
||||
// Documents functions that dynamically check to see if a lock is held, and fail
|
||||
// if it is not held.
|
||||
#if ABSL_HAVE_ATTRIBUTE(assert_exclusive_lock)
|
||||
#define ABSL_ASSERT_EXCLUSIVE_LOCK(...) \
|
||||
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(assert_exclusive_lock(__VA_ARGS__))
|
||||
__attribute__((assert_exclusive_lock(__VA_ARGS__)))
|
||||
#else
|
||||
#define ABSL_ASSERT_EXCLUSIVE_LOCK(...)
|
||||
#endif
|
||||
|
||||
#if ABSL_HAVE_ATTRIBUTE(assert_shared_lock)
|
||||
#define ABSL_ASSERT_SHARED_LOCK(...) \
|
||||
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(assert_shared_lock(__VA_ARGS__))
|
||||
__attribute__((assert_shared_lock(__VA_ARGS__)))
|
||||
#else
|
||||
#define ABSL_ASSERT_SHARED_LOCK(...)
|
||||
#endif
|
||||
|
||||
// ABSL_NO_THREAD_SAFETY_ANALYSIS
|
||||
//
|
||||
// Turns off thread safety checking within the body of a particular function.
|
||||
// This annotation is used to mark functions that are known to be correct, but
|
||||
// the locking behavior is more complicated than the analyzer can handle.
|
||||
#if ABSL_HAVE_ATTRIBUTE(no_thread_safety_analysis)
|
||||
#define ABSL_NO_THREAD_SAFETY_ANALYSIS \
|
||||
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(no_thread_safety_analysis)
|
||||
__attribute__((no_thread_safety_analysis))
|
||||
#else
|
||||
#define ABSL_NO_THREAD_SAFETY_ANALYSIS
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Tool-Supplied Annotations
|
||||
|
||||
@@ -150,8 +150,7 @@ TEST(FixedArrayExceptionSafety, InitListConstructorWithAlloc) {
|
||||
|
||||
template <typename FixedArrT>
|
||||
testing::AssertionResult ReadMemory(FixedArrT* fixed_arr) {
|
||||
// Marked volatile to prevent optimization. Used for running asan tests.
|
||||
volatile int sum = 0;
|
||||
int sum = 0;
|
||||
for (const auto& thrower : *fixed_arr) {
|
||||
sum += thrower.Get();
|
||||
}
|
||||
|
||||
@@ -1155,7 +1155,8 @@ TEST_F(FormatConvertTest, IntAsDouble) {
|
||||
{__LINE__, StrPrint("%.12a", dx), "%.12a"},
|
||||
};
|
||||
if (native_traits.hex_float_uses_minimal_precision_when_not_specified) {
|
||||
expect.push_back({__LINE__, StrPrint("%12a", dx), "%12a"});
|
||||
Expectation ex = {__LINE__, StrPrint("%12a", dx), "%12a"};
|
||||
expect.push_back(ex);
|
||||
}
|
||||
for (const Expectation &e : expect) {
|
||||
SCOPED_TRACE(e.line);
|
||||
|
||||
@@ -59,6 +59,7 @@
|
||||
|
||||
using absl::base_internal::CurrentThreadIdentityIfPresent;
|
||||
using absl::base_internal::PerThreadSynch;
|
||||
using absl::base_internal::SchedulingGuard;
|
||||
using absl::base_internal::ThreadIdentity;
|
||||
using absl::synchronization_internal::GetOrCreateCurrentThreadIdentity;
|
||||
using absl::synchronization_internal::GraphCycles;
|
||||
@@ -141,7 +142,9 @@ static const MutexGlobals& GetMutexGlobals() {
|
||||
namespace {
|
||||
enum DelayMode { AGGRESSIVE, GENTLE };
|
||||
};
|
||||
static int Delay(int32_t c, DelayMode mode) {
|
||||
|
||||
namespace synchronization_internal {
|
||||
int MutexDelay(int32_t c, int mode) {
|
||||
// If this a uniprocessor, only yield/sleep. Otherwise, if the mode is
|
||||
// aggressive then spin many times before yielding. If the mode is
|
||||
// gentle then spin only a few times before yielding. Aggressive spinning is
|
||||
@@ -153,6 +156,7 @@ static int Delay(int32_t c, DelayMode mode) {
|
||||
// Spin.
|
||||
c++;
|
||||
} else {
|
||||
SchedulingGuard::ScopedEnable enable_rescheduling;
|
||||
ABSL_TSAN_MUTEX_PRE_DIVERT(nullptr, 0);
|
||||
if (c == limit) {
|
||||
// Yield once.
|
||||
@@ -167,6 +171,7 @@ static int Delay(int32_t c, DelayMode mode) {
|
||||
}
|
||||
return c;
|
||||
}
|
||||
} // namespace synchronization_internal
|
||||
|
||||
// --------------------------Generic atomic ops
|
||||
// Ensure that "(*pv & bits) == bits" by doing an atomic update of "*pv" to
|
||||
@@ -1051,6 +1056,7 @@ static PerThreadSynch *DequeueAllWakeable(PerThreadSynch *head,
|
||||
// Try to remove thread s from the list of waiters on this mutex.
|
||||
// Does nothing if s is not on the waiter list.
|
||||
void Mutex::TryRemove(PerThreadSynch *s) {
|
||||
SchedulingGuard::ScopedDisable disable_rescheduling;
|
||||
intptr_t v = mu_.load(std::memory_order_relaxed);
|
||||
// acquire spinlock & lock
|
||||
if ((v & (kMuWait | kMuSpin | kMuWriter | kMuReader)) == kMuWait &&
|
||||
@@ -1115,7 +1121,7 @@ ABSL_XRAY_LOG_ARGS(1) void Mutex::Block(PerThreadSynch *s) {
|
||||
this->TryRemove(s);
|
||||
int c = 0;
|
||||
while (s->next != nullptr) {
|
||||
c = Delay(c, GENTLE);
|
||||
c = synchronization_internal::MutexDelay(c, GENTLE);
|
||||
this->TryRemove(s);
|
||||
}
|
||||
if (kDebugMode) {
|
||||
@@ -1894,6 +1900,7 @@ static void CheckForMutexCorruption(intptr_t v, const char* label) {
|
||||
}
|
||||
|
||||
void Mutex::LockSlowLoop(SynchWaitParams *waitp, int flags) {
|
||||
SchedulingGuard::ScopedDisable disable_rescheduling;
|
||||
int c = 0;
|
||||
intptr_t v = mu_.load(std::memory_order_relaxed);
|
||||
if ((v & kMuEvent) != 0) {
|
||||
@@ -1995,7 +2002,8 @@ void Mutex::LockSlowLoop(SynchWaitParams *waitp, int flags) {
|
||||
ABSL_RAW_CHECK(
|
||||
waitp->thread->waitp == nullptr || waitp->thread->suppress_fatal_errors,
|
||||
"detected illegal recursion into Mutex code");
|
||||
c = Delay(c, GENTLE); // delay, then try again
|
||||
// delay, then try again
|
||||
c = synchronization_internal::MutexDelay(c, GENTLE);
|
||||
}
|
||||
ABSL_RAW_CHECK(
|
||||
waitp->thread->waitp == nullptr || waitp->thread->suppress_fatal_errors,
|
||||
@@ -2013,6 +2021,7 @@ void Mutex::LockSlowLoop(SynchWaitParams *waitp, int flags) {
|
||||
// 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.
|
||||
ABSL_ATTRIBUTE_NOINLINE void Mutex::UnlockSlow(SynchWaitParams *waitp) {
|
||||
SchedulingGuard::ScopedDisable disable_rescheduling;
|
||||
intptr_t v = mu_.load(std::memory_order_relaxed);
|
||||
this->AssertReaderHeld();
|
||||
CheckForMutexCorruption(v, "Unlock");
|
||||
@@ -2289,7 +2298,8 @@ ABSL_ATTRIBUTE_NOINLINE void Mutex::UnlockSlow(SynchWaitParams *waitp) {
|
||||
mu_.store(nv, std::memory_order_release);
|
||||
break; // out of for(;;)-loop
|
||||
}
|
||||
c = Delay(c, AGGRESSIVE); // aggressive here; no one can proceed till we do
|
||||
// aggressive here; no one can proceed till we do
|
||||
c = synchronization_internal::MutexDelay(c, AGGRESSIVE);
|
||||
} // end of for(;;)-loop
|
||||
|
||||
if (wake_list != kPerThreadSynchNull) {
|
||||
@@ -2328,6 +2338,7 @@ void Mutex::Trans(MuHow how) {
|
||||
// It will later acquire the mutex with high probability. Otherwise, we
|
||||
// enqueue thread w on this mutex.
|
||||
void Mutex::Fer(PerThreadSynch *w) {
|
||||
SchedulingGuard::ScopedDisable disable_rescheduling;
|
||||
int c = 0;
|
||||
ABSL_RAW_CHECK(w->waitp->cond == nullptr,
|
||||
"Mutex::Fer while waiting on Condition");
|
||||
@@ -2377,7 +2388,7 @@ void Mutex::Fer(PerThreadSynch *w) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
c = Delay(c, GENTLE);
|
||||
c = synchronization_internal::MutexDelay(c, GENTLE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2426,6 +2437,7 @@ CondVar::~CondVar() {
|
||||
|
||||
// Remove thread s from the list of waiters on this condition variable.
|
||||
void CondVar::Remove(PerThreadSynch *s) {
|
||||
SchedulingGuard::ScopedDisable disable_rescheduling;
|
||||
intptr_t v;
|
||||
int c = 0;
|
||||
for (v = cv_.load(std::memory_order_relaxed);;
|
||||
@@ -2454,7 +2466,8 @@ void CondVar::Remove(PerThreadSynch *s) {
|
||||
std::memory_order_release);
|
||||
return;
|
||||
} else {
|
||||
c = Delay(c, GENTLE); // try again after a delay
|
||||
// try again after a delay
|
||||
c = synchronization_internal::MutexDelay(c, GENTLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2487,7 +2500,7 @@ static void CondVarEnqueue(SynchWaitParams *waitp) {
|
||||
!cv_word->compare_exchange_weak(v, v | kCvSpin,
|
||||
std::memory_order_acquire,
|
||||
std::memory_order_relaxed)) {
|
||||
c = Delay(c, GENTLE);
|
||||
c = synchronization_internal::MutexDelay(c, GENTLE);
|
||||
v = cv_word->load(std::memory_order_relaxed);
|
||||
}
|
||||
ABSL_RAW_CHECK(waitp->thread->waitp == nullptr, "waiting when shouldn't be");
|
||||
@@ -2586,6 +2599,7 @@ void CondVar::Wakeup(PerThreadSynch *w) {
|
||||
}
|
||||
|
||||
void CondVar::Signal() {
|
||||
SchedulingGuard::ScopedDisable disable_rescheduling;
|
||||
ABSL_TSAN_MUTEX_PRE_SIGNAL(nullptr, 0);
|
||||
intptr_t v;
|
||||
int c = 0;
|
||||
@@ -2618,7 +2632,7 @@ void CondVar::Signal() {
|
||||
ABSL_TSAN_MUTEX_POST_SIGNAL(nullptr, 0);
|
||||
return;
|
||||
} else {
|
||||
c = Delay(c, GENTLE);
|
||||
c = synchronization_internal::MutexDelay(c, GENTLE);
|
||||
}
|
||||
}
|
||||
ABSL_TSAN_MUTEX_POST_SIGNAL(nullptr, 0);
|
||||
@@ -2655,7 +2669,8 @@ void CondVar::SignalAll () {
|
||||
ABSL_TSAN_MUTEX_POST_SIGNAL(nullptr, 0);
|
||||
return;
|
||||
} else {
|
||||
c = Delay(c, GENTLE); // try again after a delay
|
||||
// try again after a delay
|
||||
c = synchronization_internal::MutexDelay(c, GENTLE);
|
||||
}
|
||||
}
|
||||
ABSL_TSAN_MUTEX_POST_SIGNAL(nullptr, 0);
|
||||
|
||||
@@ -40,7 +40,6 @@
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
@@ -83,6 +82,27 @@ const std::int_least32_t kSecsPerYear[2] = {
|
||||
366 * kSecsPerDay,
|
||||
};
|
||||
|
||||
// Convert a cctz::weekday to a POSIX TZ weekday number (0==Sun, ..., 6=Sat).
|
||||
inline int ToPosixWeekday(weekday wd) {
|
||||
switch (wd) {
|
||||
case weekday::sunday:
|
||||
return 0;
|
||||
case weekday::monday:
|
||||
return 1;
|
||||
case weekday::tuesday:
|
||||
return 2;
|
||||
case weekday::wednesday:
|
||||
return 3;
|
||||
case weekday::thursday:
|
||||
return 4;
|
||||
case weekday::friday:
|
||||
return 5;
|
||||
case weekday::saturday:
|
||||
return 6;
|
||||
}
|
||||
return 0; /*NOTREACHED*/
|
||||
}
|
||||
|
||||
// Single-byte, unsigned numeric values are encoded directly.
|
||||
inline std::uint_fast8_t Decode8(const char* cp) {
|
||||
return static_cast<std::uint_fast8_t>(*cp) & 0xff;
|
||||
@@ -188,15 +208,13 @@ bool TimeZoneInfo::ResetToBuiltinUTC(const seconds& offset) {
|
||||
tt.is_dst = false;
|
||||
tt.abbr_index = 0;
|
||||
|
||||
// We temporarily add some redundant, contemporary (2013 through 2023)
|
||||
// We temporarily add some redundant, contemporary (2015 through 2025)
|
||||
// transitions for performance reasons. See TimeZoneInfo::LocalTime().
|
||||
// TODO: Fix the performance issue and remove the extra transitions.
|
||||
transitions_.clear();
|
||||
transitions_.reserve(12);
|
||||
for (const std::int_fast64_t unix_time : {
|
||||
-(1LL << 59), // BIG_BANG
|
||||
1356998400LL, // 2013-01-01T00:00:00+00:00
|
||||
1388534400LL, // 2014-01-01T00:00:00+00:00
|
||||
-(1LL << 59), // a "first half" transition
|
||||
1420070400LL, // 2015-01-01T00:00:00+00:00
|
||||
1451606400LL, // 2016-01-01T00:00:00+00:00
|
||||
1483228800LL, // 2017-01-01T00:00:00+00:00
|
||||
@@ -206,7 +224,8 @@ bool TimeZoneInfo::ResetToBuiltinUTC(const seconds& offset) {
|
||||
1609459200LL, // 2021-01-01T00:00:00+00:00
|
||||
1640995200LL, // 2022-01-01T00:00:00+00:00
|
||||
1672531200LL, // 2023-01-01T00:00:00+00:00
|
||||
2147483647LL, // 2^31 - 1
|
||||
1704067200LL, // 2024-01-01T00:00:00+00:00
|
||||
1735689600LL, // 2025-01-01T00:00:00+00:00
|
||||
}) {
|
||||
Transition& tr(*transitions_.emplace(transitions_.end()));
|
||||
tr.unix_time = unix_time;
|
||||
@@ -217,8 +236,8 @@ bool TimeZoneInfo::ResetToBuiltinUTC(const seconds& offset) {
|
||||
|
||||
default_transition_type_ = 0;
|
||||
abbreviations_ = FixedOffsetToAbbr(offset);
|
||||
abbreviations_.append(1, '\0'); // add NUL
|
||||
future_spec_.clear(); // never needed for a fixed-offset zone
|
||||
abbreviations_.append(1, '\0');
|
||||
future_spec_.clear(); // never needed for a fixed-offset zone
|
||||
extended_ = false;
|
||||
|
||||
tt.civil_max = LocalTime(seconds::max().count(), tt).cs;
|
||||
@@ -259,21 +278,6 @@ std::size_t TimeZoneInfo::Header::DataLength(std::size_t time_len) const {
|
||||
return len;
|
||||
}
|
||||
|
||||
// Check that the TransitionType has the expected offset/is_dst/abbreviation.
|
||||
void TimeZoneInfo::CheckTransition(const std::string& name,
|
||||
const TransitionType& tt,
|
||||
std::int_fast32_t offset, bool is_dst,
|
||||
const std::string& abbr) const {
|
||||
if (tt.utc_offset != offset || tt.is_dst != is_dst ||
|
||||
&abbreviations_[tt.abbr_index] != abbr) {
|
||||
std::clog << name << ": Transition"
|
||||
<< " offset=" << tt.utc_offset << "/"
|
||||
<< (tt.is_dst ? "DST" : "STD")
|
||||
<< "/abbr=" << &abbreviations_[tt.abbr_index]
|
||||
<< " does not match POSIX spec '" << future_spec_ << "'\n";
|
||||
}
|
||||
}
|
||||
|
||||
// zic(8) can generate no-op transitions when a zone changes rules at an
|
||||
// instant when there is actually no discontinuity. So we check whether
|
||||
// two transitions have equivalent types (same offset/is_dst/abbr).
|
||||
@@ -282,117 +286,108 @@ bool TimeZoneInfo::EquivTransitions(std::uint_fast8_t tt1_index,
|
||||
if (tt1_index == tt2_index) return true;
|
||||
const TransitionType& tt1(transition_types_[tt1_index]);
|
||||
const TransitionType& tt2(transition_types_[tt2_index]);
|
||||
if (tt1.is_dst != tt2.is_dst) return false;
|
||||
if (tt1.utc_offset != tt2.utc_offset) return false;
|
||||
if (tt1.is_dst != tt2.is_dst) return false;
|
||||
if (tt1.abbr_index != tt2.abbr_index) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Find/make a transition type with these attributes.
|
||||
bool TimeZoneInfo::GetTransitionType(std::int_fast32_t utc_offset, bool is_dst,
|
||||
const std::string& abbr,
|
||||
std::uint_fast8_t* index) {
|
||||
std::size_t type_index = 0;
|
||||
std::size_t abbr_index = abbreviations_.size();
|
||||
for (; type_index != transition_types_.size(); ++type_index) {
|
||||
const TransitionType& tt(transition_types_[type_index]);
|
||||
const char* tt_abbr = &abbreviations_[tt.abbr_index];
|
||||
if (tt_abbr == abbr) abbr_index = tt.abbr_index;
|
||||
if (tt.utc_offset == utc_offset && tt.is_dst == is_dst) {
|
||||
if (abbr_index == tt.abbr_index) break; // reuse
|
||||
}
|
||||
}
|
||||
if (type_index > 255 || abbr_index > 255) {
|
||||
// No index space (8 bits) available for a new type or abbreviation.
|
||||
return false;
|
||||
}
|
||||
if (type_index == transition_types_.size()) {
|
||||
TransitionType& tt(*transition_types_.emplace(transition_types_.end()));
|
||||
tt.utc_offset = static_cast<std::int_least32_t>(utc_offset);
|
||||
tt.is_dst = is_dst;
|
||||
if (abbr_index == abbreviations_.size()) {
|
||||
abbreviations_.append(abbr);
|
||||
abbreviations_.append(1, '\0');
|
||||
}
|
||||
tt.abbr_index = static_cast<std::uint_least8_t>(abbr_index);
|
||||
}
|
||||
*index = static_cast<std::uint_least8_t>(type_index);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Use the POSIX-TZ-environment-variable-style string to handle times
|
||||
// in years after the last transition stored in the zoneinfo data.
|
||||
void TimeZoneInfo::ExtendTransitions(const std::string& name,
|
||||
const Header& hdr) {
|
||||
bool TimeZoneInfo::ExtendTransitions() {
|
||||
extended_ = false;
|
||||
bool extending = !future_spec_.empty();
|
||||
if (future_spec_.empty()) return true; // last transition prevails
|
||||
|
||||
PosixTimeZone posix;
|
||||
if (extending && !ParsePosixSpec(future_spec_, &posix)) {
|
||||
std::clog << name << ": Failed to parse '" << future_spec_ << "'\n";
|
||||
extending = false;
|
||||
if (!ParsePosixSpec(future_spec_, &posix)) return false;
|
||||
|
||||
// Find transition type for the future std specification.
|
||||
std::uint_fast8_t std_ti;
|
||||
if (!GetTransitionType(posix.std_offset, false, posix.std_abbr, &std_ti))
|
||||
return false;
|
||||
|
||||
if (posix.dst_abbr.empty()) { // std only
|
||||
// The future specification should match the last transition, and
|
||||
// that means that handling the future will fall out naturally.
|
||||
return EquivTransitions(transitions_.back().type_index, std_ti);
|
||||
}
|
||||
|
||||
if (extending && posix.dst_abbr.empty()) { // std only
|
||||
// The future specification should match the last/default transition,
|
||||
// and that means that handling the future will fall out naturally.
|
||||
std::uint_fast8_t index = default_transition_type_;
|
||||
if (hdr.timecnt != 0) index = transitions_[hdr.timecnt - 1].type_index;
|
||||
const TransitionType& tt(transition_types_[index]);
|
||||
CheckTransition(name, tt, posix.std_offset, false, posix.std_abbr);
|
||||
extending = false;
|
||||
}
|
||||
|
||||
if (extending && hdr.timecnt < 2) {
|
||||
std::clog << name << ": Too few transitions for POSIX spec\n";
|
||||
extending = false;
|
||||
}
|
||||
|
||||
if (!extending) {
|
||||
// Ensure that there is always a transition in the second half of the
|
||||
// time line (the BIG_BANG transition is in the first half) so that the
|
||||
// signed difference between a civil_second and the civil_second of its
|
||||
// previous transition is always representable, without overflow.
|
||||
const Transition& last(transitions_.back());
|
||||
if (last.unix_time < 0) {
|
||||
const std::uint_fast8_t type_index = last.type_index;
|
||||
Transition& tr(*transitions_.emplace(transitions_.end()));
|
||||
tr.unix_time = 2147483647; // 2038-01-19T03:14:07+00:00
|
||||
tr.type_index = type_index;
|
||||
}
|
||||
return; // last transition wins
|
||||
}
|
||||
// Find transition type for the future dst specification.
|
||||
std::uint_fast8_t dst_ti;
|
||||
if (!GetTransitionType(posix.dst_offset, true, posix.dst_abbr, &dst_ti))
|
||||
return false;
|
||||
|
||||
// Extend the transitions for an additional 400 years using the
|
||||
// future specification. Years beyond those can be handled by
|
||||
// mapping back to a cycle-equivalent year within that range.
|
||||
// zic(8) should probably do this so that we don't have to.
|
||||
// TODO: Reduce the extension by the number of compatible
|
||||
// transitions already in place.
|
||||
transitions_.reserve(hdr.timecnt + 400 * 2 + 1);
|
||||
transitions_.resize(hdr.timecnt + 400 * 2);
|
||||
// We may need two additional transitions for the current year.
|
||||
transitions_.reserve(transitions_.size() + 400 * 2 + 2);
|
||||
extended_ = true;
|
||||
|
||||
// The future specification should match the last two transitions,
|
||||
// and those transitions should have different is_dst flags. Note
|
||||
// that nothing says the UTC offset used by the is_dst transition
|
||||
// must be greater than that used by the !is_dst transition. (See
|
||||
// Europe/Dublin, for example.)
|
||||
const Transition* tr0 = &transitions_[hdr.timecnt - 1];
|
||||
const Transition* tr1 = &transitions_[hdr.timecnt - 2];
|
||||
const TransitionType* tt0 = &transition_types_[tr0->type_index];
|
||||
const TransitionType* tt1 = &transition_types_[tr1->type_index];
|
||||
const TransitionType& dst(tt0->is_dst ? *tt0 : *tt1);
|
||||
const TransitionType& std(tt0->is_dst ? *tt1 : *tt0);
|
||||
CheckTransition(name, dst, posix.dst_offset, true, posix.dst_abbr);
|
||||
CheckTransition(name, std, posix.std_offset, false, posix.std_abbr);
|
||||
|
||||
// Add the transitions to tr1 and back to tr0 for each extra year.
|
||||
last_year_ = LocalTime(tr0->unix_time, *tt0).cs.year();
|
||||
const Transition& last(transitions_.back());
|
||||
const std::int_fast64_t last_time = last.unix_time;
|
||||
const TransitionType& last_tt(transition_types_[last.type_index]);
|
||||
last_year_ = LocalTime(last_time, last_tt).cs.year();
|
||||
bool leap_year = IsLeap(last_year_);
|
||||
const civil_day jan1(last_year_, 1, 1);
|
||||
std::int_fast64_t jan1_time = civil_second(jan1) - civil_second();
|
||||
int jan1_weekday = (static_cast<int>(get_weekday(jan1)) + 1) % 7;
|
||||
Transition* tr = &transitions_[hdr.timecnt]; // next trans to fill
|
||||
if (LocalTime(tr1->unix_time, *tt1).cs.year() != last_year_) {
|
||||
// Add a single extra transition to align to a calendar year.
|
||||
transitions_.resize(transitions_.size() + 1);
|
||||
assert(tr == &transitions_[hdr.timecnt]); // no reallocation
|
||||
const PosixTransition& pt1(tt0->is_dst ? posix.dst_end : posix.dst_start);
|
||||
std::int_fast64_t tr1_offset = TransOffset(leap_year, jan1_weekday, pt1);
|
||||
tr->unix_time = jan1_time + tr1_offset - tt0->utc_offset;
|
||||
tr++->type_index = tr1->type_index;
|
||||
tr0 = &transitions_[hdr.timecnt];
|
||||
tr1 = &transitions_[hdr.timecnt - 1];
|
||||
tt0 = &transition_types_[tr0->type_index];
|
||||
tt1 = &transition_types_[tr1->type_index];
|
||||
}
|
||||
const PosixTransition& pt1(tt0->is_dst ? posix.dst_end : posix.dst_start);
|
||||
const PosixTransition& pt0(tt0->is_dst ? posix.dst_start : posix.dst_end);
|
||||
for (const year_t limit = last_year_ + 400; last_year_ < limit;) {
|
||||
last_year_ += 1; // an additional year of generated transitions
|
||||
const civil_second jan1(last_year_);
|
||||
std::int_fast64_t jan1_time = jan1 - civil_second();
|
||||
int jan1_weekday = ToPosixWeekday(get_weekday(jan1));
|
||||
|
||||
Transition dst = {0, dst_ti, civil_second(), civil_second()};
|
||||
Transition std = {0, std_ti, civil_second(), civil_second()};
|
||||
for (const year_t limit = last_year_ + 400;; ++last_year_) {
|
||||
auto dst_trans_off = TransOffset(leap_year, jan1_weekday, posix.dst_start);
|
||||
auto std_trans_off = TransOffset(leap_year, jan1_weekday, posix.dst_end);
|
||||
dst.unix_time = jan1_time + dst_trans_off - posix.std_offset;
|
||||
std.unix_time = jan1_time + std_trans_off - posix.dst_offset;
|
||||
const auto* ta = dst.unix_time < std.unix_time ? &dst : &std;
|
||||
const auto* tb = dst.unix_time < std.unix_time ? &std : &dst;
|
||||
if (last_time < tb->unix_time) {
|
||||
if (last_time < ta->unix_time) transitions_.push_back(*ta);
|
||||
transitions_.push_back(*tb);
|
||||
}
|
||||
if (last_year_ == limit) break;
|
||||
jan1_time += kSecsPerYear[leap_year];
|
||||
jan1_weekday = (jan1_weekday + kDaysPerYear[leap_year]) % 7;
|
||||
leap_year = !leap_year && IsLeap(last_year_);
|
||||
std::int_fast64_t tr1_offset = TransOffset(leap_year, jan1_weekday, pt1);
|
||||
tr->unix_time = jan1_time + tr1_offset - tt0->utc_offset;
|
||||
tr++->type_index = tr1->type_index;
|
||||
std::int_fast64_t tr0_offset = TransOffset(leap_year, jan1_weekday, pt0);
|
||||
tr->unix_time = jan1_time + tr0_offset - tt1->utc_offset;
|
||||
tr++->type_index = tr0->type_index;
|
||||
leap_year = !leap_year && IsLeap(last_year_ + 1);
|
||||
}
|
||||
assert(tr == &transitions_[0] + transitions_.size());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TimeZoneInfo::Load(const std::string& name, ZoneInfoSource* zip) {
|
||||
bool TimeZoneInfo::Load(ZoneInfoSource* zip) {
|
||||
// Read and validate the header.
|
||||
tzhead tzh;
|
||||
if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh)) return false;
|
||||
@@ -430,7 +425,7 @@ bool TimeZoneInfo::Load(const std::string& name, ZoneInfoSource* zip) {
|
||||
const char* bp = tbuf.data();
|
||||
|
||||
// Decode and validate the transitions.
|
||||
transitions_.reserve(hdr.timecnt + 2); // We might add a couple.
|
||||
transitions_.reserve(hdr.timecnt + 2);
|
||||
transitions_.resize(hdr.timecnt);
|
||||
for (std::size_t i = 0; i != hdr.timecnt; ++i) {
|
||||
transitions_[i].unix_time = (time_len == 4) ? Decode32(bp) : Decode64(bp);
|
||||
@@ -449,6 +444,7 @@ bool TimeZoneInfo::Load(const std::string& name, ZoneInfoSource* zip) {
|
||||
}
|
||||
|
||||
// Decode and validate the transition types.
|
||||
transition_types_.reserve(hdr.typecnt + 2);
|
||||
transition_types_.resize(hdr.typecnt);
|
||||
for (std::size_t i = 0; i != hdr.typecnt; ++i) {
|
||||
transition_types_[i].utc_offset =
|
||||
@@ -475,6 +471,7 @@ bool TimeZoneInfo::Load(const std::string& name, ZoneInfoSource* zip) {
|
||||
}
|
||||
|
||||
// Copy all the abbreviations.
|
||||
abbreviations_.reserve(hdr.charcnt + 10);
|
||||
abbreviations_.assign(bp, hdr.charcnt);
|
||||
bp += hdr.charcnt;
|
||||
|
||||
@@ -525,19 +522,29 @@ bool TimeZoneInfo::Load(const std::string& name, ZoneInfoSource* zip) {
|
||||
transitions_.resize(hdr.timecnt);
|
||||
|
||||
// Ensure that there is always a transition in the first half of the
|
||||
// time line (the second half is handled in ExtendTransitions()) so that
|
||||
// the signed difference between a civil_second and the civil_second of
|
||||
// its previous transition is always representable, without overflow.
|
||||
// A contemporary zic will usually have already done this for us.
|
||||
// time line (the second half is handled below) so that the signed
|
||||
// difference between a civil_second and the civil_second of its
|
||||
// previous transition is always representable, without overflow.
|
||||
if (transitions_.empty() || transitions_.front().unix_time >= 0) {
|
||||
Transition& tr(*transitions_.emplace(transitions_.begin()));
|
||||
tr.unix_time = -(1LL << 59); // see tz/zic.c "BIG_BANG"
|
||||
tr.unix_time = -(1LL << 59); // -18267312070-10-26T17:01:52+00:00
|
||||
tr.type_index = default_transition_type_;
|
||||
hdr.timecnt += 1;
|
||||
}
|
||||
|
||||
// Extend the transitions using the future specification.
|
||||
ExtendTransitions(name, hdr);
|
||||
if (!ExtendTransitions()) return false;
|
||||
|
||||
// Ensure that there is always a transition in the second half of the
|
||||
// time line (the first half is handled above) so that the signed
|
||||
// difference between a civil_second and the civil_second of its
|
||||
// previous transition is always representable, without overflow.
|
||||
const Transition& last(transitions_.back());
|
||||
if (last.unix_time < 0) {
|
||||
const std::uint_fast8_t type_index = last.type_index;
|
||||
Transition& tr(*transitions_.emplace(transitions_.end()));
|
||||
tr.unix_time = 2147483647; // 2038-01-19T03:14:07+00:00
|
||||
tr.type_index = type_index;
|
||||
}
|
||||
|
||||
// Compute the local civil time for each transition and the preceding
|
||||
// second. These will be used for reverse conversions in MakeTime().
|
||||
@@ -723,7 +730,7 @@ bool TimeZoneInfo::Load(const std::string& name) {
|
||||
if (auto zip = AndroidZoneInfoSource::Open(name)) return zip;
|
||||
return nullptr;
|
||||
});
|
||||
return zip != nullptr && Load(name, zip.get());
|
||||
return zip != nullptr && Load(zip.get());
|
||||
}
|
||||
|
||||
// BreakTime() translation for a particular transition type.
|
||||
@@ -897,8 +904,8 @@ bool TimeZoneInfo::NextTransition(const time_point<seconds>& tp,
|
||||
const Transition* begin = &transitions_[0];
|
||||
const Transition* end = begin + transitions_.size();
|
||||
if (begin->unix_time <= -(1LL << 59)) {
|
||||
// Do not report the BIG_BANG found in recent zoneinfo data as it is
|
||||
// really a sentinel, not a transition. See tz/zic.c.
|
||||
// Do not report the BIG_BANG found in some zoneinfo data as it is
|
||||
// really a sentinel, not a transition. See pre-2018f tz/zic.c.
|
||||
++begin;
|
||||
}
|
||||
std::int_fast64_t unix_time = ToUnixSeconds(tp);
|
||||
@@ -923,8 +930,8 @@ bool TimeZoneInfo::PrevTransition(const time_point<seconds>& tp,
|
||||
const Transition* begin = &transitions_[0];
|
||||
const Transition* end = begin + transitions_.size();
|
||||
if (begin->unix_time <= -(1LL << 59)) {
|
||||
// Do not report the BIG_BANG found in recent zoneinfo data as it is
|
||||
// really a sentinel, not a transition. See tz/zic.c.
|
||||
// Do not report the BIG_BANG found in some zoneinfo data as it is
|
||||
// really a sentinel, not a transition. See pre-2018f tz/zic.c.
|
||||
++begin;
|
||||
}
|
||||
std::int_fast64_t unix_time = ToUnixSeconds(tp);
|
||||
|
||||
@@ -95,15 +95,14 @@ class TimeZoneInfo : public TimeZoneIf {
|
||||
std::size_t DataLength(std::size_t time_len) const;
|
||||
};
|
||||
|
||||
void CheckTransition(const std::string& name, const TransitionType& tt,
|
||||
std::int_fast32_t offset, bool is_dst,
|
||||
const std::string& abbr) const;
|
||||
bool GetTransitionType(std::int_fast32_t utc_offset, bool is_dst,
|
||||
const std::string& abbr, std::uint_fast8_t* index);
|
||||
bool EquivTransitions(std::uint_fast8_t tt1_index,
|
||||
std::uint_fast8_t tt2_index) const;
|
||||
void ExtendTransitions(const std::string& name, const Header& hdr);
|
||||
bool ExtendTransitions();
|
||||
|
||||
bool ResetToBuiltinUTC(const seconds& offset);
|
||||
bool Load(const std::string& name, ZoneInfoSource* zip);
|
||||
bool Load(ZoneInfoSource* zip);
|
||||
|
||||
// Helpers for BreakTime() and MakeTime().
|
||||
time_zone::absolute_lookup LocalTime(std::int_fast64_t unix_time,
|
||||
|
||||
@@ -71,15 +71,16 @@ for std in ${STD}; do
|
||||
-e CC="/opt/llvm/clang/bin/clang" \
|
||||
-e BAZEL_COMPILER="llvm" \
|
||||
-e BAZEL_CXXOPTS="-std=${std}" \
|
||||
-e CPLUS_INCLUDE_PATH="/usr/include/c++/8" \
|
||||
${DOCKER_EXTRA_ARGS:-} \
|
||||
${DOCKER_CONTAINER} \
|
||||
/usr/local/bin/bazel test ... \
|
||||
--compilation_mode="${compilation_mode}" \
|
||||
--copt="--gcc-toolchain=/usr/local" \
|
||||
--copt="${exceptions_mode}" \
|
||||
--copt=-Werror \
|
||||
--define="absl=1" \
|
||||
--keep_going \
|
||||
--linkopt="--gcc-toolchain=/usr/local" \
|
||||
--show_timestamps \
|
||||
--test_env="GTEST_INSTALL_FAILURE_SIGNAL_HANDLER=1" \
|
||||
--test_env="TZDIR=/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo" \
|
||||
|
||||
@@ -16,6 +16,6 @@
|
||||
# Test scripts should source this file to get the identifiers.
|
||||
|
||||
readonly LINUX_ALPINE_CONTAINER="gcr.io/google.com/absl-177019/alpine:20191016"
|
||||
readonly LINUX_CLANG_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_clang-latest:20200706"
|
||||
readonly LINUX_GCC_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-latest:20200319"
|
||||
readonly LINUX_CLANG_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20200710"
|
||||
readonly LINUX_GCC_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20200710"
|
||||
readonly LINUX_GCC_49_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-4.9:20191018"
|
||||
|
||||
Reference in New Issue
Block a user