Home | History | Annotate | Download | only in src
      1 //===------------------------- mutex.cpp ----------------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is dual licensed under the MIT and the University of Illinois Open
      6 // Source Licenses. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #define _LIBCPP_BUILDING_MUTEX
     11 #include "mutex"
     12 #include "limits"
     13 #include "system_error"
     14 #include "cassert"
     15 #include "include/atomic_support.h"
     16 
     17 _LIBCPP_BEGIN_NAMESPACE_STD
     18 #ifndef _LIBCPP_HAS_NO_THREADS
     19 
     20 const defer_lock_t  defer_lock = {};
     21 const try_to_lock_t try_to_lock = {};
     22 const adopt_lock_t  adopt_lock = {};
     23 
     24 mutex::~mutex()
     25 {
     26     __libcpp_mutex_destroy(&__m_);
     27 }
     28 
     29 void
     30 mutex::lock()
     31 {
     32     int ec = __libcpp_mutex_lock(&__m_);
     33     if (ec)
     34         __throw_system_error(ec, "mutex lock failed");
     35 }
     36 
     37 bool
     38 mutex::try_lock() _NOEXCEPT
     39 {
     40     return __libcpp_mutex_trylock(&__m_) == 0;
     41 }
     42 
     43 void
     44 mutex::unlock() _NOEXCEPT
     45 {
     46     int ec = __libcpp_mutex_unlock(&__m_);
     47     (void)ec;
     48     assert(ec == 0);
     49 }
     50 
     51 // recursive_mutex
     52 
     53 recursive_mutex::recursive_mutex()
     54 {
     55     int ec = __libcpp_recursive_mutex_init(&__m_);
     56     if (ec)
     57         __throw_system_error(ec, "recursive_mutex constructor failed");
     58 }
     59 
     60 recursive_mutex::~recursive_mutex()
     61 {
     62     int e = __libcpp_mutex_destroy(&__m_);
     63     (void)e;
     64     assert(e == 0);
     65 }
     66 
     67 void
     68 recursive_mutex::lock()
     69 {
     70     int ec = __libcpp_mutex_lock(&__m_);
     71     if (ec)
     72         __throw_system_error(ec, "recursive_mutex lock failed");
     73 }
     74 
     75 void
     76 recursive_mutex::unlock() _NOEXCEPT
     77 {
     78     int e = __libcpp_mutex_unlock(&__m_);
     79     (void)e;
     80     assert(e == 0);
     81 }
     82 
     83 bool
     84 recursive_mutex::try_lock() _NOEXCEPT
     85 {
     86     return __libcpp_mutex_trylock(&__m_) == 0;
     87 }
     88 
     89 // timed_mutex
     90 
     91 timed_mutex::timed_mutex()
     92     : __locked_(false)
     93 {
     94 }
     95 
     96 timed_mutex::~timed_mutex()
     97 {
     98     lock_guard<mutex> _(__m_);
     99 }
    100 
    101 void
    102 timed_mutex::lock()
    103 {
    104     unique_lock<mutex> lk(__m_);
    105     while (__locked_)
    106         __cv_.wait(lk);
    107     __locked_ = true;
    108 }
    109 
    110 bool
    111 timed_mutex::try_lock() _NOEXCEPT
    112 {
    113     unique_lock<mutex> lk(__m_, try_to_lock);
    114     if (lk.owns_lock() && !__locked_)
    115     {
    116         __locked_ = true;
    117         return true;
    118     }
    119     return false;
    120 }
    121 
    122 void
    123 timed_mutex::unlock() _NOEXCEPT
    124 {
    125     lock_guard<mutex> _(__m_);
    126     __locked_ = false;
    127     __cv_.notify_one();
    128 }
    129 
    130 // recursive_timed_mutex
    131 
    132 recursive_timed_mutex::recursive_timed_mutex()
    133     : __count_(0),
    134       __id_(0)
    135 {
    136 }
    137 
    138 recursive_timed_mutex::~recursive_timed_mutex()
    139 {
    140     lock_guard<mutex> _(__m_);
    141 }
    142 
    143 void
    144 recursive_timed_mutex::lock()
    145 {
    146     __libcpp_thread_id id = __libcpp_thread_get_current_id();
    147     unique_lock<mutex> lk(__m_);
    148     if (__libcpp_thread_id_equal(id, __id_))
    149     {
    150         if (__count_ == numeric_limits<size_t>::max())
    151             __throw_system_error(EAGAIN, "recursive_timed_mutex lock limit reached");
    152         ++__count_;
    153         return;
    154     }
    155     while (__count_ != 0)
    156         __cv_.wait(lk);
    157     __count_ = 1;
    158     __id_ = id;
    159 }
    160 
    161 bool
    162 recursive_timed_mutex::try_lock() _NOEXCEPT
    163 {
    164     __libcpp_thread_id id = __libcpp_thread_get_current_id();
    165     unique_lock<mutex> lk(__m_, try_to_lock);
    166     if (lk.owns_lock() && (__count_ == 0 || __libcpp_thread_id_equal(id, __id_)))
    167     {
    168         if (__count_ == numeric_limits<size_t>::max())
    169             return false;
    170         ++__count_;
    171         __id_ = id;
    172         return true;
    173     }
    174     return false;
    175 }
    176 
    177 void
    178 recursive_timed_mutex::unlock() _NOEXCEPT
    179 {
    180     unique_lock<mutex> lk(__m_);
    181     if (--__count_ == 0)
    182     {
    183         __id_ = 0;
    184         lk.unlock();
    185         __cv_.notify_one();
    186     }
    187 }
    188 
    189 #endif // !_LIBCPP_HAS_NO_THREADS
    190 
    191 // If dispatch_once_f ever handles C++ exceptions, and if one can get to it
    192 // without illegal macros (unexpected macros not beginning with _UpperCase or
    193 // __lowercase), and if it stops spinning waiting threads, then call_once should
    194 // call into dispatch_once_f instead of here. Relevant radar this code needs to
    195 // keep in sync with:  7741191.
    196 
    197 #ifndef _LIBCPP_HAS_NO_THREADS
    198 static __libcpp_mutex_t mut = _LIBCPP_MUTEX_INITIALIZER;
    199 static __libcpp_condvar_t cv = _LIBCPP_CONDVAR_INITIALIZER;
    200 #endif
    201 
    202 /// NOTE: Changes to flag are done via relaxed atomic stores
    203 ///       even though the accesses are protected by a mutex because threads
    204 ///       just entering 'call_once` concurrently read from flag.
    205 void
    206 __call_once(volatile unsigned long& flag, void* arg, void(*func)(void*))
    207 {
    208 #if defined(_LIBCPP_HAS_NO_THREADS)
    209     if (flag == 0)
    210     {
    211 #ifndef _LIBCPP_NO_EXCEPTIONS
    212         try
    213         {
    214 #endif  // _LIBCPP_NO_EXCEPTIONS
    215             flag = 1;
    216             func(arg);
    217             flag = ~0ul;
    218 #ifndef _LIBCPP_NO_EXCEPTIONS
    219         }
    220         catch (...)
    221         {
    222             flag = 0ul;
    223             throw;
    224         }
    225 #endif  // _LIBCPP_NO_EXCEPTIONS
    226     }
    227 #else // !_LIBCPP_HAS_NO_THREADS
    228     __libcpp_mutex_lock(&mut);
    229     while (flag == 1)
    230         __libcpp_condvar_wait(&cv, &mut);
    231     if (flag == 0)
    232     {
    233 #ifndef _LIBCPP_NO_EXCEPTIONS
    234         try
    235         {
    236 #endif  // _LIBCPP_NO_EXCEPTIONS
    237             __libcpp_relaxed_store(&flag, 1ul);
    238             __libcpp_mutex_unlock(&mut);
    239             func(arg);
    240             __libcpp_mutex_lock(&mut);
    241             __libcpp_relaxed_store(&flag, ~0ul);
    242             __libcpp_mutex_unlock(&mut);
    243             __libcpp_condvar_broadcast(&cv);
    244 #ifndef _LIBCPP_NO_EXCEPTIONS
    245         }
    246         catch (...)
    247         {
    248             __libcpp_mutex_lock(&mut);
    249             __libcpp_relaxed_store(&flag, 0ul);
    250             __libcpp_mutex_unlock(&mut);
    251             __libcpp_condvar_broadcast(&cv);
    252             throw;
    253         }
    254 #endif  // _LIBCPP_NO_EXCEPTIONS
    255     }
    256     else
    257         __libcpp_mutex_unlock(&mut);
    258 #endif // !_LIBCPP_HAS_NO_THREADS
    259 
    260 }
    261 
    262 _LIBCPP_END_NAMESPACE_STD
    263