You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@marmotta.apache.org by ja...@apache.org on 2018/06/18 18:35:43 UTC
[24/62] [abbrv] [partial] marmotta git commit: * Replace gtest with
upstream version,
including LICENSE header. * Include absl library for faster and safer string
operations. * Update license headers where needed. * Removed custom code
replaced by absl.
http://git-wip-us.apache.org/repos/asf/marmotta/blob/0eb556da/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/internal/kernel_timeout.h
----------------------------------------------------------------------
diff --git a/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/internal/kernel_timeout.h b/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/internal/kernel_timeout.h
new file mode 100644
index 0000000..0d132d9
--- /dev/null
+++ b/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/internal/kernel_timeout.h
@@ -0,0 +1,149 @@
+// Copyright 2017 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
+//
+// http://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.
+//
+
+// An optional absolute timeout, with nanosecond granularity,
+// compatible with absl::Time. Suitable for in-register
+// parameter-passing (e.g. syscalls.)
+// Constructible from a absl::Time (for a timeout to be respected) or {}
+// (for "no timeout".)
+// This is a private low-level API for use by a handful of low-level
+// components that are friends of this class. Higher-level components
+// should build APIs based on absl::Time and absl::Duration.
+
+#ifndef ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_
+#define ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_
+
+#ifdef _WIN32
+#include <intsafe.h>
+#endif
+#include <time.h>
+#include <algorithm>
+#include <limits>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+
+namespace absl {
+namespace synchronization_internal {
+
+class Futex;
+class Waiter;
+
+class KernelTimeout {
+ public:
+ // A timeout that should expire at <t>. Any value, in the full
+ // InfinitePast() to InfiniteFuture() range, is valid here and will be
+ // respected.
+ explicit KernelTimeout(absl::Time t) : ns_(MakeNs(t)) {}
+ // No timeout.
+ KernelTimeout() : ns_(0) {}
+
+ // A more explicit factory for those who prefer it. Equivalent to {}.
+ static KernelTimeout Never() { return {}; }
+
+ // We explicitly do not support other custom formats: timespec, int64_t nanos.
+ // Unify on this and absl::Time, please.
+ bool has_timeout() const { return ns_ != 0; }
+
+ private:
+ // internal rep, not user visible: ns after unix epoch.
+ // zero = no timeout.
+ // Negative we treat as an unlikely (and certainly expired!) but valid
+ // timeout.
+ int64_t ns_;
+
+ static int64_t MakeNs(absl::Time t) {
+ // optimization--InfiniteFuture is common "no timeout" value
+ // and cheaper to compare than convert.
+ if (t == absl::InfiniteFuture()) return 0;
+ int64_t x = ToUnixNanos(t);
+
+ // A timeout that lands exactly on the epoch (x=0) needs to be respected,
+ // so we alter it unnoticably to 1. Negative timeouts are in
+ // theory supported, but handled poorly by the kernel (long
+ // delays) so push them forward too; since all such times have
+ // already passed, it's indistinguishable.
+ if (x <= 0) x = 1;
+ // A time larger than what can be represented to the kernel is treated
+ // as no timeout.
+ if (x == std::numeric_limits<int64_t>::max()) x = 0;
+ return x;
+ }
+
+ // Convert to parameter for sem_timedwait/futex/similar. Only for approved
+ // users. Do not call if !has_timeout.
+ struct timespec MakeAbsTimespec() {
+ int64_t n = ns_;
+ static const int64_t kNanosPerSecond = 1000 * 1000 * 1000;
+ if (n == 0) {
+ ABSL_RAW_LOG(
+ ERROR,
+ "Tried to create a timespec from a non-timeout; never do this.");
+ // But we'll try to continue sanely. no-timeout ~= saturated timeout.
+ n = std::numeric_limits<int64_t>::max();
+ }
+
+ // Kernel APIs validate timespecs as being at or after the epoch,
+ // despite the kernel time type being signed. However, no one can
+ // tell the difference between a timeout at or before the epoch (since
+ // all such timeouts have expired!)
+ if (n < 0) n = 0;
+
+ struct timespec abstime;
+ int64_t seconds = std::min(n / kNanosPerSecond,
+ int64_t{std::numeric_limits<time_t>::max()});
+ abstime.tv_sec = static_cast<time_t>(seconds);
+ abstime.tv_nsec =
+ static_cast<decltype(abstime.tv_nsec)>(n % kNanosPerSecond);
+ return abstime;
+ }
+
+#ifdef _WIN32
+ // Converts to milliseconds from now, or INFINITE when
+ // !has_timeout(). For use by SleepConditionVariableSRW on
+ // Windows. Callers should recognize that the return value is a
+ // relative duration (it should be recomputed by calling this method
+ // in the case of a spurious wakeup).
+ DWORD InMillisecondsFromNow() const {
+ if (!has_timeout()) {
+ return INFINITE;
+ }
+ // The use of absl::Now() to convert from absolute time to
+ // relative time means that absl::Now() cannot use anything that
+ // depends on KernelTimeout (for example, Mutex) on Windows.
+ int64_t now = ToUnixNanos(absl::Now());
+ if (ns_ >= now) {
+ // Round up so that Now() + ms_from_now >= ns_.
+ constexpr uint64_t max_nanos =
+ std::numeric_limits<int64_t>::max() - 999999u;
+ uint64_t ms_from_now =
+ (std::min<uint64_t>(max_nanos, ns_ - now) + 999999u) / 1000000u;
+ if (ms_from_now > std::numeric_limits<DWORD>::max()) {
+ return INFINITE;
+ }
+ return static_cast<DWORD>(ms_from_now);
+ }
+ return 0;
+ }
+#endif
+
+ friend class Futex;
+ friend class Waiter;
+};
+
+} // namespace synchronization_internal
+} // namespace absl
+#endif // ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_
http://git-wip-us.apache.org/repos/asf/marmotta/blob/0eb556da/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/internal/mutex_nonprod.cc
----------------------------------------------------------------------
diff --git a/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/internal/mutex_nonprod.cc b/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/internal/mutex_nonprod.cc
new file mode 100644
index 0000000..45c6032
--- /dev/null
+++ b/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/internal/mutex_nonprod.cc
@@ -0,0 +1,318 @@
+// Copyright 2017 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
+//
+// http://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.
+
+// Implementation of a small subset of Mutex and CondVar functionality
+// for platforms where the production implementation hasn't been fully
+// ported yet.
+
+#include "absl/synchronization/mutex.h"
+
+#if defined(_WIN32)
+#include <chrono> // NOLINT(build/c++11)
+#else
+#include <sys/time.h>
+#include <time.h>
+#endif
+
+#include <algorithm>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/time/time.h"
+
+namespace absl {
+namespace synchronization_internal {
+
+namespace {
+
+// Return the current time plus the timeout.
+absl::Time DeadlineFromTimeout(absl::Duration timeout) {
+ return absl::Now() + timeout;
+}
+
+// Limit the deadline to a positive, 32-bit time_t value to accommodate
+// implementation restrictions. This also deals with InfinitePast and
+// InfiniteFuture.
+absl::Time LimitedDeadline(absl::Time deadline) {
+ deadline = std::max(absl::FromTimeT(0), deadline);
+ deadline = std::min(deadline, absl::FromTimeT(0x7fffffff));
+ return deadline;
+}
+
+} // namespace
+
+#if defined(_WIN32)
+
+MutexImpl::MutexImpl() {}
+
+MutexImpl::~MutexImpl() {
+ if (locked_) {
+ std_mutex_.unlock();
+ }
+}
+
+void MutexImpl::Lock() {
+ std_mutex_.lock();
+ locked_ = true;
+}
+
+bool MutexImpl::TryLock() {
+ bool locked = std_mutex_.try_lock();
+ if (locked) locked_ = true;
+ return locked;
+}
+
+void MutexImpl::Unlock() {
+ locked_ = false;
+ released_.SignalAll();
+ std_mutex_.unlock();
+}
+
+CondVarImpl::CondVarImpl() {}
+
+CondVarImpl::~CondVarImpl() {}
+
+void CondVarImpl::Signal() { std_cv_.notify_one(); }
+
+void CondVarImpl::SignalAll() { std_cv_.notify_all(); }
+
+void CondVarImpl::Wait(MutexImpl* mu) {
+ mu->released_.SignalAll();
+ std_cv_.wait(mu->std_mutex_);
+}
+
+bool CondVarImpl::WaitWithDeadline(MutexImpl* mu, absl::Time deadline) {
+ mu->released_.SignalAll();
+ time_t when = ToTimeT(deadline);
+ int64_t nanos = ToInt64Nanoseconds(deadline - absl::FromTimeT(when));
+ std::chrono::system_clock::time_point deadline_tp =
+ std::chrono::system_clock::from_time_t(when) +
+ std::chrono::duration_cast<std::chrono::system_clock::duration>(
+ std::chrono::nanoseconds(nanos));
+ auto deadline_since_epoch =
+ std::chrono::duration_cast<std::chrono::duration<double>>(
+ deadline_tp - std::chrono::system_clock::from_time_t(0));
+ return std_cv_.wait_until(mu->std_mutex_, deadline_tp) ==
+ std::cv_status::timeout;
+}
+
+#else // ! _WIN32
+
+MutexImpl::MutexImpl() {
+ ABSL_RAW_CHECK(pthread_mutex_init(&pthread_mutex_, nullptr) == 0,
+ "pthread error");
+}
+
+MutexImpl::~MutexImpl() {
+ if (locked_) {
+ ABSL_RAW_CHECK(pthread_mutex_unlock(&pthread_mutex_) == 0, "pthread error");
+ }
+ ABSL_RAW_CHECK(pthread_mutex_destroy(&pthread_mutex_) == 0, "pthread error");
+}
+
+void MutexImpl::Lock() {
+ ABSL_RAW_CHECK(pthread_mutex_lock(&pthread_mutex_) == 0, "pthread error");
+ locked_ = true;
+}
+
+bool MutexImpl::TryLock() {
+ bool locked = (0 == pthread_mutex_trylock(&pthread_mutex_));
+ if (locked) locked_ = true;
+ return locked;
+}
+
+void MutexImpl::Unlock() {
+ locked_ = false;
+ released_.SignalAll();
+ ABSL_RAW_CHECK(pthread_mutex_unlock(&pthread_mutex_) == 0, "pthread error");
+}
+
+CondVarImpl::CondVarImpl() {
+ ABSL_RAW_CHECK(pthread_cond_init(&pthread_cv_, nullptr) == 0,
+ "pthread error");
+}
+
+CondVarImpl::~CondVarImpl() {
+ ABSL_RAW_CHECK(pthread_cond_destroy(&pthread_cv_) == 0, "pthread error");
+}
+
+void CondVarImpl::Signal() {
+ ABSL_RAW_CHECK(pthread_cond_signal(&pthread_cv_) == 0, "pthread error");
+}
+
+void CondVarImpl::SignalAll() {
+ ABSL_RAW_CHECK(pthread_cond_broadcast(&pthread_cv_) == 0, "pthread error");
+}
+
+void CondVarImpl::Wait(MutexImpl* mu) {
+ mu->released_.SignalAll();
+ ABSL_RAW_CHECK(pthread_cond_wait(&pthread_cv_, &mu->pthread_mutex_) == 0,
+ "pthread error");
+}
+
+bool CondVarImpl::WaitWithDeadline(MutexImpl* mu, absl::Time deadline) {
+ mu->released_.SignalAll();
+ struct timespec ts = ToTimespec(deadline);
+ int rc = pthread_cond_timedwait(&pthread_cv_, &mu->pthread_mutex_, &ts);
+ if (rc == ETIMEDOUT) return true;
+ ABSL_RAW_CHECK(rc == 0, "pthread error");
+ return false;
+}
+
+#endif // ! _WIN32
+
+void MutexImpl::Await(const Condition& cond) {
+ if (cond.Eval()) return;
+ released_.SignalAll();
+ do {
+ released_.Wait(this);
+ } while (!cond.Eval());
+}
+
+bool MutexImpl::AwaitWithDeadline(const Condition& cond, absl::Time deadline) {
+ if (cond.Eval()) return true;
+ released_.SignalAll();
+ while (true) {
+ if (released_.WaitWithDeadline(this, deadline)) return false;
+ if (cond.Eval()) return true;
+ }
+}
+
+} // namespace synchronization_internal
+
+Mutex::Mutex() {}
+
+Mutex::~Mutex() {}
+
+void Mutex::Lock() { impl()->Lock(); }
+
+void Mutex::Unlock() { impl()->Unlock(); }
+
+bool Mutex::TryLock() { return impl()->TryLock(); }
+
+void Mutex::ReaderLock() { Lock(); }
+
+void Mutex::ReaderUnlock() { Unlock(); }
+
+void Mutex::Await(const Condition& cond) { impl()->Await(cond); }
+
+void Mutex::LockWhen(const Condition& cond) {
+ Lock();
+ Await(cond);
+}
+
+bool Mutex::AwaitWithDeadline(const Condition& cond, absl::Time deadline) {
+ return impl()->AwaitWithDeadline(
+ cond, synchronization_internal::LimitedDeadline(deadline));
+}
+
+bool Mutex::AwaitWithTimeout(const Condition& cond, absl::Duration timeout) {
+ return AwaitWithDeadline(
+ cond, synchronization_internal::DeadlineFromTimeout(timeout));
+}
+
+bool Mutex::LockWhenWithDeadline(const Condition& cond, absl::Time deadline) {
+ Lock();
+ return AwaitWithDeadline(cond, deadline);
+}
+
+bool Mutex::LockWhenWithTimeout(const Condition& cond, absl::Duration timeout) {
+ return LockWhenWithDeadline(
+ cond, synchronization_internal::DeadlineFromTimeout(timeout));
+}
+
+void Mutex::ReaderLockWhen(const Condition& cond) {
+ ReaderLock();
+ Await(cond);
+}
+
+bool Mutex::ReaderLockWhenWithTimeout(const Condition& cond,
+ absl::Duration timeout) {
+ return LockWhenWithTimeout(cond, timeout);
+}
+bool Mutex::ReaderLockWhenWithDeadline(const Condition& cond,
+ absl::Time deadline) {
+ return LockWhenWithDeadline(cond, deadline);
+}
+
+void Mutex::EnableDebugLog(const char*) {}
+void Mutex::EnableInvariantDebugging(void (*)(void*), void*) {}
+void Mutex::ForgetDeadlockInfo() {}
+void Mutex::AssertHeld() const {}
+void Mutex::AssertReaderHeld() const {}
+void Mutex::AssertNotHeld() const {}
+
+CondVar::CondVar() {}
+
+CondVar::~CondVar() {}
+
+void CondVar::Signal() { impl()->Signal(); }
+
+void CondVar::SignalAll() { impl()->SignalAll(); }
+
+void CondVar::Wait(Mutex* mu) { return impl()->Wait(mu->impl()); }
+
+bool CondVar::WaitWithDeadline(Mutex* mu, absl::Time deadline) {
+ return impl()->WaitWithDeadline(
+ mu->impl(), synchronization_internal::LimitedDeadline(deadline));
+}
+
+bool CondVar::WaitWithTimeout(Mutex* mu, absl::Duration timeout) {
+ return WaitWithDeadline(mu, absl::Now() + timeout);
+}
+
+void CondVar::EnableDebugLog(const char*) {}
+
+#ifdef THREAD_SANITIZER
+extern "C" void __tsan_read1(void *addr);
+#else
+#define __tsan_read1(addr) // do nothing if TSan not enabled
+#endif
+
+// A function that just returns its argument, dereferenced
+static bool Dereference(void *arg) {
+ // ThreadSanitizer does not instrument this file for memory accesses.
+ // This function dereferences a user variable that can participate
+ // in a data race, so we need to manually tell TSan about this memory access.
+ __tsan_read1(arg);
+ return *(static_cast<bool *>(arg));
+}
+
+Condition::Condition() {} // null constructor, used for kTrue only
+const Condition Condition::kTrue;
+
+Condition::Condition(bool (*func)(void *), void *arg)
+ : eval_(&CallVoidPtrFunction),
+ function_(func),
+ method_(nullptr),
+ arg_(arg) {}
+
+bool Condition::CallVoidPtrFunction(const Condition *c) {
+ return (*c->function_)(c->arg_);
+}
+
+Condition::Condition(const bool *cond)
+ : eval_(CallVoidPtrFunction),
+ function_(Dereference),
+ method_(nullptr),
+ // const_cast is safe since Dereference does not modify arg
+ arg_(const_cast<bool *>(cond)) {}
+
+bool Condition::Eval() const {
+ // eval_ == null for kTrue
+ return (this->eval_ == nullptr) || (*this->eval_)(this);
+}
+
+void RegisterSymbolizer(bool (*)(const void*, char*, int)) {}
+
+} // namespace absl
http://git-wip-us.apache.org/repos/asf/marmotta/blob/0eb556da/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/internal/mutex_nonprod.inc
----------------------------------------------------------------------
diff --git a/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/internal/mutex_nonprod.inc b/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/internal/mutex_nonprod.inc
new file mode 100644
index 0000000..0aab3d1
--- /dev/null
+++ b/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/internal/mutex_nonprod.inc
@@ -0,0 +1,256 @@
+// Do not include. This is an implementation detail of base/mutex.h.
+//
+// Declares three classes:
+//
+// base::internal::MutexImpl - implementation helper for Mutex
+// base::internal::CondVarImpl - implementation helper for CondVar
+// base::internal::SynchronizationStorage<T> - implementation helper for
+// Mutex, CondVar
+
+#include <type_traits>
+
+#if defined(_WIN32)
+#include <condition_variable>
+#include <mutex>
+#else
+#include <pthread.h>
+#endif
+
+#include "absl/base/call_once.h"
+#include "absl/time/time.h"
+
+// Declare that Mutex::ReaderLock is actually Lock(). Intended primarily
+// for tests, and even then as a last resort.
+#ifdef ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE
+#error ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE cannot be directly set
+#else
+#define ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE 1
+#endif
+
+// Declare that Mutex::EnableInvariantDebugging is not implemented.
+// Intended primarily for tests, and even then as a last resort.
+#ifdef ABSL_MUTEX_ENABLE_INVARIANT_DEBUGGING_NOT_IMPLEMENTED
+#error ABSL_MUTEX_ENABLE_INVARIANT_DEBUGGING_NOT_IMPLEMENTED cannot be directly set
+#else
+#define ABSL_MUTEX_ENABLE_INVARIANT_DEBUGGING_NOT_IMPLEMENTED 1
+#endif
+
+namespace absl {
+class Condition;
+
+namespace synchronization_internal {
+
+class MutexImpl;
+
+// Do not use this implementation detail of CondVar. Provides most of the
+// implementation, but should not be placed directly in static storage
+// because it will not linker initialize properly. See
+// SynchronizationStorage<T> below for what we mean by linker
+// initialization.
+class CondVarImpl {
+ public:
+ CondVarImpl();
+ CondVarImpl(const CondVarImpl&) = delete;
+ CondVarImpl& operator=(const CondVarImpl&) = delete;
+ ~CondVarImpl();
+
+ void Signal();
+ void SignalAll();
+ void Wait(MutexImpl* mutex);
+ bool WaitWithDeadline(MutexImpl* mutex, absl::Time deadline);
+
+ private:
+#if defined(_WIN32)
+ std::condition_variable_any std_cv_;
+#else
+ pthread_cond_t pthread_cv_;
+#endif
+};
+
+// Do not use this implementation detail of Mutex. Provides most of the
+// implementation, but should not be placed directly in static storage
+// because it will not linker initialize properly. See
+// SynchronizationStorage<T> below for what we mean by linker
+// initialization.
+class MutexImpl {
+ public:
+ MutexImpl();
+ MutexImpl(const MutexImpl&) = delete;
+ MutexImpl& operator=(const MutexImpl&) = delete;
+ ~MutexImpl();
+
+ void Lock();
+ bool TryLock();
+ void Unlock();
+ void Await(const Condition& cond);
+ bool AwaitWithDeadline(const Condition& cond, absl::Time deadline);
+
+ private:
+ friend class CondVarImpl;
+
+#if defined(_WIN32)
+ std::mutex std_mutex_;
+#else
+ pthread_mutex_t pthread_mutex_;
+#endif
+
+ // True if the underlying mutex is locked. If the destructor is entered
+ // while locked_, the underlying mutex is unlocked. Mutex supports
+ // destruction while locked, but the same is undefined behavior for both
+ // pthread_mutex_t and std::mutex.
+ bool locked_ = false;
+
+ // Signaled before releasing the lock, in support of Await.
+ CondVarImpl released_;
+};
+
+// Do not use this implementation detail of CondVar and Mutex. A storage
+// space for T that supports a LinkerInitialized constructor. T must
+// have a default constructor, which is called by the first call to
+// get(). T's destructor is never called if the LinkerInitialized
+// constructor is called.
+//
+// Objects constructed with the default constructor are constructed and
+// destructed like any other object, and should never be allocated in
+// static storage.
+//
+// Objects constructed with the LinkerInitialized constructor should
+// always be in static storage. For such objects, calls to get() are always
+// valid, except from signal handlers.
+//
+// Note that this implementation relies on undefined language behavior that
+// are known to hold for the set of supported compilers. An analysis
+// follows.
+//
+// From the C++11 standard:
+//
+// [basic.life] says an object has non-trivial initialization if it is of
+// class type and it is initialized by a constructor other than a trivial
+// default constructor. (the LinkerInitialized constructor is
+// non-trivial)
+//
+// [basic.life] says the lifetime of an object with a non-trivial
+// constructor begins when the call to the constructor is complete.
+//
+// [basic.life] says the lifetime of an object with non-trivial destructor
+// ends when the call to the destructor begins.
+//
+// [basic.life] p5 specifies undefined behavior when accessing non-static
+// members of an instance outside its
+// lifetime. (SynchronizationStorage::get() access non-static members)
+//
+// So, LinkerInitialized object of SynchronizationStorage uses a
+// non-trivial constructor, which is called at some point during dynamic
+// initialization, and is therefore subject to order of dynamic
+// initialization bugs, where get() is called before the object's
+// constructor is, resulting in undefined behavior.
+//
+// Similarly, a LinkerInitialized SynchronizationStorage object has a
+// non-trivial destructor, and so its lifetime ends at some point during
+// destruction of objects with static storage duration [basic.start.term]
+// p4. There is a window where other exit code could call get() after this
+// occurs, resulting in undefined behavior.
+//
+// Combined, these statements imply that LinkerInitialized instances
+// of SynchronizationStorage<T> rely on undefined behavior.
+//
+// However, in practice, the implementation works on all supported
+// compilers. Specifically, we rely on:
+//
+// a) zero-initialization being sufficient to initialize
+// LinkerInitialized instances for the purposes of calling
+// get(), regardless of when the constructor is called. This is
+// because the is_dynamic_ boolean is correctly zero-initialized to
+// false.
+//
+// b) the LinkerInitialized constructor is a NOP, and immaterial to
+// even to concurrent calls to get().
+//
+// c) the destructor being a NOP for LinkerInitialized objects
+// (guaranteed by a check for !is_dynamic_), and so any concurrent and
+// subsequent calls to get() functioning as if the destructor were not
+// called, by virtue of the instances' storage remaining valid after the
+// destructor runs.
+//
+// d) That a-c apply transitively when SynchronizationStorage<T> is the
+// only member of a class allocated in static storage.
+//
+// Nothing in the language standard guarantees that a-d hold. In practice,
+// these hold in all supported compilers.
+//
+// Future direction:
+//
+// Ideally, we would simply use std::mutex or a similar class, which when
+// allocated statically would support use immediately after static
+// initialization up until static storage is reclaimed (i.e. the properties
+// we require of all "linker initialized" instances).
+//
+// Regarding construction in static storage, std::mutex is required to
+// provide a constexpr default constructor [thread.mutex.class], which
+// ensures the instance's lifetime begins with static initialization
+// [basic.start.init], and so is immune to any problems caused by the order
+// of dynamic initialization. However, as of this writing Microsoft's
+// Visual Studio does not provide a constexpr constructor for std::mutex.
+// See
+// https://blogs.msdn.microsoft.com/vcblog/2015/06/02/constexpr-complete-for-vs-2015-rtm-c11-compiler-c17-stl/
+//
+// Regarding destruction of instances in static storage, [basic.life] does
+// say an object ends when storage in which the occupies is released, in
+// the case of non-trivial destructor. However, std::mutex is not specified
+// to have a trivial destructor.
+//
+// So, we would need a class with a constexpr default constructor and a
+// trivial destructor. Today, we can achieve neither desired property using
+// std::mutex directly.
+template <typename T>
+class SynchronizationStorage {
+ public:
+ // Instances allocated on the heap or on the stack should use the default
+ // constructor.
+ SynchronizationStorage()
+ : is_dynamic_(true), once_() {}
+
+ // Instances allocated in static storage (not on the heap, not on the
+ // stack) should use this constructor.
+ explicit SynchronizationStorage(base_internal::LinkerInitialized) {}
+
+ SynchronizationStorage(SynchronizationStorage&) = delete;
+ SynchronizationStorage& operator=(SynchronizationStorage&) = delete;
+
+ ~SynchronizationStorage() {
+ if (is_dynamic_) {
+ get()->~T();
+ }
+ }
+
+ // Retrieve the object in storage. This is fast and thread safe, but does
+ // incur the cost of absl::call_once().
+ //
+ // For instances in static storage constructed with the
+ // LinkerInitialized constructor, may be called at any time without
+ // regard for order of dynamic initialization or destruction of objects
+ // in static storage. See the class comment for caveats.
+ T* get() {
+ absl::call_once(once_, SynchronizationStorage::Construct, this);
+ return reinterpret_cast<T*>(&space_);
+ }
+
+ private:
+ static void Construct(SynchronizationStorage<T>* self) {
+ new (&self->space_) T();
+ }
+
+ // When true, T's destructor is run when this is destructed.
+ //
+ // The LinkerInitialized constructor assumes this value will be set
+ // false by static initialization.
+ bool is_dynamic_;
+
+ absl::once_flag once_;
+
+ // An aligned space for T.
+ typename std::aligned_storage<sizeof(T), alignof(T)>::type space_;
+};
+
+} // namespace synchronization_internal
+} // namespace absl
http://git-wip-us.apache.org/repos/asf/marmotta/blob/0eb556da/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/internal/per_thread_sem.cc
----------------------------------------------------------------------
diff --git a/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/internal/per_thread_sem.cc b/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/internal/per_thread_sem.cc
new file mode 100644
index 0000000..caa2baf
--- /dev/null
+++ b/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/internal/per_thread_sem.cc
@@ -0,0 +1,99 @@
+// Copyright 2017 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
+//
+// http://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.
+
+// This file is a no-op if the required LowLevelAlloc support is missing.
+#include "absl/base/internal/low_level_alloc.h"
+#ifndef ABSL_LOW_LEVEL_ALLOC_MISSING
+
+#include "absl/synchronization/internal/per_thread_sem.h"
+
+#include <atomic>
+
+#include "absl/base/attributes.h"
+#include "absl/base/internal/thread_identity.h"
+#include "absl/synchronization/internal/waiter.h"
+
+namespace absl {
+namespace synchronization_internal {
+
+void PerThreadSem::SetThreadBlockedCounter(std::atomic<int> *counter) {
+ base_internal::ThreadIdentity *identity;
+ identity = GetOrCreateCurrentThreadIdentity();
+ identity->blocked_count_ptr = counter;
+}
+
+std::atomic<int> *PerThreadSem::GetThreadBlockedCounter() {
+ base_internal::ThreadIdentity *identity;
+ identity = GetOrCreateCurrentThreadIdentity();
+ return identity->blocked_count_ptr;
+}
+
+void PerThreadSem::Init(base_internal::ThreadIdentity *identity) {
+ Waiter::GetWaiter(identity)->Init();
+ identity->ticker.store(0, std::memory_order_relaxed);
+ identity->wait_start.store(0, std::memory_order_relaxed);
+ identity->is_idle.store(false, std::memory_order_relaxed);
+}
+
+void PerThreadSem::Tick(base_internal::ThreadIdentity *identity) {
+ const int ticker =
+ identity->ticker.fetch_add(1, std::memory_order_relaxed) + 1;
+ const int wait_start = identity->wait_start.load(std::memory_order_relaxed);
+ const bool is_idle = identity->is_idle.load(std::memory_order_relaxed);
+ if (wait_start && (ticker - wait_start > Waiter::kIdlePeriods) && !is_idle) {
+ // Wakeup the waiting thread since it is time for it to become idle.
+ Waiter::GetWaiter(identity)->Poke();
+ }
+}
+
+} // namespace synchronization_internal
+} // namespace absl
+
+extern "C" {
+
+ABSL_ATTRIBUTE_WEAK void AbslInternalPerThreadSemPost(
+ absl::base_internal::ThreadIdentity *identity) {
+ absl::synchronization_internal::Waiter::GetWaiter(identity)->Post();
+}
+
+ABSL_ATTRIBUTE_WEAK bool AbslInternalPerThreadSemWait(
+ absl::synchronization_internal::KernelTimeout t) {
+ bool timeout = false;
+ absl::base_internal::ThreadIdentity *identity;
+ identity = absl::synchronization_internal::GetOrCreateCurrentThreadIdentity();
+
+ // Ensure wait_start != 0.
+ int ticker = identity->ticker.load(std::memory_order_relaxed);
+ identity->wait_start.store(ticker ? ticker : 1, std::memory_order_relaxed);
+ identity->is_idle.store(false, std::memory_order_relaxed);
+
+ if (identity->blocked_count_ptr != nullptr) {
+ // Increment count of threads blocked in a given thread pool.
+ identity->blocked_count_ptr->fetch_add(1, std::memory_order_relaxed);
+ }
+
+ timeout =
+ !absl::synchronization_internal::Waiter::GetWaiter(identity)->Wait(t);
+
+ if (identity->blocked_count_ptr != nullptr) {
+ identity->blocked_count_ptr->fetch_sub(1, std::memory_order_relaxed);
+ }
+ identity->is_idle.store(false, std::memory_order_relaxed);
+ identity->wait_start.store(0, std::memory_order_relaxed);
+ return !timeout;
+}
+
+} // extern "C"
+
+#endif // ABSL_LOW_LEVEL_ALLOC_MISSING
http://git-wip-us.apache.org/repos/asf/marmotta/blob/0eb556da/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/internal/per_thread_sem.h
----------------------------------------------------------------------
diff --git a/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/internal/per_thread_sem.h b/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/internal/per_thread_sem.h
new file mode 100644
index 0000000..678b69e
--- /dev/null
+++ b/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/internal/per_thread_sem.h
@@ -0,0 +1,107 @@
+// Copyright 2017 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
+//
+// http://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.
+//
+
+// PerThreadSem is a low-level synchronization primitive controlling the
+// runnability of a single thread, used internally by Mutex and CondVar.
+//
+// This is NOT a general-purpose synchronization mechanism, and should not be
+// used directly by applications. Applications should use Mutex and CondVar.
+//
+// The semantics of PerThreadSem are the same as that of a counting semaphore.
+// Each thread maintains an abstract "count" value associated with its identity.
+
+#ifndef ABSL_SYNCHRONIZATION_INTERNAL_PER_THREAD_SEM_H_
+#define ABSL_SYNCHRONIZATION_INTERNAL_PER_THREAD_SEM_H_
+
+#include <atomic>
+
+#include "absl/base/internal/thread_identity.h"
+#include "absl/synchronization/internal/create_thread_identity.h"
+#include "absl/synchronization/internal/kernel_timeout.h"
+
+namespace absl {
+
+class Mutex;
+
+namespace synchronization_internal {
+
+class PerThreadSem {
+ public:
+ PerThreadSem() = delete;
+ PerThreadSem(const PerThreadSem&) = delete;
+ PerThreadSem& operator=(const PerThreadSem&) = delete;
+
+ // Routine invoked periodically (once a second) by a background thread.
+ // Has no effect on user-visible state.
+ static void Tick(base_internal::ThreadIdentity* identity);
+
+ // ---------------------------------------------------------------------------
+ // Routines used by autosizing threadpools to detect when threads are
+ // blocked. Each thread has a counter pointer, initially zero. If non-zero,
+ // the implementation atomically increments the counter when it blocks on a
+ // semaphore, a decrements it again when it wakes. This allows a threadpool
+ // to keep track of how many of its threads are blocked.
+ // SetThreadBlockedCounter() should be used only by threadpool
+ // implementations. GetThreadBlockedCounter() should be used by modules that
+ // block threads; if the pointer returned is non-zero, the location should be
+ // incremented before the thread blocks, and decremented after it wakes.
+ static void SetThreadBlockedCounter(std::atomic<int> *counter);
+ static std::atomic<int> *GetThreadBlockedCounter();
+
+ private:
+ // Create the PerThreadSem associated with "identity". Initializes count=0.
+ // REQUIRES: May only be called by ThreadIdentity.
+ static void Init(base_internal::ThreadIdentity* identity);
+
+ // Increments "identity"'s count.
+ static inline void Post(base_internal::ThreadIdentity* identity);
+
+ // Waits until either our count > 0 or t has expired.
+ // If count > 0, decrements count and returns true. Otherwise returns false.
+ // !t.has_timeout() => Wait(t) will return true.
+ static inline bool Wait(KernelTimeout t);
+
+ // White-listed callers.
+ friend class PerThreadSemTest;
+ friend class absl::Mutex;
+ friend absl::base_internal::ThreadIdentity* CreateThreadIdentity();
+};
+
+} // namespace synchronization_internal
+} // namespace absl
+
+// In some build configurations we pass --detect-odr-violations to the
+// gold linker. This causes it to flag weak symbol overrides as ODR
+// violations. Because ODR only applies to C++ and not C,
+// --detect-odr-violations ignores symbols not mangled with C++ names.
+// By changing our extension points to be extern "C", we dodge this
+// check.
+extern "C" {
+void AbslInternalPerThreadSemPost(
+ absl::base_internal::ThreadIdentity* identity);
+bool AbslInternalPerThreadSemWait(
+ absl::synchronization_internal::KernelTimeout t);
+} // extern "C"
+
+void absl::synchronization_internal::PerThreadSem::Post(
+ absl::base_internal::ThreadIdentity* identity) {
+ AbslInternalPerThreadSemPost(identity);
+}
+
+bool absl::synchronization_internal::PerThreadSem::Wait(
+ absl::synchronization_internal::KernelTimeout t) {
+ return AbslInternalPerThreadSemWait(t);
+}
+#endif // ABSL_SYNCHRONIZATION_INTERNAL_PER_THREAD_SEM_H_
http://git-wip-us.apache.org/repos/asf/marmotta/blob/0eb556da/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/internal/per_thread_sem_test.cc
----------------------------------------------------------------------
diff --git a/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/internal/per_thread_sem_test.cc b/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/internal/per_thread_sem_test.cc
new file mode 100644
index 0000000..2b52ea7
--- /dev/null
+++ b/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/internal/per_thread_sem_test.cc
@@ -0,0 +1,172 @@
+// Copyright 2017 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
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/synchronization/internal/per_thread_sem.h"
+
+#include <atomic>
+#include <condition_variable> // NOLINT(build/c++11)
+#include <functional>
+#include <limits>
+#include <mutex> // NOLINT(build/c++11)
+#include <string>
+#include <thread> // NOLINT(build/c++11)
+
+#include "gtest/gtest.h"
+#include "absl/base/internal/cycleclock.h"
+#include "absl/base/internal/thread_identity.h"
+#include "absl/strings/str_cat.h"
+#include "absl/time/clock.h"
+#include "absl/time/time.h"
+
+// In this test we explicitly avoid the use of synchronization
+// primitives which might use PerThreadSem, most notably absl::Mutex.
+
+namespace absl {
+namespace synchronization_internal {
+
+class SimpleSemaphore {
+ public:
+ SimpleSemaphore() : count_(0) {}
+
+ // Decrements (locks) the semaphore. If the semaphore's value is
+ // greater than zero, then the decrement proceeds, and the function
+ // returns, immediately. If the semaphore currently has the value
+ // zero, then the call blocks until it becomes possible to perform
+ // the decrement.
+ void Wait() {
+ std::unique_lock<std::mutex> lock(mu_);
+ cv_.wait(lock, [this]() { return count_ > 0; });
+ --count_;
+ cv_.notify_one();
+ }
+
+ // Increments (unlocks) the semaphore. If the semaphore's value
+ // consequently becomes greater than zero, then another thread
+ // blocked Wait() call will be woken up and proceed to lock the
+ // semaphore.
+ void Post() {
+ std::lock_guard<std::mutex> lock(mu_);
+ ++count_;
+ cv_.notify_one();
+ }
+
+ private:
+ std::mutex mu_;
+ std::condition_variable cv_;
+ int count_;
+};
+
+struct ThreadData {
+ int num_iterations; // Number of replies to send.
+ SimpleSemaphore identity2_written; // Posted by thread writing identity2.
+ base_internal::ThreadIdentity *identity1; // First Post()-er.
+ base_internal::ThreadIdentity *identity2; // First Wait()-er.
+ KernelTimeout timeout;
+};
+
+// Need friendship with PerThreadSem.
+class PerThreadSemTest : public testing::Test {
+ public:
+ static void TimingThread(ThreadData* t) {
+ t->identity2 = GetOrCreateCurrentThreadIdentity();
+ t->identity2_written.Post();
+ while (t->num_iterations--) {
+ Wait(t->timeout);
+ Post(t->identity1);
+ }
+ }
+
+ void TestTiming(const char *msg, bool timeout) {
+ static const int kNumIterations = 100;
+ ThreadData t;
+ t.num_iterations = kNumIterations;
+ t.timeout = timeout ?
+ KernelTimeout(absl::Now() + absl::Seconds(10000)) // far in the future
+ : KernelTimeout::Never();
+ t.identity1 = GetOrCreateCurrentThreadIdentity();
+
+ // We can't use the Thread class here because it uses the Mutex
+ // class which will invoke PerThreadSem, so we use std::thread instead.
+ std::thread partner_thread(std::bind(TimingThread, &t));
+
+ // Wait for our partner thread to register their identity.
+ t.identity2_written.Wait();
+
+ int64_t min_cycles = std::numeric_limits<int64_t>::max();
+ int64_t total_cycles = 0;
+ for (int i = 0; i < kNumIterations; ++i) {
+ absl::SleepFor(absl::Milliseconds(20));
+ int64_t cycles = base_internal::CycleClock::Now();
+ Post(t.identity2);
+ Wait(t.timeout);
+ cycles = base_internal::CycleClock::Now() - cycles;
+ min_cycles = std::min(min_cycles, cycles);
+ total_cycles += cycles;
+ }
+ std::string out =
+ StrCat(msg, "min cycle count=", min_cycles, " avg cycle count=",
+ absl::SixDigits(static_cast<double>(total_cycles) /
+ kNumIterations));
+ printf("%s\n", out.c_str());
+
+ partner_thread.join();
+ }
+
+ protected:
+ static void Post(base_internal::ThreadIdentity *id) {
+ PerThreadSem::Post(id);
+ }
+ static bool Wait(KernelTimeout t) {
+ return PerThreadSem::Wait(t);
+ }
+
+ // convenience overload
+ static bool Wait(absl::Time t) {
+ return Wait(KernelTimeout(t));
+ }
+
+ static void Tick(base_internal::ThreadIdentity *identity) {
+ PerThreadSem::Tick(identity);
+ }
+};
+
+namespace {
+
+TEST_F(PerThreadSemTest, WithoutTimeout) {
+ PerThreadSemTest::TestTiming("Without timeout: ", false);
+}
+
+TEST_F(PerThreadSemTest, WithTimeout) {
+ PerThreadSemTest::TestTiming("With timeout: ", true);
+}
+
+TEST_F(PerThreadSemTest, Timeouts) {
+ absl::Time timeout = absl::Now() + absl::Milliseconds(50);
+ EXPECT_FALSE(Wait(timeout));
+ EXPECT_LE(timeout, absl::Now());
+
+ absl::Time negative_timeout = absl::UnixEpoch() - absl::Milliseconds(100);
+ EXPECT_FALSE(Wait(negative_timeout));
+ EXPECT_LE(negative_timeout, absl::Now()); // trivially true :)
+
+ Post(GetOrCreateCurrentThreadIdentity());
+ // The wait here has an expired timeout, but we have a wake to consume,
+ // so this should succeed
+ EXPECT_TRUE(Wait(negative_timeout));
+}
+
+} // namespace
+
+} // namespace synchronization_internal
+} // namespace absl
http://git-wip-us.apache.org/repos/asf/marmotta/blob/0eb556da/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/internal/thread_pool.h
----------------------------------------------------------------------
diff --git a/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/internal/thread_pool.h b/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/internal/thread_pool.h
new file mode 100644
index 0000000..8464042
--- /dev/null
+++ b/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/internal/thread_pool.h
@@ -0,0 +1,90 @@
+// Copyright 2017 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
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_SYNCHRONIZATION_INTERNAL_THREAD_POOL_H_
+#define ABSL_SYNCHRONIZATION_INTERNAL_THREAD_POOL_H_
+
+#include <cassert>
+#include <functional>
+#include <queue>
+#include <thread> // NOLINT(build/c++11)
+#include <vector>
+
+#include "absl/base/thread_annotations.h"
+#include "absl/synchronization/mutex.h"
+
+namespace absl {
+namespace synchronization_internal {
+
+// A simple ThreadPool implementation for tests.
+class ThreadPool {
+ public:
+ explicit ThreadPool(int num_threads) {
+ for (int i = 0; i < num_threads; ++i) {
+ threads_.push_back(std::thread(&ThreadPool::WorkLoop, this));
+ }
+ }
+
+ ThreadPool(const ThreadPool &) = delete;
+ ThreadPool &operator=(const ThreadPool &) = delete;
+
+ ~ThreadPool() {
+ {
+ absl::MutexLock l(&mu_);
+ for (int i = 0; i < threads_.size(); ++i) {
+ queue_.push(nullptr); // Shutdown signal.
+ }
+ }
+ for (auto &t : threads_) {
+ t.join();
+ }
+ }
+
+ // Schedule a function to be run on a ThreadPool thread immediately.
+ void Schedule(std::function<void()> func) {
+ assert(func != nullptr);
+ absl::MutexLock l(&mu_);
+ queue_.push(std::move(func));
+ }
+
+ private:
+ bool WorkAvailable() const EXCLUSIVE_LOCKS_REQUIRED(mu_) {
+ return !queue_.empty();
+ }
+
+ void WorkLoop() {
+ while (true) {
+ std::function<void()> func;
+ {
+ absl::MutexLock l(&mu_);
+ mu_.Await(absl::Condition(this, &ThreadPool::WorkAvailable));
+ func = std::move(queue_.front());
+ queue_.pop();
+ }
+ if (func == nullptr) { // Shutdown signal.
+ break;
+ }
+ func();
+ }
+ }
+
+ absl::Mutex mu_;
+ std::queue<std::function<void()>> queue_ GUARDED_BY(mu_);
+ std::vector<std::thread> threads_;
+};
+
+} // namespace synchronization_internal
+} // namespace absl
+
+#endif // ABSL_SYNCHRONIZATION_INTERNAL_THREAD_POOL_H_
http://git-wip-us.apache.org/repos/asf/marmotta/blob/0eb556da/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/internal/waiter.cc
----------------------------------------------------------------------
diff --git a/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/internal/waiter.cc b/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/internal/waiter.cc
new file mode 100644
index 0000000..768c520
--- /dev/null
+++ b/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/internal/waiter.cc
@@ -0,0 +1,412 @@
+// Copyright 2017 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
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/synchronization/internal/waiter.h"
+
+#include "absl/base/config.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <pthread.h>
+#include <sys/time.h>
+#include <unistd.h>
+#endif
+
+#ifdef __linux__
+#include <linux/futex.h>
+#include <sys/syscall.h>
+#endif
+
+#ifdef ABSL_HAVE_SEMAPHORE_H
+#include <semaphore.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <time.h>
+
+#include <atomic>
+#include <cassert>
+#include <cstdint>
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/thread_identity.h"
+#include "absl/base/optimization.h"
+#include "absl/synchronization/internal/kernel_timeout.h"
+
+namespace absl {
+namespace synchronization_internal {
+
+static void MaybeBecomeIdle() {
+ base_internal::ThreadIdentity *identity =
+ base_internal::CurrentThreadIdentityIfPresent();
+ assert(identity != nullptr);
+ const bool is_idle = identity->is_idle.load(std::memory_order_relaxed);
+ const int ticker = identity->ticker.load(std::memory_order_relaxed);
+ const int wait_start = identity->wait_start.load(std::memory_order_relaxed);
+ if (!is_idle && ticker - wait_start > Waiter::kIdlePeriods) {
+ identity->is_idle.store(true, std::memory_order_relaxed);
+ }
+}
+
+#if ABSL_WAITER_MODE == ABSL_WAITER_MODE_FUTEX
+
+// Some Android headers are missing these definitions even though they
+// support these futex operations.
+#ifdef __BIONIC__
+#ifndef SYS_futex
+#define SYS_futex __NR_futex
+#endif
+#ifndef FUTEX_WAIT_BITSET
+#define FUTEX_WAIT_BITSET 9
+#endif
+#ifndef FUTEX_PRIVATE_FLAG
+#define FUTEX_PRIVATE_FLAG 128
+#endif
+#ifndef FUTEX_CLOCK_REALTIME
+#define FUTEX_CLOCK_REALTIME 256
+#endif
+#ifndef FUTEX_BITSET_MATCH_ANY
+#define FUTEX_BITSET_MATCH_ANY 0xFFFFFFFF
+#endif
+#endif
+class Futex {
+ public:
+ static int WaitUntil(std::atomic<int32_t> *v, int32_t val,
+ KernelTimeout t) {
+ int err = 0;
+ if (t.has_timeout()) {
+ // https://locklessinc.com/articles/futex_cheat_sheet/
+ // Unlike FUTEX_WAIT, FUTEX_WAIT_BITSET uses absolute time.
+ struct timespec abs_timeout = t.MakeAbsTimespec();
+ // Atomically check that the futex value is still 0, and if it
+ // is, sleep until abs_timeout or until woken by FUTEX_WAKE.
+ err = syscall(
+ SYS_futex, reinterpret_cast<int32_t *>(v),
+ FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME, val,
+ &abs_timeout, nullptr, FUTEX_BITSET_MATCH_ANY);
+ } else {
+ // Atomically check that the futex value is still 0, and if it
+ // is, sleep until woken by FUTEX_WAKE.
+ err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
+ FUTEX_WAIT | FUTEX_PRIVATE_FLAG, val, nullptr);
+ }
+ if (err != 0) {
+ err = -errno;
+ }
+ return err;
+ }
+
+ static int Wake(std::atomic<int32_t> *v, int32_t count) {
+ int err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
+ FUTEX_WAKE | FUTEX_PRIVATE_FLAG, count);
+ if (ABSL_PREDICT_FALSE(err < 0)) {
+ err = -errno;
+ }
+ return err;
+ }
+};
+
+void Waiter::Init() {
+ futex_.store(0, std::memory_order_relaxed);
+}
+
+bool Waiter::Wait(KernelTimeout t) {
+ // Loop until we can atomically decrement futex from a positive
+ // value, waiting on a futex while we believe it is zero.
+ while (true) {
+ int32_t x = futex_.load(std::memory_order_relaxed);
+ if (x != 0) {
+ if (!futex_.compare_exchange_weak(x, x - 1,
+ std::memory_order_acquire,
+ std::memory_order_relaxed)) {
+ continue; // Raced with someone, retry.
+ }
+ return true; // Consumed a wakeup, we are done.
+ }
+
+ const int err = Futex::WaitUntil(&futex_, 0, t);
+ if (err != 0) {
+ if (err == -EINTR || err == -EWOULDBLOCK) {
+ // Do nothing, the loop will retry.
+ } else if (err == -ETIMEDOUT) {
+ return false;
+ } else {
+ ABSL_RAW_LOG(FATAL, "Futex operation failed with error %d\n", err);
+ }
+ }
+
+ MaybeBecomeIdle();
+ }
+}
+
+void Waiter::Post() {
+ if (futex_.fetch_add(1, std::memory_order_release) == 0) {
+ // We incremented from 0, need to wake a potential waker.
+ Poke();
+ }
+}
+
+void Waiter::Poke() {
+ // Wake one thread waiting on the futex.
+ const int err = Futex::Wake(&futex_, 1);
+ if (ABSL_PREDICT_FALSE(err < 0)) {
+ ABSL_RAW_LOG(FATAL, "Futex operation failed with error %d\n", err);
+ }
+}
+
+#elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_CONDVAR
+
+class PthreadMutexHolder {
+ public:
+ explicit PthreadMutexHolder(pthread_mutex_t *mu) : mu_(mu) {
+ const int err = pthread_mutex_lock(mu_);
+ if (err != 0) {
+ ABSL_RAW_LOG(FATAL, "pthread_mutex_lock failed: %d", err);
+ }
+ }
+
+ PthreadMutexHolder(const PthreadMutexHolder &rhs) = delete;
+ PthreadMutexHolder &operator=(const PthreadMutexHolder &rhs) = delete;
+
+ ~PthreadMutexHolder() {
+ const int err = pthread_mutex_unlock(mu_);
+ if (err != 0) {
+ ABSL_RAW_LOG(FATAL, "pthread_mutex_unlock failed: %d", err);
+ }
+ }
+
+ private:
+ pthread_mutex_t *mu_;
+};
+
+void Waiter::Init() {
+ const int err = pthread_mutex_init(&mu_, 0);
+ if (err != 0) {
+ ABSL_RAW_LOG(FATAL, "pthread_mutex_init failed: %d", err);
+ }
+
+ const int err2 = pthread_cond_init(&cv_, 0);
+ if (err2 != 0) {
+ ABSL_RAW_LOG(FATAL, "pthread_cond_init failed: %d", err2);
+ }
+
+ waiter_count_.store(0, std::memory_order_relaxed);
+ wakeup_count_.store(0, std::memory_order_relaxed);
+}
+
+bool Waiter::Wait(KernelTimeout t) {
+ struct timespec abs_timeout;
+ if (t.has_timeout()) {
+ abs_timeout = t.MakeAbsTimespec();
+ }
+
+ PthreadMutexHolder h(&mu_);
+ waiter_count_.fetch_add(1, std::memory_order_relaxed);
+ // Loop until we find a wakeup to consume or timeout.
+ while (true) {
+ int x = wakeup_count_.load(std::memory_order_relaxed);
+ if (x != 0) {
+ if (!wakeup_count_.compare_exchange_weak(x, x - 1,
+ std::memory_order_acquire,
+ std::memory_order_relaxed)) {
+ continue; // Raced with someone, retry.
+ }
+ // Successfully consumed a wakeup, we're done.
+ waiter_count_.fetch_sub(1, std::memory_order_relaxed);
+ return true;
+ }
+
+ // No wakeups available, time to wait.
+ if (!t.has_timeout()) {
+ const int err = pthread_cond_wait(&cv_, &mu_);
+ if (err != 0) {
+ ABSL_RAW_LOG(FATAL, "pthread_cond_wait failed: %d", err);
+ }
+ } else {
+ const int err = pthread_cond_timedwait(&cv_, &mu_, &abs_timeout);
+ if (err == ETIMEDOUT) {
+ waiter_count_.fetch_sub(1, std::memory_order_relaxed);
+ return false;
+ }
+ if (err != 0) {
+ ABSL_RAW_LOG(FATAL, "pthread_cond_wait failed: %d", err);
+ }
+ }
+ MaybeBecomeIdle();
+ }
+}
+
+void Waiter::Post() {
+ wakeup_count_.fetch_add(1, std::memory_order_release);
+ Poke();
+}
+
+void Waiter::Poke() {
+ if (waiter_count_.load(std::memory_order_relaxed) == 0) {
+ return;
+ }
+ // Potentially a waker. Take the lock and check again.
+ PthreadMutexHolder h(&mu_);
+ if (waiter_count_.load(std::memory_order_relaxed) == 0) {
+ return;
+ }
+ const int err = pthread_cond_signal(&cv_);
+ if (err != 0) {
+ ABSL_RAW_LOG(FATAL, "pthread_cond_signal failed: %d", err);
+ }
+}
+
+#elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_SEM
+
+void Waiter::Init() {
+ if (sem_init(&sem_, 0, 0) != 0) {
+ ABSL_RAW_LOG(FATAL, "sem_init failed with errno %d\n", errno);
+ }
+ wakeups_.store(0, std::memory_order_relaxed);
+}
+
+bool Waiter::Wait(KernelTimeout t) {
+ struct timespec abs_timeout;
+ if (t.has_timeout()) {
+ abs_timeout = t.MakeAbsTimespec();
+ }
+
+ // Loop until we timeout or consume a wakeup.
+ while (true) {
+ int x = wakeups_.load(std::memory_order_relaxed);
+ if (x != 0) {
+ if (!wakeups_.compare_exchange_weak(x, x - 1,
+ std::memory_order_acquire,
+ std::memory_order_relaxed)) {
+ continue; // Raced with someone, retry.
+ }
+ // Successfully consumed a wakeup, we're done.
+ return true;
+ }
+
+ // Nothing to consume, wait (looping on EINTR).
+ while (true) {
+ if (!t.has_timeout()) {
+ if (sem_wait(&sem_) == 0) break;
+ if (errno == EINTR) continue;
+ ABSL_RAW_LOG(FATAL, "sem_wait failed: %d", errno);
+ } else {
+ if (sem_timedwait(&sem_, &abs_timeout) == 0) break;
+ if (errno == EINTR) continue;
+ if (errno == ETIMEDOUT) return false;
+ ABSL_RAW_LOG(FATAL, "sem_timedwait failed: %d", errno);
+ }
+ }
+ MaybeBecomeIdle();
+ }
+}
+
+void Waiter::Post() {
+ wakeups_.fetch_add(1, std::memory_order_release); // Post a wakeup.
+ Poke();
+}
+
+void Waiter::Poke() {
+ if (sem_post(&sem_) != 0) { // Wake any semaphore waiter.
+ ABSL_RAW_LOG(FATAL, "sem_post failed with errno %d\n", errno);
+ }
+}
+
+#elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_WIN32
+
+class LockHolder {
+ public:
+ explicit LockHolder(SRWLOCK* mu) : mu_(mu) {
+ AcquireSRWLockExclusive(mu_);
+ }
+
+ LockHolder(const LockHolder&) = delete;
+ LockHolder& operator=(const LockHolder&) = delete;
+
+ ~LockHolder() {
+ ReleaseSRWLockExclusive(mu_);
+ }
+
+ private:
+ SRWLOCK* mu_;
+};
+
+void Waiter::Init() {
+ InitializeSRWLock(&mu_);
+ InitializeConditionVariable(&cv_);
+ waiter_count_.store(0, std::memory_order_relaxed);
+ wakeup_count_.store(0, std::memory_order_relaxed);
+}
+
+bool Waiter::Wait(KernelTimeout t) {
+ LockHolder h(&mu_);
+ waiter_count_.fetch_add(1, std::memory_order_relaxed);
+
+ // Loop until we find a wakeup to consume or timeout.
+ while (true) {
+ int x = wakeup_count_.load(std::memory_order_relaxed);
+ if (x != 0) {
+ if (!wakeup_count_.compare_exchange_weak(x, x - 1,
+ std::memory_order_acquire,
+ std::memory_order_relaxed)) {
+ continue; // Raced with someone, retry.
+ }
+ // Successfully consumed a wakeup, we're done.
+ waiter_count_.fetch_sub(1, std::memory_order_relaxed);
+ return true;
+ }
+
+ // No wakeups available, time to wait.
+ if (!SleepConditionVariableSRW(
+ &cv_, &mu_, t.InMillisecondsFromNow(), 0)) {
+ // GetLastError() returns a Win32 DWORD, but we assign to
+ // unsigned long to simplify the ABSL_RAW_LOG case below. The uniform
+ // initialization guarantees this is not a narrowing conversion.
+ const unsigned long err{GetLastError()}; // NOLINT(runtime/int)
+ if (err == ERROR_TIMEOUT) {
+ waiter_count_.fetch_sub(1, std::memory_order_relaxed);
+ return false;
+ } else {
+ ABSL_RAW_LOG(FATAL, "SleepConditionVariableSRW failed: %lu", err);
+ }
+ }
+
+ MaybeBecomeIdle();
+ }
+}
+
+void Waiter::Post() {
+ wakeup_count_.fetch_add(1, std::memory_order_release);
+ Poke();
+}
+
+void Waiter::Poke() {
+ if (waiter_count_.load(std::memory_order_relaxed) == 0) {
+ return;
+ }
+ // Potentially a waker. Take the lock and check again.
+ LockHolder h(&mu_);
+ if (waiter_count_.load(std::memory_order_relaxed) == 0) {
+ return;
+ }
+ WakeConditionVariable(&cv_);
+}
+
+#else
+#error Unknown ABSL_WAITER_MODE
+#endif
+
+} // namespace synchronization_internal
+} // namespace absl
http://git-wip-us.apache.org/repos/asf/marmotta/blob/0eb556da/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/internal/waiter.h
----------------------------------------------------------------------
diff --git a/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/internal/waiter.h b/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/internal/waiter.h
new file mode 100644
index 0000000..23166f4
--- /dev/null
+++ b/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/internal/waiter.h
@@ -0,0 +1,139 @@
+// Copyright 2017 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
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef ABSL_SYNCHRONIZATION_INTERNAL_WAITER_H_
+#define ABSL_SYNCHRONIZATION_INTERNAL_WAITER_H_
+
+#include "absl/base/config.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <pthread.h>
+#endif
+
+#ifdef ABSL_HAVE_SEMAPHORE_H
+#include <semaphore.h>
+#endif
+
+#include <atomic>
+#include <cstdint>
+
+#include "absl/base/internal/thread_identity.h"
+#include "absl/synchronization/internal/kernel_timeout.h"
+
+// May be chosen at compile time via -DABSL_FORCE_WAITER_MODE=<index>
+#define ABSL_WAITER_MODE_FUTEX 0
+#define ABSL_WAITER_MODE_SEM 1
+#define ABSL_WAITER_MODE_CONDVAR 2
+#define ABSL_WAITER_MODE_WIN32 3
+
+#if defined(ABSL_FORCE_WAITER_MODE)
+#define ABSL_WAITER_MODE ABSL_FORCE_WAITER_MODE
+#elif defined(_WIN32)
+#define ABSL_WAITER_MODE ABSL_WAITER_MODE_WIN32
+#elif defined(__linux__)
+#define ABSL_WAITER_MODE ABSL_WAITER_MODE_FUTEX
+#elif defined(ABSL_HAVE_SEMAPHORE_H)
+#define ABSL_WAITER_MODE ABSL_WAITER_MODE_SEM
+#else
+#define ABSL_WAITER_MODE ABSL_WAITER_MODE_CONDVAR
+#endif
+
+namespace absl {
+namespace synchronization_internal {
+
+// Waiter is an OS-specific semaphore.
+class Waiter {
+ public:
+ // No constructor, instances use the reserved space in ThreadIdentity.
+ // All initialization logic belongs in `Init()`.
+ Waiter() = delete;
+ Waiter(const Waiter&) = delete;
+ Waiter& operator=(const Waiter&) = delete;
+
+ // Prepare any data to track waits.
+ void Init();
+
+ // Blocks the calling thread until a matching call to `Post()` or
+ // `t` has passed. Returns `true` if woken (`Post()` called),
+ // `false` on timeout.
+ bool Wait(KernelTimeout t);
+
+ // Restart the caller of `Wait()` as with a normal semaphore.
+ void Post();
+
+ // If anyone is waiting, wake them up temporarily and cause them to
+ // call `MaybeBecomeIdle()`. They will then return to waiting for a
+ // `Post()` or timeout.
+ void Poke();
+
+ // Returns the Waiter associated with the identity.
+ static Waiter* GetWaiter(base_internal::ThreadIdentity* identity) {
+ static_assert(
+ sizeof(Waiter) <= sizeof(base_internal::ThreadIdentity::WaiterState),
+ "Insufficient space for Waiter");
+ return reinterpret_cast<Waiter*>(identity->waiter_state.data);
+ }
+
+ // How many periods to remain idle before releasing resources
+#ifndef THREAD_SANITIZER
+ static const int kIdlePeriods = 60;
+#else
+ // Memory consumption under ThreadSanitizer is a serious concern,
+ // so we release resources sooner. The value of 1 leads to 1 to 2 second
+ // delay before marking a thread as idle.
+ static const int kIdlePeriods = 1;
+#endif
+
+ private:
+#if ABSL_WAITER_MODE == ABSL_WAITER_MODE_FUTEX
+ // Futexes are defined by specification to be 32-bits.
+ // Thus std::atomic<int32_t> must be just an int32_t with lockfree methods.
+ std::atomic<int32_t> futex_;
+ static_assert(sizeof(int32_t) == sizeof(futex_), "Wrong size for futex");
+
+#elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_CONDVAR
+ pthread_mutex_t mu_;
+ pthread_cond_t cv_;
+ std::atomic<int> waiter_count_;
+ std::atomic<int> wakeup_count_; // Unclaimed wakeups, written under lock.
+
+#elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_SEM
+ sem_t sem_;
+ // This seems superfluous, but for Poke() we need to cause spurious
+ // wakeups on the semaphore. Hence we can't actually use the
+ // semaphore's count.
+ std::atomic<int> wakeups_;
+
+#elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_WIN32
+ // The Windows API has lots of choices for synchronization
+ // primivitives. We are using SRWLOCK and CONDITION_VARIABLE
+ // because they don't require a destructor to release system
+ // resources.
+ SRWLOCK mu_;
+ CONDITION_VARIABLE cv_;
+ std::atomic<int> waiter_count_;
+ std::atomic<int> wakeup_count_;
+
+#else
+ #error Unknown ABSL_WAITER_MODE
+#endif
+};
+
+} // namespace synchronization_internal
+} // namespace absl
+
+#endif // ABSL_SYNCHRONIZATION_INTERNAL_WAITER_H_
http://git-wip-us.apache.org/repos/asf/marmotta/blob/0eb556da/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/lifetime_test.cc
----------------------------------------------------------------------
diff --git a/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/lifetime_test.cc b/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/lifetime_test.cc
new file mode 100644
index 0000000..90c9009
--- /dev/null
+++ b/libraries/ostrich/backend/3rdparty/abseil/absl/synchronization/lifetime_test.cc
@@ -0,0 +1,132 @@
+// Copyright 2017 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
+//
+// http://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 <cstdlib>
+#include <thread> // NOLINT(build/c++11), Abseil test
+#include <type_traits>
+
+#include "absl/base/attributes.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/thread_annotations.h"
+#include "absl/synchronization/mutex.h"
+#include "absl/synchronization/notification.h"
+
+namespace {
+
+// A two-threaded test which checks that Mutex, CondVar, and Notification have
+// correct basic functionality. The intent is to establish that they
+// function correctly in various phases of construction and destruction.
+//
+// Thread one acquires a lock on 'mutex', wakes thread two via 'notification',
+// then waits for 'state' to be set, as signalled by 'condvar'.
+//
+// Thread two waits on 'notification', then sets 'state' inside the 'mutex',
+// signalling the change via 'condvar'.
+//
+// These tests use ABSL_RAW_CHECK to validate invariants, rather than EXPECT or
+// ASSERT from gUnit, because we need to invoke them during global destructors,
+// when gUnit teardown would have already begun.
+void ThreadOne(absl::Mutex* mutex, absl::CondVar* condvar,
+ absl::Notification* notification, bool* state) {
+ // Test that the notification is in a valid initial state.
+ ABSL_RAW_CHECK(!notification->HasBeenNotified(), "invalid Notification");
+ ABSL_RAW_CHECK(*state == false, "*state not initialized");
+
+ {
+ absl::MutexLock lock(mutex);
+
+ notification->Notify();
+ ABSL_RAW_CHECK(notification->HasBeenNotified(), "invalid Notification");
+
+ while (*state == false) {
+ condvar->Wait(mutex);
+ }
+ }
+}
+
+void ThreadTwo(absl::Mutex* mutex, absl::CondVar* condvar,
+ absl::Notification* notification, bool* state) {
+ ABSL_RAW_CHECK(*state == false, "*state not initialized");
+
+ // Wake thread one
+ notification->WaitForNotification();
+ ABSL_RAW_CHECK(notification->HasBeenNotified(), "invalid Notification");
+ {
+ absl::MutexLock lock(mutex);
+ *state = true;
+ condvar->Signal();
+ }
+}
+
+// Launch thread 1 and thread 2, and block on their completion.
+// If any of 'mutex', 'condvar', or 'notification' is nullptr, use a locally
+// constructed instance instead.
+void RunTests(absl::Mutex* mutex, absl::CondVar* condvar,
+ absl::Notification* notification) {
+ absl::Mutex default_mutex;
+ absl::CondVar default_condvar;
+ absl::Notification default_notification;
+ if (!mutex) {
+ mutex = &default_mutex;
+ }
+ if (!condvar) {
+ condvar = &default_condvar;
+ }
+ if (!notification) {
+ notification = &default_notification;
+ }
+ bool state = false;
+ std::thread thread_one(ThreadOne, mutex, condvar, notification, &state);
+ std::thread thread_two(ThreadTwo, mutex, condvar, notification, &state);
+ thread_one.join();
+ thread_two.join();
+}
+
+void TestLocals() {
+ absl::Mutex mutex;
+ absl::CondVar condvar;
+ absl::Notification notification;
+ RunTests(&mutex, &condvar, ¬ification);
+}
+
+// Global variables during start and termination
+//
+// In a translation unit, static storage duration variables are initialized in
+// the order of their definitions, and destroyed in the reverse order of their
+// definitions. We can use this to arrange for tests to be run on these objects
+// before they are created, and after they are destroyed.
+
+using Function = void (*)();
+
+class OnConstruction {
+ public:
+ explicit OnConstruction(Function fn) { fn(); }
+};
+
+class OnDestruction {
+ public:
+ explicit OnDestruction(Function fn) : fn_(fn) {}
+ ~OnDestruction() { fn_(); }
+ private:
+ Function fn_;
+};
+
+} // namespace
+
+int main() {
+ TestLocals();
+ // Explicitly call exit(0) here, to make it clear that we intend for the
+ // above global object destructors to run.
+ std::exit(0);
+}