Files
swift-mirror/include/swift/Runtime/Mutex.h
Shawn Erickson 16c39d92f1 [runtime] predicate the use of constexpr on what the platform can support
At the moment CYGWIN pthreads implementation doesn't support the use of constexpr for static allocation versions. The way they define things results in a reinterpret_cast which violates constexpr.
2016-04-22 11:45:03 -07:00

801 lines
28 KiB
C++

//===--- Mutex.h - Mutex, ConditionVariable, & ReadWriteLock ----*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// Mutex, ConditionVariable, Read/Write lock, and Scoped lock abstractions
// for use in Swift runtime.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_RUNTIME_MUTEX_H
#define SWIFT_RUNTIME_MUTEX_H
#include <type_traits>
#if (defined(__APPLE__) || defined(__linux__) || defined(__CYGWIN__) || defined(__FreeBSD__))
#include "swift/Runtime/MutexPThread.h"
#else
#error "Implement equvalent of MutexPThread.h/cpp for your platform."
#endif
namespace swift {
/// A ConditionVariable that works with Mutex to allow -- as an example --
/// multi-threaded producers and consumers to signal each other in a safe way.
class ConditionVariable {
friend class Mutex;
ConditionVariable(const ConditionVariable &) = delete;
ConditionVariable &operator=(const ConditionVariable &) = delete;
ConditionVariable(ConditionVariable &&) = delete;
ConditionVariable &operator=(ConditionVariable &&) = delete;
public:
ConditionVariable() { ConditionPlatformHelper::init(Handle); }
~ConditionVariable() { ConditionPlatformHelper::destroy(Handle); }
/// Notifies one waiter (if any exists) that the condition has been met.
///
/// Note: To avoid missed notification it is best hold the related mutex
// lock when calling notifyOne.
void notifyOne() { ConditionPlatformHelper::notifyOne(Handle); }
/// Notifies all waiters (if any exists) that the condition has been met.
///
/// Note: To avoid missed notification it is best hold the related mutex
// lock when calling notifyAll.
void notifyAll() { ConditionPlatformHelper::notifyAll(Handle); }
private:
ConditionHandle Handle;
};
/// A Mutex object that supports `BasicLockable` and `Lockable` C++ concepts.
/// See http://en.cppreference.com/w/cpp/concept/BasicLockable
/// See http://en.cppreference.com/w/cpp/concept/Lockable
///
/// This is NOT a recursive mutex.
class Mutex {
Mutex(const Mutex &) = delete;
Mutex &operator=(const Mutex &) = delete;
Mutex(Mutex &&) = delete;
Mutex &operator=(Mutex &&) = delete;
public:
/// Constructs a non-recursive mutex.
///
/// If `checked` is true the mutex will attempt to check for misuse and
/// fatalError when detected. If `checked` is false (the default) the
/// mutex will make little to no effort to check for misuse (more efficient).
explicit Mutex(bool checked = false) {
MutexPlatformHelper::init(Handle, checked);
}
~Mutex() { MutexPlatformHelper::destroy(Handle); }
/// The lock() method has the following properties:
/// - Behaves as an atomic operation.
/// - Blocks the calling thread until exclusive ownership of the mutex
/// can be obtained.
/// - Prior m.unlock() operations on the same mutex synchronize-with
/// this lock operation.
/// - The behavior is undefined if the calling thread already owns
/// the mutex (likely a deadlock).
/// - Does not throw exceptions but will halt on error (fatalError).
void lock() { MutexPlatformHelper::lock(Handle); }
/// The unlock() method has the following properties:
/// - Behaves as an atomic operation.
/// - Releases the calling thread's ownership of the mutex and
/// synchronizes-with the subsequent successful lock operations on
/// the same object.
/// - The behavior is undefined if the calling thread does not own
/// the mutex.
/// - Does not throw exceptions but will halt on error (fatalError).
void unlock() { MutexPlatformHelper::unlock(Handle); }
/// The try_lock() method has the following properties:
/// - Behaves as an atomic operation.
/// - Attempts to obtain exclusive ownership of the mutex for the calling
/// thread without blocking. If ownership is not obtained, returns
/// immediately. The function is allowed to spuriously fail and return
/// even if the mutex is not currently owned by another thread.
/// - If try_lock() succeeds, prior unlock() operations on the same object
/// synchronize-with this operation. lock() does not synchronize with a
/// failed try_lock()
/// - The behavior is undefined if the calling thread already owns
/// the mutex (likely a deadlock)?
/// - Does not throw exceptions but will halt on error (fatalError).
bool try_lock() { return MutexPlatformHelper::try_lock(Handle); }
/// Releases lock, waits on supplied condition, and relocks before returning.
///
/// Precondition: Mutex held by this thread, undefined otherwise.
void wait(ConditionVariable &condition) {
ConditionPlatformHelper::wait(condition.Handle, Handle);
}
/// Acquires lock before calling the supplied critical section and releases
/// lock on return from critical section.
///
/// This call can block while waiting for the lock to become available.
///
/// For example the following mutates value while holding the mutex lock.
///
/// ```
/// mutex.lock([&value] { value++; });
/// ```
///
/// Precondition: Mutex not held by this thread, undefined otherwise.
template <typename CriticalSection>
void lock(CriticalSection criticalSection) {
lock();
criticalSection();
unlock();
}
/// Acquires lock before calling the supplied critical section. If critical
/// section returns `false` then it will wait on the supplied condition and
/// call the critical section again when wait returns (after acquiring lock).
/// If critical section returns `true` (done) it will no longer wait, it
/// will release the lock and return (lockOrWait returns to caller).
///
/// This call can block while waiting for the lock to become available.
///
/// For example the following will loop waiting on the condition until
/// `value > 0`. It will then "consume" that value and stop looping.
/// ...all while being correctly protected by mutex.
///
/// ```
/// mutex.lockOrWait(condition, [&value] {
/// if (value > 0) {
/// value--;
/// return true;
/// }
/// return false;
/// });
/// ```
///
/// Precondition: Mutex not held by this thread, undefined otherwise.
template <typename CriticalSection>
void lockOrWait(ConditionVariable &condition,
CriticalSection criticalSection) {
lock([&] {
while (!criticalSection()) {
wait(condition);
}
});
}
/// Acquires lock before calling the supplied critical section and on return
/// from critical section it notifies one waiter of supplied condition and
/// then releases the lock.
///
/// This call can block while waiting for the lock to become available.
///
/// For example the following mutates value while holding the mutex lock and
/// then notifies one condition waiter about this change.
///
/// ```
/// mutex.lockAndNotifyOne([&value] { value++; });
/// ```
///
/// Precondition: Mutex not held by this thread, undefined otherwise.
template <typename CriticalSection>
void lockAndNotifyOne(ConditionVariable &condition,
CriticalSection criticalSection) {
lock([&] {
criticalSection();
condition.notifyOne();
});
}
/// Acquires lock before calling the supplied critical section and on return
/// from critical section it notifies all waiters of supplied condition and
/// then releases the lock.
///
/// This call can block while waiting for the lock to become available.
///
/// For example the following mutates value while holding the mutex lock and
/// then notifies all condition waiters about this change.
///
/// ```
/// mutex.lockAndNotifyAll([&value] { value++; });
/// ```
///
/// Precondition: Mutex not held by this thread, undefined otherwise.
template <typename CriticalSection>
void lockAndNotifyAll(ConditionVariable &condition,
CriticalSection criticalSection) {
lock([&] {
criticalSection();
condition.notifyAll();
});
}
private:
MutexHandle Handle;
};
/// A Read / Write lock object that has semantics similar to `BasicLockable`
/// and `Lockable` C++ concepts however it supports multiple concurrent
/// threads holding the reader lock as long as the write lock isn't held and
/// only one thread can hold the write local at the same time.
///
/// If you need static allocated ReadWriteLock use StaticReadWriteLock.
///
/// See http://en.cppreference.com/w/cpp/concept/BasicLockable
/// See http://en.cppreference.com/w/cpp/concept/Lockable
///
/// This is NOT a recursive mutex.
class ReadWriteLock {
ReadWriteLock(const ReadWriteLock &) = delete;
ReadWriteLock &operator=(const ReadWriteLock &) = delete;
ReadWriteLock(ReadWriteLock &&) = delete;
ReadWriteLock &operator=(ReadWriteLock &&) = delete;
public:
ReadWriteLock() { ReadWriteLockPlatformHelper::init(Handle); }
~ReadWriteLock() { ReadWriteLockPlatformHelper::destroy(Handle); }
/// The readLock() method has the following properties:
/// - Behaves as an atomic operation.
/// - Blocks the calling thread while the write lock is held by another
/// thread and once the read lock is acquired by the calling thread
/// other threads are prevented from acquiring the write lock.
/// - Multiple threads can hold the read lock at the same time.
/// - Prior unlock() operations on the same lock synchronize-with
/// this lock operation.
/// - The behavior is undefined if the calling thread already owns
/// the read or write lock (likely a deadlock).
/// - Does not throw exceptions but will halt on error (fatalError).
///
/// Callers must not mutate the data protected by the ReadWriteLock while
/// holding the read lock, the write lock must be used.
void readLock() { ReadWriteLockPlatformHelper::readLock(Handle); }
/// The try_readLock() method has the following properties:
/// - Behaves as an atomic operation.
/// - Attempts to obtain the read lock without blocking the calling thread.
/// If ownership is not obtained, returns immediately. The function is
/// allowed to spuriously fail and return even if the lock is not
/// currently owned by another thread.
/// - If try_readLock() succeeds, prior unlock() operations on the same
/// object synchronize-with this operation. unlock() does not synchronize
/// with a failed try_readLock().
/// - The behavior is undefined if the calling thread already owns
/// the read or write lock (likely a deadlock)?
/// - Does not throw exceptions but will halt on error (fatalError).
///
/// Callers must not mutate the data protected by the ReadWriteLock while
/// holding the read lock, the write lock must be used.
bool try_readLock() {
return ReadWriteLockPlatformHelper::try_readLock(Handle);
}
/// The readUnlock() method has the following properties:
/// - Behaves as an atomic operation.
/// - Releases the calling thread's ownership of the read lock
/// and synchronizes-with the subsequent successful lock operations on
/// the same object.
/// - The behavior is undefined if the calling thread does not own
/// the read lock.
/// - Does not throw exceptions but will halt on error (fatalError).
void readUnlock() { ReadWriteLockPlatformHelper::readUnlock(Handle); }
/// The writeLock() method has the following properties:
/// - Behaves as an atomic operation.
/// - Blocks the calling thread while the write lock or a read lock is held
/// by another thread and once the write lock is acquired by the calling
/// thread other threads are prevented from acquiring the write lock or a
/// read lock.
/// - Only one thread can hold the write lock at the same time.
/// - Prior unlock() operations on the same lock synchronize-with
/// this lock operation.
/// - The behavior is undefined if the calling thread already owns
/// the read or write lock (likely a deadlock).
/// - Does not throw exceptions but will halt on error (fatalError).
void writeLock() { ReadWriteLockPlatformHelper::writeLock(Handle); }
/// The try_writeLock() method has the following properties:
/// - Behaves as an atomic operation.
/// - Attempts to obtain the write lock without blocking the calling thread.
/// If ownership is not obtained, returns immediately. The function is
/// allowed to spuriously fail and return even if the lock is not
/// currently owned by another thread.
/// - If try_writeLock() succeeds, prior unlock() operations on the same
/// object synchronize-with this operation. unlock() does not synchronize
/// with a failed try_writeLock().
/// - The behavior is undefined if the calling thread already owns
/// the read or write lock (likely a deadlock)?
/// - Does not throw exceptions but will halt on error (fatalError).
bool try_writeLock() {
return ReadWriteLockPlatformHelper::try_writeLock(Handle);
}
/// The writeUnlock() method has the following properties:
/// - Behaves as an atomic operation.
/// - Releases the calling thread's ownership of the write lock
/// and synchronizes-with the subsequent successful lock operations on
/// the same object.
/// - The behavior is undefined if the calling thread does not own
/// the write lock.
/// - Does not throw exceptions but will halt on error (fatalError).
void writeUnlock() { ReadWriteLockPlatformHelper::writeUnlock(Handle); }
/// Acquires read lock before calling the supplied critical section and
/// releases lock on return from critical section. Callers must not mutate
/// the data protected by the ReadWriteLock while holding the read lock, the
/// write lock must be used.
///
/// This call can block while waiting for the lock to become available.
///
/// For example the following reads the cached value while holding
/// the read lock.
///
/// ```
/// rw.readLock([&value] { value = cachedValue; });
/// ```
///
/// Precondition: ReadWriteLock not held by this thread, undefined otherwise.
template <typename CriticalSection>
void readLock(CriticalSection criticalSection) {
readLock();
criticalSection();
readUnlock();
}
/// Acquires write lock before calling the supplied critical section and
/// releases lock on return from critical section.
///
/// This call can block while waiting for the lock to become available.
///
/// For example the following updates the cached value while holding
/// the write lock.
///
/// ```
/// rw.writeLock([&newValue] { cachedValue = newValue });
/// ```
///
/// Precondition: ReadWriteLock not held by this thread, undefined otherwise.
template <typename CriticalSection>
void writeLock(CriticalSection criticalSection) {
writeLock();
criticalSection();
writeUnlock();
}
/// Acquires read lock before calling the read critical section and if
/// the critical section returns `true` (done) readWriteLock returns to the
/// caller. If the read critical section returns `false` the read lock
/// will be dropped, the write lock will be acquired and then the read
/// critical section will be called again. Then if the critical section
/// returns `true` (done) readWriteLock returns to the caller. If the read
/// critical section returns `false` then the write critical section will
/// be called (with write lock still held).
///
/// Note in all situations on return to caller the ReadWriteLock will
/// not be held.
///
/// For example the following attempts to get a cachedValue if it exists
/// if not found it will create the needed cachedValue.
///
/// ```
/// rw.readWriteLock(
/// [&value] {
/// if (cachedValue) {
/// value = cachedValue;
/// return true;
/// }
/// return false;
/// },
/// [&value] {
/// cachedValue = createValue();
/// value = cachedValue;
/// });
/// ```
///
/// Precondition: ReadWriteLock not held by this thread, undefined otherwise.
template <typename ReadonlySection, typename WriteSection>
void readWriteLock(ReadonlySection readSection, WriteSection writeSection) {
bool done;
readLock([&done, &readSection] { done = readSection(); });
if (!done) {
writeLock([&readSection, &writeSection] {
if (!readSection()) {
writeSection();
}
});
}
}
private:
ReadWriteLockHandle Handle;
};
/// A static allocation variant of ConditionVariable.
///
/// Use ConditionVariable instead unless you need static allocation.
class StaticConditionVariable {
friend class StaticMutex;
StaticConditionVariable(const StaticConditionVariable &) = delete;
StaticConditionVariable &operator=(const StaticConditionVariable &) = delete;
StaticConditionVariable(StaticConditionVariable &&) = delete;
StaticConditionVariable &operator=(StaticConditionVariable &&) = delete;
public:
#if CONDITION_SUPPORTS_CONSTEXPR
constexpr
#endif
StaticConditionVariable()
: Handle(ConditionPlatformHelper::staticInit()) {
}
/// See ConditionVariable::notifyOne
void notifyOne() { ConditionPlatformHelper::notifyOne(Handle); }
/// See ConditionVariable::notifyAll
void notifyAll() { ConditionPlatformHelper::notifyAll(Handle); }
private:
ConditionHandle Handle;
};
/// A static allocation variant of Mutex.
///
/// Use Mutex instead unless you need static allocation.
class StaticMutex {
StaticMutex(const StaticMutex &) = delete;
StaticMutex &operator=(const StaticMutex &) = delete;
StaticMutex(StaticMutex &&) = delete;
StaticMutex &operator=(StaticMutex &&) = delete;
public:
#if MUTEX_SUPPORTS_CONSTEXPR
constexpr
#endif
StaticMutex()
: Handle(MutexPlatformHelper::staticInit()) {
}
/// See Mutex::lock
void lock() { MutexPlatformHelper::lock(Handle); }
/// See Mutex::unlock
void unlock() { MutexPlatformHelper::unlock(Handle); }
/// See Mutex::try_lock
bool try_lock() { return MutexPlatformHelper::try_lock(Handle); }
/// See Mutex::wait
void wait(StaticConditionVariable &condition) {
ConditionPlatformHelper::wait(condition.Handle, Handle);
}
/// See Mutex::lock
template <typename CriticalSection>
void lock(CriticalSection criticalSection) {
lock();
criticalSection();
unlock();
}
/// See Mutex::lockOrWait
template <typename CriticalSection>
void lockOrWait(StaticConditionVariable &condition,
CriticalSection criticalSection) {
lock([&] {
while (!criticalSection()) {
wait(condition);
}
});
}
/// See Mutex::lockAndNotifyOne
template <typename CriticalSection>
void lockAndNotifyOne(StaticConditionVariable &condition,
CriticalSection criticalSection) {
lock([&] {
criticalSection();
condition.notifyOne();
});
}
/// See Mutex::lockAndNotifyAll
template <typename CriticalSection>
void lockAndNotifyAll(StaticConditionVariable &condition,
CriticalSection criticalSection) {
lock([&] {
criticalSection();
condition.notifyAll();
});
}
private:
MutexHandle Handle;
};
/// A static allocation variant of ReadWriteLock.
///
/// Use ReadWriteLock instead unless you need static allocation.
class StaticReadWriteLock {
StaticReadWriteLock(const StaticReadWriteLock &) = delete;
StaticReadWriteLock &operator=(const StaticReadWriteLock &) = delete;
StaticReadWriteLock(StaticReadWriteLock &&) = delete;
StaticReadWriteLock &operator=(StaticReadWriteLock &&) = delete;
public:
#if READWRITELOCK_SUPPORTS_CONSTEXPR
constexpr
#endif
StaticReadWriteLock()
: Handle(ReadWriteLockPlatformHelper::staticInit()) {
}
/// See ReadWriteLock::readLock
void readLock() { ReadWriteLockPlatformHelper::readLock(Handle); }
/// See ReadWriteLock::try_readLock
bool try_readLock() {
return ReadWriteLockPlatformHelper::try_readLock(Handle);
}
/// See ReadWriteLock::readUnlock
void readUnlock() { ReadWriteLockPlatformHelper::readUnlock(Handle); }
/// See ReadWriteLock::writeLock
void writeLock() { ReadWriteLockPlatformHelper::writeLock(Handle); }
/// See ReadWriteLock::try_writeLock
bool try_writeLock() {
return ReadWriteLockPlatformHelper::try_writeLock(Handle);
}
/// See ReadWriteLock::writeUnlock
void writeUnlock() { ReadWriteLockPlatformHelper::writeUnlock(Handle); }
/// See ReadWriteLock::readLock
template <typename CriticalSection>
void readLock(CriticalSection criticalSection) {
readLock();
criticalSection();
readUnlock();
}
/// See ReadWriteLock::writeLock
template <typename CriticalSection>
void writeLock(CriticalSection criticalSection) {
writeLock();
criticalSection();
writeUnlock();
}
/// See ReadWriteLock::readWriteLock
template <typename ReadonlySection, typename WriteSection>
void readWriteLock(ReadonlySection readSection, WriteSection writeSection) {
bool done;
readLock([&done, &readSection] { done = readSection(); });
if (!done) {
writeLock([&readSection, &writeSection] {
if (!readSection()) {
writeSection();
}
});
}
}
private:
ReadWriteLockHandle Handle;
};
/// A Mutex object that supports `BasicLockable` C++ concepts. It is
/// considered
/// unsafe to use because it doesn't do any error checking. It is only for
/// use in pathways that deal with reporting fatalErrors to avoid the
/// potential
/// for recursive fatalErrors that could happen if you used Mutex.
///
/// Always use Mutex, unless in the above mentioned error pathway situation.
class StaticUnsafeMutex {
StaticUnsafeMutex(const StaticUnsafeMutex &) = delete;
StaticUnsafeMutex &operator=(const StaticUnsafeMutex &) = delete;
StaticUnsafeMutex(StaticUnsafeMutex &&) = delete;
StaticUnsafeMutex &operator=(StaticUnsafeMutex &&) = delete;
public:
#if MUTEX_SUPPORTS_CONSTEXPR
constexpr
#endif
StaticUnsafeMutex()
: Handle(MutexPlatformHelper::staticInit()) {
}
/// The lock() method has the following properties:
/// - Behaves as an atomic operation.
/// - Blocks the calling thread until exclusive ownership of the mutex
/// can be obtained.
/// - Prior m.unlock() operations on the same mutex synchronize-with
/// this lock operation.
/// - The behavior is undefined if the calling thread already owns
/// the mutex (likely a deadlock).
/// - Ignores errors that may happen, undefined when an error happens.
void lock() { MutexPlatformHelper::unsafeLock(Handle); }
/// The unlock() method has the following properties:
/// - Behaves as an atomic operation.
/// - Releases the calling thread's ownership of the mutex and
/// synchronizes-with the subsequent successful lock operations on
/// the same object.
/// - The behavior is undefined if the calling thread does not own
/// the mutex.
/// - Ignores errors that may happen, undefined when an error happens.
void unlock() { MutexPlatformHelper::unsafeUnlock(Handle); }
private:
MutexHandle Handle;
};
/// Compile time adjusted stack based object that locks/unlocks the supplied
/// Mutex type. Use the provided typedefs instead of this directly.
template <typename T, bool Inverted> class ScopedLockT {
ScopedLockT() = delete;
ScopedLockT(const ScopedLockT &) = delete;
ScopedLockT &operator=(const ScopedLockT &) = delete;
ScopedLockT(ScopedLockT &&) = delete;
ScopedLockT &operator=(ScopedLockT &&) = delete;
public:
explicit ScopedLockT(T &l) : Lock(l) {
if (Inverted) {
Lock.unlock();
} else {
Lock.lock();
}
}
~ScopedLockT() {
if (Inverted) {
Lock.lock();
} else {
Lock.unlock();
}
}
private:
T &Lock;
};
/// A stack based object that locks the supplied mutex on construction
/// and unlocks it on destruction.
///
/// Precondition: Mutex unlocked by this thread, undefined otherwise.
typedef ScopedLockT<Mutex, false> ScopedLock;
typedef ScopedLockT<StaticMutex, false> StaticScopedLock;
/// A stack based object that unlocks the supplied mutex on construction
/// and relocks it on destruction.
///
/// Precondition: Mutex locked by this thread, undefined otherwise.
typedef ScopedLockT<Mutex, true> ScopedUnlock;
typedef ScopedLockT<StaticMutex, true> StaticScopedUnlock;
/// Compile time adjusted stack based object that locks/unlocks the supplied
/// ReadWriteLock type. Use the provided typedefs instead of this directly.
template <typename T, bool Read, bool Inverted> class ScopedRWLockT {
ScopedRWLockT() = delete;
ScopedRWLockT(const ScopedRWLockT &) = delete;
ScopedRWLockT &operator=(const ScopedRWLockT &) = delete;
ScopedRWLockT(ScopedRWLockT &&) = delete;
ScopedRWLockT &operator=(ScopedRWLockT &&) = delete;
public:
explicit ScopedRWLockT(T &l) : Lock(l) {
if (Inverted) {
if (Read) {
Lock.readUnlock();
} else {
Lock.writeUnlock();
}
} else {
if (Read) {
Lock.readLock();
} else {
Lock.writeLock();
}
}
}
~ScopedRWLockT() {
if (Inverted) {
if (Read) {
Lock.readLock();
} else {
Lock.writeLock();
}
} else {
if (Read) {
Lock.readUnlock();
} else {
Lock.writeUnlock();
}
}
}
private:
T &Lock;
};
/// A stack based object that unlocks the supplied ReadWriteLock on
/// construction and locks it for reading on destruction.
///
/// Precondition: ReadWriteLock unlocked by this thread, undefined otherwise.
typedef ScopedRWLockT<ReadWriteLock, true, false> ScopedReadLock;
typedef ScopedRWLockT<StaticReadWriteLock, true, false> StaticScopedReadLock;
/// A stack based object that unlocks the supplied ReadWriteLock on
/// construction and locks it for reading on destruction.
///
/// Precondition: ReadWriteLock unlocked by this thread, undefined
/// otherwise.
typedef ScopedRWLockT<ReadWriteLock, true, true> ScopedReadUnlock;
typedef ScopedRWLockT<StaticReadWriteLock, true, true> StaticScopedReadUnlock;
/// A stack based object that unlocks the supplied ReadWriteLock on
/// construction and locks it for reading on destruction.
///
/// Precondition: ReadWriteLock unlocked by this thread, undefined otherwise.
typedef ScopedRWLockT<ReadWriteLock, false, false> ScopedWriteLock;
typedef ScopedRWLockT<StaticReadWriteLock, false, false> StaticScopedWriteLock;
/// A stack based object that unlocks the supplied ReadWriteLock on
/// construction and locks it for writing on destruction.
///
/// Precondition: ReadWriteLock unlocked by this thread, undefined otherwise.
typedef ScopedRWLockT<ReadWriteLock, false, true> ScopedWriteUnlock;
typedef ScopedRWLockT<StaticReadWriteLock, false, true> StaticScopedWriteUnlock;
// Enforce literal requirements for static variants.
#if MUTEX_SUPPORTS_CONSTEXPR
static_assert(std::is_literal_type<StaticMutex>::value,
"StaticMutex must be literal type");
static_assert(std::is_literal_type<StaticUnsafeMutex>::value,
"StaticUnsafeMutex must be literal type");
#else
// Your platform doesn't currently support staticly allocated Mutex
// you will possibly see global-constructors warnings
#endif
#if CONDITION_SUPPORTS_CONSTEXPR
static_assert(std::is_literal_type<StaticConditionVariable>::value,
"StaticConditionVariable must be literal type");
#else
// Your platform doesn't currently support staticly allocated ConditionVar
// you will possibly see global-constructors warnings
#endif
#if READWRITELOCK_SUPPORTS_CONSTEXPR
static_assert(std::is_literal_type<StaticReadWriteLock>::value,
"StaticReadWriteLock must be literal type");
#else
// Your platform doesn't currently support staticly allocated ReadWriteLocks
// you will possibly see global-constructors warnings
#endif
}
#endif