freebsd-dev/contrib/libc++/include/mutex
Dimitry Andric d72607e9e2 Import libc++ trunk r224926. This fixes a number of bugs, completes
C++14 support[1], adds more C++1z features[2], and fixes the following
LWG issues[3]:

1450: Contradiction in regex_constants
2003: String exception inconsistency in erase.
2075: Progress guarantees, lock-free property, and scheduling
      assumptions
2104: unique_lock move-assignment should not be noexcept
2112: User-defined classes that cannot be derived from
2132: std::function ambiguity
2135: Unclear requirement for exceptions thrown in
      condition_variable::wait()
2142: packaged_task::operator() synchronization too broad?
2182: Container::[const_]reference types are misleadingly specified
2186: Incomplete action on async/launch::deferred
2188: Reverse iterator does not fully support targets that overload
      operator&
2193: Default constructors for standard library containers are explicit
2205: Problematic postconditions of regex_match and regex_search
2213: Return value of std::regex_replace
2240: Probable misuse of term "function scope" in [thread.condition]
2252: Strong guarantee on vector::push_back() still broken with C++11?
2257: Simplify container requirements with the new algorithms
2258: a.erase(q1, q2) unable to directly return q2
2263: Comparing iterators and allocator pointers with different
      const-character
2268: Setting a default argument in the declaration of a member
      function assign of std::basic_string
2271: regex_traits::lookup_classname specification unclear
2272: quoted should use char_traits::eq for character comparison
2278: User-defined literals for Standard Library types
2280: begin / end for arrays should be constexpr and noexcept
2285: make_reverse_iterator
2288: Inconsistent requirements for shared mutexes
2291: std::hash is vulnerable to collision DoS attack
2293: Wrong facet used by num_put::do_put
2299: Effects of inaccessible key_compare::is_transparent type are not
      clear
2301: Why is std::tie not constexpr?
2304: Complexity of count in unordered associative containers
2306: match_results::reference should be value_type&, not const
      value_type&
2308: Clarify container destructor requirements w.r.t. std::array
2313: tuple_size should always derive from integral_constant<size_t, N>
2314: apply() should return decltype(auto) and use decay_t before
      tuple_size
2315: weak_ptr should be movable
2316: weak_ptr::lock() should be atomic
2317: The type property queries should be UnaryTypeTraits returning
      size_t
2320: select_on_container_copy_construction() takes allocators, not
      containers
2322: Associative(initializer_list, stuff) constructors are
      underspecified
2323: vector::resize(n, t)'s specification should be simplified
2324: Insert iterator constructors should use addressof()
2329: regex_match()/regex_search() with match_results should forbid
      temporary strings
2330: regex("meow", regex::icase) is technically forbidden but should
      be permitted
2332: regex_iterator/regex_token_iterator should forbid temporary
      regexes
2339: Wording issue in nth_element
2341: Inconsistency between basic_ostream::seekp(pos) and
      basic_ostream::seekp(off, dir)
2344: quoted()'s interaction with padding is unclear
2346: integral_constant's member functions should be marked noexcept
2350: min, max, and minmax should be constexpr
2356: Stability of erasure in unordered associative containers
2357: Remaining "Assignable" requirement
2359: How does regex_constants::nosubs affect basic_regex::mark_count()?
2360: reverse_iterator::operator*() is unimplementable

[1] http://libcxx.llvm.org/cxx1y_status.html
[2] http://libcxx.llvm.org/cxx1z_status.html
[3] http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html

Exp-run:	antoine
MFC after:	1 month
2015-01-15 21:17:36 +00:00

572 lines
14 KiB
C++

// -*- C++ -*-
//===--------------------------- mutex ------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef _LIBCPP_MUTEX
#define _LIBCPP_MUTEX
/*
mutex synopsis
namespace std
{
class mutex
{
public:
constexpr mutex() noexcept;
~mutex();
mutex(const mutex&) = delete;
mutex& operator=(const mutex&) = delete;
void lock();
bool try_lock();
void unlock();
typedef pthread_mutex_t* native_handle_type;
native_handle_type native_handle();
};
class recursive_mutex
{
public:
recursive_mutex();
~recursive_mutex();
recursive_mutex(const recursive_mutex&) = delete;
recursive_mutex& operator=(const recursive_mutex&) = delete;
void lock();
bool try_lock() noexcept;
void unlock();
typedef pthread_mutex_t* native_handle_type;
native_handle_type native_handle();
};
class timed_mutex
{
public:
timed_mutex();
~timed_mutex();
timed_mutex(const timed_mutex&) = delete;
timed_mutex& operator=(const timed_mutex&) = delete;
void lock();
bool try_lock();
template <class Rep, class Period>
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
template <class Clock, class Duration>
bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
void unlock();
};
class recursive_timed_mutex
{
public:
recursive_timed_mutex();
~recursive_timed_mutex();
recursive_timed_mutex(const recursive_timed_mutex&) = delete;
recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
void lock();
bool try_lock() noexcept;
template <class Rep, class Period>
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
template <class Clock, class Duration>
bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
void unlock();
};
struct defer_lock_t {};
struct try_to_lock_t {};
struct adopt_lock_t {};
constexpr defer_lock_t defer_lock{};
constexpr try_to_lock_t try_to_lock{};
constexpr adopt_lock_t adopt_lock{};
template <class Mutex>
class lock_guard
{
public:
typedef Mutex mutex_type;
explicit lock_guard(mutex_type& m);
lock_guard(mutex_type& m, adopt_lock_t);
~lock_guard();
lock_guard(lock_guard const&) = delete;
lock_guard& operator=(lock_guard const&) = delete;
};
template <class Mutex>
class unique_lock
{
public:
typedef Mutex mutex_type;
unique_lock() noexcept;
explicit unique_lock(mutex_type& m);
unique_lock(mutex_type& m, defer_lock_t) noexcept;
unique_lock(mutex_type& m, try_to_lock_t);
unique_lock(mutex_type& m, adopt_lock_t);
template <class Clock, class Duration>
unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time);
template <class Rep, class Period>
unique_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time);
~unique_lock();
unique_lock(unique_lock const&) = delete;
unique_lock& operator=(unique_lock const&) = delete;
unique_lock(unique_lock&& u) noexcept;
unique_lock& operator=(unique_lock&& u) noexcept;
void lock();
bool try_lock();
template <class Rep, class Period>
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
template <class Clock, class Duration>
bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
void unlock();
void swap(unique_lock& u) noexcept;
mutex_type* release() noexcept;
bool owns_lock() const noexcept;
explicit operator bool () const noexcept;
mutex_type* mutex() const noexcept;
};
template <class Mutex>
void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y) noexcept;
template <class L1, class L2, class... L3>
int try_lock(L1&, L2&, L3&...);
template <class L1, class L2, class... L3>
void lock(L1&, L2&, L3&...);
struct once_flag
{
constexpr once_flag() noexcept;
once_flag(const once_flag&) = delete;
once_flag& operator=(const once_flag&) = delete;
};
template<class Callable, class ...Args>
void call_once(once_flag& flag, Callable&& func, Args&&... args);
} // std
*/
#include <__config>
#include <__mutex_base>
#include <functional>
#ifndef _LIBCPP_HAS_NO_VARIADICS
#include <tuple>
#endif
#include <sched.h>
#include <__undef_min_max>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#pragma GCC system_header
#endif
_LIBCPP_BEGIN_NAMESPACE_STD
#ifndef _LIBCPP_HAS_NO_THREADS
class _LIBCPP_TYPE_VIS recursive_mutex
{
pthread_mutex_t __m_;
public:
recursive_mutex();
~recursive_mutex();
private:
recursive_mutex(const recursive_mutex&); // = delete;
recursive_mutex& operator=(const recursive_mutex&); // = delete;
public:
void lock();
bool try_lock() _NOEXCEPT;
void unlock() _NOEXCEPT;
typedef pthread_mutex_t* native_handle_type;
_LIBCPP_INLINE_VISIBILITY
native_handle_type native_handle() {return &__m_;}
};
class _LIBCPP_TYPE_VIS timed_mutex
{
mutex __m_;
condition_variable __cv_;
bool __locked_;
public:
timed_mutex();
~timed_mutex();
private:
timed_mutex(const timed_mutex&); // = delete;
timed_mutex& operator=(const timed_mutex&); // = delete;
public:
void lock();
bool try_lock() _NOEXCEPT;
template <class _Rep, class _Period>
_LIBCPP_INLINE_VISIBILITY
bool try_lock_for(const chrono::duration<_Rep, _Period>& __d)
{return try_lock_until(chrono::steady_clock::now() + __d);}
template <class _Clock, class _Duration>
bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
void unlock() _NOEXCEPT;
};
template <class _Clock, class _Duration>
bool
timed_mutex::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
{
using namespace chrono;
unique_lock<mutex> __lk(__m_);
bool no_timeout = _Clock::now() < __t;
while (no_timeout && __locked_)
no_timeout = __cv_.wait_until(__lk, __t) == cv_status::no_timeout;
if (!__locked_)
{
__locked_ = true;
return true;
}
return false;
}
class _LIBCPP_TYPE_VIS recursive_timed_mutex
{
mutex __m_;
condition_variable __cv_;
size_t __count_;
pthread_t __id_;
public:
recursive_timed_mutex();
~recursive_timed_mutex();
private:
recursive_timed_mutex(const recursive_timed_mutex&); // = delete;
recursive_timed_mutex& operator=(const recursive_timed_mutex&); // = delete;
public:
void lock();
bool try_lock() _NOEXCEPT;
template <class _Rep, class _Period>
_LIBCPP_INLINE_VISIBILITY
bool try_lock_for(const chrono::duration<_Rep, _Period>& __d)
{return try_lock_until(chrono::steady_clock::now() + __d);}
template <class _Clock, class _Duration>
bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t);
void unlock() _NOEXCEPT;
};
template <class _Clock, class _Duration>
bool
recursive_timed_mutex::try_lock_until(const chrono::time_point<_Clock, _Duration>& __t)
{
using namespace chrono;
pthread_t __id = pthread_self();
unique_lock<mutex> lk(__m_);
if (pthread_equal(__id, __id_))
{
if (__count_ == numeric_limits<size_t>::max())
return false;
++__count_;
return true;
}
bool no_timeout = _Clock::now() < __t;
while (no_timeout && __count_ != 0)
no_timeout = __cv_.wait_until(lk, __t) == cv_status::no_timeout;
if (__count_ == 0)
{
__count_ = 1;
__id_ = __id;
return true;
}
return false;
}
template <class _L0, class _L1>
int
try_lock(_L0& __l0, _L1& __l1)
{
unique_lock<_L0> __u0(__l0, try_to_lock);
if (__u0.owns_lock())
{
if (__l1.try_lock())
{
__u0.release();
return -1;
}
else
return 1;
}
return 0;
}
#ifndef _LIBCPP_HAS_NO_VARIADICS
template <class _L0, class _L1, class _L2, class... _L3>
int
try_lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3)
{
int __r = 0;
unique_lock<_L0> __u0(__l0, try_to_lock);
if (__u0.owns_lock())
{
__r = try_lock(__l1, __l2, __l3...);
if (__r == -1)
__u0.release();
else
++__r;
}
return __r;
}
#endif // _LIBCPP_HAS_NO_VARIADICS
template <class _L0, class _L1>
void
lock(_L0& __l0, _L1& __l1)
{
while (true)
{
{
unique_lock<_L0> __u0(__l0);
if (__l1.try_lock())
{
__u0.release();
break;
}
}
sched_yield();
{
unique_lock<_L1> __u1(__l1);
if (__l0.try_lock())
{
__u1.release();
break;
}
}
sched_yield();
}
}
#ifndef _LIBCPP_HAS_NO_VARIADICS
template <class _L0, class _L1, class _L2, class ..._L3>
void
__lock_first(int __i, _L0& __l0, _L1& __l1, _L2& __l2, _L3& ...__l3)
{
while (true)
{
switch (__i)
{
case 0:
{
unique_lock<_L0> __u0(__l0);
__i = try_lock(__l1, __l2, __l3...);
if (__i == -1)
{
__u0.release();
return;
}
}
++__i;
sched_yield();
break;
case 1:
{
unique_lock<_L1> __u1(__l1);
__i = try_lock(__l2, __l3..., __l0);
if (__i == -1)
{
__u1.release();
return;
}
}
if (__i == sizeof...(_L3) + 1)
__i = 0;
else
__i += 2;
sched_yield();
break;
default:
__lock_first(__i - 2, __l2, __l3..., __l0, __l1);
return;
}
}
}
template <class _L0, class _L1, class _L2, class ..._L3>
inline _LIBCPP_INLINE_VISIBILITY
void
lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3& ...__l3)
{
__lock_first(0, __l0, __l1, __l2, __l3...);
}
#endif // _LIBCPP_HAS_NO_VARIADICS
#endif // !_LIBCPP_HAS_NO_THREADS
struct _LIBCPP_TYPE_VIS_ONLY once_flag;
#ifndef _LIBCPP_HAS_NO_VARIADICS
template<class _Callable, class... _Args>
_LIBCPP_INLINE_VISIBILITY
void call_once(once_flag&, _Callable&&, _Args&&...);
#else // _LIBCPP_HAS_NO_VARIADICS
template<class _Callable>
_LIBCPP_INLINE_VISIBILITY
void call_once(once_flag&, _Callable);
#endif // _LIBCPP_HAS_NO_VARIADICS
struct _LIBCPP_TYPE_VIS_ONLY once_flag
{
_LIBCPP_INLINE_VISIBILITY
_LIBCPP_CONSTEXPR
once_flag() _NOEXCEPT : __state_(0) {}
private:
once_flag(const once_flag&); // = delete;
once_flag& operator=(const once_flag&); // = delete;
unsigned long __state_;
#ifndef _LIBCPP_HAS_NO_VARIADICS
template<class _Callable, class... _Args>
friend
void call_once(once_flag&, _Callable&&, _Args&&...);
#else // _LIBCPP_HAS_NO_VARIADICS
template<class _Callable>
friend
void call_once(once_flag&, _Callable);
#endif // _LIBCPP_HAS_NO_VARIADICS
};
#ifndef _LIBCPP_HAS_NO_VARIADICS
template <class _Fp>
class __call_once_param
{
_Fp __f_;
public:
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
_LIBCPP_INLINE_VISIBILITY
explicit __call_once_param(_Fp&& __f) : __f_(_VSTD::move(__f)) {}
#else
_LIBCPP_INLINE_VISIBILITY
explicit __call_once_param(const _Fp& __f) : __f_(__f) {}
#endif
_LIBCPP_INLINE_VISIBILITY
void operator()()
{
typedef typename __make_tuple_indices<tuple_size<_Fp>::value, 1>::type _Index;
__execute(_Index());
}
private:
template <size_t ..._Indices>
_LIBCPP_INLINE_VISIBILITY
void __execute(__tuple_indices<_Indices...>)
{
__invoke(_VSTD::move(_VSTD::get<0>(__f_)), _VSTD::move(_VSTD::get<_Indices>(__f_))...);
}
};
#else
template <class _Fp>
class __call_once_param
{
_Fp __f_;
public:
#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
_LIBCPP_INLINE_VISIBILITY
explicit __call_once_param(_Fp&& __f) : __f_(_VSTD::move(__f)) {}
#else
_LIBCPP_INLINE_VISIBILITY
explicit __call_once_param(const _Fp& __f) : __f_(__f) {}
#endif
_LIBCPP_INLINE_VISIBILITY
void operator()()
{
__f_();
}
};
#endif
template <class _Fp>
void
__call_once_proxy(void* __vp)
{
__call_once_param<_Fp>* __p = static_cast<__call_once_param<_Fp>*>(__vp);
(*__p)();
}
_LIBCPP_FUNC_VIS void __call_once(volatile unsigned long&, void*, void(*)(void*));
#ifndef _LIBCPP_HAS_NO_VARIADICS
template<class _Callable, class... _Args>
inline _LIBCPP_INLINE_VISIBILITY
void
call_once(once_flag& __flag, _Callable&& __func, _Args&&... __args)
{
if (__flag.__state_ != ~0ul)
{
typedef tuple<typename decay<_Callable>::type, typename decay<_Args>::type...> _Gp;
__call_once_param<_Gp> __p(_Gp(__decay_copy(_VSTD::forward<_Callable>(__func)),
__decay_copy(_VSTD::forward<_Args>(__args))...));
__call_once(__flag.__state_, &__p, &__call_once_proxy<_Gp>);
}
}
#else // _LIBCPP_HAS_NO_VARIADICS
template<class _Callable>
inline _LIBCPP_INLINE_VISIBILITY
void
call_once(once_flag& __flag, _Callable __func)
{
if (__flag.__state_ != ~0ul)
{
__call_once_param<_Callable> __p(__func);
__call_once(__flag.__state_, &__p, &__call_once_proxy<_Callable>);
}
}
#endif // _LIBCPP_HAS_NO_VARIADICS
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP_MUTEX