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
pull/741/head
Abseil Team 4 years ago committed by vslashg
parent 302b250e1d
commit 55c04eb920
  1. 6
      WORKSPACE
  2. 5
      absl/BUILD.bazel
  3. 28
      absl/base/internal/low_level_scheduling.h
  4. 128
      absl/base/thread_annotations.h
  5. 3
      absl/container/fixed_array_exception_safety_test.cc
  6. 3
      absl/strings/internal/str_format/convert_test.cc
  7. 33
      absl/synchronization/mutex.cc
  8. 257
      absl/time/internal/cctz/src/time_zone_info.cc
  9. 9
      absl/time/internal/cctz/src/time_zone_info.h
  10. 3
      ci/linux_clang-latest_libstdcxx_bazel.sh
  11. 4
      ci/linux_docker_containers.sh

@ -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 (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
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);
}
// 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;
}
assert(tr == &transitions_[0] + transitions_.size());
leap_year = !leap_year && IsLeap(last_year_ + 1);
}
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"

Loading…
Cancel
Save