tvl-depot/absl/synchronization/internal/mutex_nonprod.inc

262 lines
9.3 KiB
PHP
Raw Normal View History

2017-09-19 22:54:40 +02:00
// 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 {
Export of internal Abseil changes -- c99f979ad34f155fbeeea69b88bdc7458d89a21c by Derek Mauro <dmauro@google.com>: Remove a floating point division by zero test. This isn't testing behavior related to the library, and MSVC warns about it in opt mode. PiperOrigin-RevId: 285220804 -- 68b015491f0dbf1ab547994673281abd1f34cd4b by Gennadiy Rozental <rogeeff@google.com>: This CL introduces following changes to the class FlagImpl: * We eliminate the CommandLineFlagLocks struct. Instead callback guard and callback function are combined into a single CallbackData struct, while primary data lock is stored separately. * CallbackData member of class FlagImpl is initially set to be nullptr and is only allocated and initialized when a flag's callback is being set. For most flags we do not pay for the extra space and extra absl::Mutex now. * Primary data guard is stored in data_guard_ data member. This is a properly aligned character buffer of necessary size. During initialization of the flag we construct absl::Mutex in this space using placement new call. * We now avoid extra value copy after successful attempt to parse value out of string. Instead we swap flag's current value with tentative value we just produced. PiperOrigin-RevId: 285132636 -- ed45d118fb818969eb13094cf7827c885dfc562c by Tom Manshreck <shreck@google.com>: Change null-term* (and nul-term*) to NUL-term* in comments PiperOrigin-RevId: 285036610 -- 729619017944db895ce8d6d29c1995aa2e5628a5 by Derek Mauro <dmauro@google.com>: Use the Posix implementation of thread identity on MinGW. Some versions of MinGW suffer from thread_local bugs. PiperOrigin-RevId: 285022920 -- 39a25493503c76885bc3254c28f66a251c5b5bb0 by Greg Falcon <gfalcon@google.com>: Implementation detail change. Add further ABSL_NAMESPACE_BEGIN and _END annotation macros to files in Abseil. PiperOrigin-RevId: 285012012 GitOrigin-RevId: c99f979ad34f155fbeeea69b88bdc7458d89a21c Change-Id: I4c85d3704e45d11a9ac50d562f39640a6adbedc1
2019-12-12 19:36:03 +01:00
ABSL_NAMESPACE_BEGIN
2017-09-19 22:54:40 +02:00
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
2017-09-19 22:54:40 +02:00
// have a default constructor, which is called by the first call to
// get(). T's destructor is never called if the LinkerInitialized
2017-09-19 22:54:40 +02:00
// 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
2017-09-19 22:54:40 +02:00
// 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
2017-09-19 22:54:40 +02:00
// 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
2017-09-19 22:54:40 +02:00
// 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
2017-09-19 22:54:40 +02:00
// 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
2017-09-19 22:54:40 +02:00
// 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
2017-09-19 22:54:40 +02:00
// 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
2017-09-19 22:54:40 +02:00
// even to concurrent calls to get().
//
// c) the destructor being a NOP for LinkerInitialized objects
2017-09-19 22:54:40 +02:00
// (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) {}
2017-09-19 22:54:40 +02:00
Export of internal Abseil changes. -- 636137f6f0de910691a3950387fefacfa4909fb8 by Abseil Team <absl-team@google.com>: Add move semantics to absl::container_internal::CompressedTuple PiperOrigin-RevId: 225394165 -- 43da91e4f95a196b2e6b76f1c2f4158817b0ebb0 by Greg Falcon <gfalcon@google.com>: Add a constructor to allow for global absl::Mutex instances. This adds a new constexpr constructor to absl::Mutex, invoked with the absl::kConstInit tag value, which is intended to be used to construct Mutex instances with static storage duration. What's tricky about is absl::Mutex (like std::mutex) is not a trivially destructible class, so by the letter of the law, accessing a global Mutex instance after it is destroyed results in undefined behavior. Despite this, we take care in the destructor to not invalidate the memory layout of the Mutex. Using a kConstInit-constructed global Mutex after it is destroyed happens to work on the toolchains we use. Google relies heavily on this behavior internally. Code sanitizers that detect undefined behavior are able to notice use-after-free of globals, and might complain about this pattern. PiperOrigin-RevId: 225389447 -- 7b553a54bc6460cc7008b028552e66799475ca64 by Abseil Team <absl-team@google.com>: Internal change. PiperOrigin-RevId: 225373389 -- fd0c722d217b3b509102274765ccb1a0b596cf46 by Abseil Team <absl-team@google.com>: Update absl/time/CMakeLists.txt to use new functions i.e. absl_cc_(library|test) PiperOrigin-RevId: 225246853 -- 9f8f3ba3b67a6d1ac4ecdc529c8b8eb0f02576d9 by Abseil Team <absl-team@google.com>: Update absl/synchronisation/CMakeLists.txt to use new functions i.e. absl_cc_(library|test) PiperOrigin-RevId: 225237980 -- a3fdd67dad2e596f804f5e100c8d3a74d8064faa by Abseil Team <absl-team@google.com>: Internal cleanup PiperOrigin-RevId: 225226813 -- 48fab23fb8cdca45e95da14fce0de56614d09c25 by Jon Cohen <cohenjon@google.com>: Use a shim #define for wchar_t in msvc in int128. On ancient versions of msvc and with some compatibility flags on wchar_t is a typedef for unsigned short, whereas on standards-conforming versions wchar_t is a typedef for __wchar_t. The first situation causes int128 to not compile as you can't define both `operator wchar_t()` and `operator unsigned short()` because they are the same type. This CL introduces a wrapper #define in order to abstract over the different typedefs for wchar_t. We do a define instead of a typedef so that we can #undef at the end and not leak the symbol, since we need it in a header. https://docs.microsoft.com/en-us/previous-versions/dh8che7s(v=vs.140) has more detail about the underlying problem. PiperOrigin-RevId: 225223756 GitOrigin-RevId: 636137f6f0de910691a3950387fefacfa4909fb8 Change-Id: Iad94e52e9484c5acec115a2f09ef2d5ec22c2074
2018-12-13 19:30:03 +01:00
constexpr explicit SynchronizationStorage(absl::ConstInitType)
: is_dynamic_(false), once_(), space_{{0}} {}
2017-09-19 22:54:40 +02:00
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
2017-09-19 22:54:40 +02:00
// 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
2017-09-19 22:54:40 +02:00
// 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
Export of internal Abseil changes -- c99f979ad34f155fbeeea69b88bdc7458d89a21c by Derek Mauro <dmauro@google.com>: Remove a floating point division by zero test. This isn't testing behavior related to the library, and MSVC warns about it in opt mode. PiperOrigin-RevId: 285220804 -- 68b015491f0dbf1ab547994673281abd1f34cd4b by Gennadiy Rozental <rogeeff@google.com>: This CL introduces following changes to the class FlagImpl: * We eliminate the CommandLineFlagLocks struct. Instead callback guard and callback function are combined into a single CallbackData struct, while primary data lock is stored separately. * CallbackData member of class FlagImpl is initially set to be nullptr and is only allocated and initialized when a flag's callback is being set. For most flags we do not pay for the extra space and extra absl::Mutex now. * Primary data guard is stored in data_guard_ data member. This is a properly aligned character buffer of necessary size. During initialization of the flag we construct absl::Mutex in this space using placement new call. * We now avoid extra value copy after successful attempt to parse value out of string. Instead we swap flag's current value with tentative value we just produced. PiperOrigin-RevId: 285132636 -- ed45d118fb818969eb13094cf7827c885dfc562c by Tom Manshreck <shreck@google.com>: Change null-term* (and nul-term*) to NUL-term* in comments PiperOrigin-RevId: 285036610 -- 729619017944db895ce8d6d29c1995aa2e5628a5 by Derek Mauro <dmauro@google.com>: Use the Posix implementation of thread identity on MinGW. Some versions of MinGW suffer from thread_local bugs. PiperOrigin-RevId: 285022920 -- 39a25493503c76885bc3254c28f66a251c5b5bb0 by Greg Falcon <gfalcon@google.com>: Implementation detail change. Add further ABSL_NAMESPACE_BEGIN and _END annotation macros to files in Abseil. PiperOrigin-RevId: 285012012 GitOrigin-RevId: c99f979ad34f155fbeeea69b88bdc7458d89a21c Change-Id: I4c85d3704e45d11a9ac50d562f39640a6adbedc1
2019-12-12 19:36:03 +01:00
ABSL_NAMESPACE_END
2017-09-19 22:54:40 +02:00
} // namespace absl