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 
     16 _LIBCPP_BEGIN_NAMESPACE_STD
     17 
     18 const defer_lock_t  defer_lock = {};
     19 const try_to_lock_t try_to_lock = {};
     20 const adopt_lock_t  adopt_lock = {};
     21 
     22 mutex::~mutex()
     23 {
     24     pthread_mutex_destroy(&__m_);
     25 }
     26 
     27 void
     28 mutex::lock()
     29 {
     30     int ec = pthread_mutex_lock(&__m_);
     31     if (ec)
     32         __throw_system_error(ec, "mutex lock failed");
     33 }
     34 
     35 bool
     36 mutex::try_lock() _NOEXCEPT
     37 {
     38     return pthread_mutex_trylock(&__m_) == 0;
     39 }
     40 
     41 void
     42 mutex::unlock() _NOEXCEPT
     43 {
     44     int ec = pthread_mutex_unlock(&__m_);
     45     assert(ec == 0);
     46 }
     47 
     48 // recursive_mutex
     49 
     50 recursive_mutex::recursive_mutex()
     51 {
     52     pthread_mutexattr_t attr;
     53     int ec = pthread_mutexattr_init(&attr);
     54     if (ec)
     55         goto fail;
     56     ec = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
     57     if (ec)
     58     {
     59         pthread_mutexattr_destroy(&attr);
     60         goto fail;
     61     }
     62     ec = pthread_mutex_init(&__m_, &attr);
     63     if (ec)
     64     {
     65         pthread_mutexattr_destroy(&attr);
     66         goto fail;
     67     }
     68     ec = pthread_mutexattr_destroy(&attr);
     69     if (ec)
     70     {
     71         pthread_mutex_destroy(&__m_);
     72         goto fail;
     73     }
     74     return;
     75 fail:
     76     __throw_system_error(ec, "recursive_mutex constructor failed");
     77 }
     78 
     79 recursive_mutex::~recursive_mutex()
     80 {
     81     int e = pthread_mutex_destroy(&__m_);
     82     assert(e == 0);
     83 }
     84 
     85 void
     86 recursive_mutex::lock()
     87 {
     88     int ec = pthread_mutex_lock(&__m_);
     89     if (ec)
     90         __throw_system_error(ec, "recursive_mutex lock failed");
     91 }
     92 
     93 void
     94 recursive_mutex::unlock() _NOEXCEPT
     95 {
     96     int e = pthread_mutex_unlock(&__m_);
     97     assert(e == 0);
     98 }
     99 
    100 bool
    101 recursive_mutex::try_lock() _NOEXCEPT
    102 {
    103     return pthread_mutex_trylock(&__m_) == 0;
    104 }
    105 
    106 // timed_mutex
    107 
    108 timed_mutex::timed_mutex()
    109     : __locked_(false)
    110 {
    111 }
    112 
    113 timed_mutex::~timed_mutex()
    114 {
    115     lock_guard<mutex> _(__m_);
    116 }
    117 
    118 void
    119 timed_mutex::lock()
    120 {
    121     unique_lock<mutex> lk(__m_);
    122     while (__locked_)
    123         __cv_.wait(lk);
    124     __locked_ = true;
    125 }
    126 
    127 bool
    128 timed_mutex::try_lock() _NOEXCEPT
    129 {
    130     unique_lock<mutex> lk(__m_, try_to_lock);
    131     if (lk.owns_lock() && !__locked_)
    132     {
    133         __locked_ = true;
    134         return true;
    135     }
    136     return false;
    137 }
    138 
    139 void
    140 timed_mutex::unlock() _NOEXCEPT
    141 {
    142     lock_guard<mutex> _(__m_);
    143     __locked_ = false;
    144     __cv_.notify_one();
    145 }
    146 
    147 // recursive_timed_mutex
    148 
    149 recursive_timed_mutex::recursive_timed_mutex()
    150     : __count_(0),
    151       __id_(0)
    152 {
    153 }
    154 
    155 recursive_timed_mutex::~recursive_timed_mutex()
    156 {
    157     lock_guard<mutex> _(__m_);
    158 }
    159 
    160 void
    161 recursive_timed_mutex::lock()
    162 {
    163     pthread_t id = pthread_self();
    164     unique_lock<mutex> lk(__m_);
    165     if (pthread_equal(id, __id_))
    166     {
    167         if (__count_ == numeric_limits<size_t>::max())
    168             __throw_system_error(EAGAIN, "recursive_timed_mutex lock limit reached");
    169         ++__count_;
    170         return;
    171     }
    172     while (__count_ != 0)
    173         __cv_.wait(lk);
    174     __count_ = 1;
    175     __id_ = id;
    176 }
    177 
    178 bool
    179 recursive_timed_mutex::try_lock() _NOEXCEPT
    180 {
    181     pthread_t id = pthread_self();
    182     unique_lock<mutex> lk(__m_, try_to_lock);
    183     if (lk.owns_lock() && (__count_ == 0 || pthread_equal(id, __id_)))
    184     {
    185         if (__count_ == numeric_limits<size_t>::max())
    186             return false;
    187         ++__count_;
    188         __id_ = id;
    189         return true;
    190     }
    191     return false;
    192 }
    193 
    194 void
    195 recursive_timed_mutex::unlock() _NOEXCEPT
    196 {
    197     unique_lock<mutex> lk(__m_);
    198     if (--__count_ == 0)
    199     {
    200         __id_ = 0;
    201         lk.unlock();
    202         __cv_.notify_one();
    203     }
    204 }
    205 
    206 // If dispatch_once_f ever handles C++ exceptions, and if one can get to it
    207 // without illegal macros (unexpected macros not beginning with _UpperCase or
    208 // __lowercase), and if it stops spinning waiting threads, then call_once should
    209 // call into dispatch_once_f instead of here. Relevant radar this code needs to
    210 // keep in sync with:  7741191.
    211 
    212 static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
    213 static pthread_cond_t  cv  = PTHREAD_COND_INITIALIZER;
    214 
    215 void
    216 __call_once(volatile unsigned long& flag, void* arg, void(*func)(void*))
    217 {
    218     pthread_mutex_lock(&mut);
    219     while (flag == 1)
    220         pthread_cond_wait(&cv, &mut);
    221     if (flag == 0)
    222     {
    223 #ifndef _LIBCPP_NO_EXCEPTIONS
    224         try
    225         {
    226 #endif  // _LIBCPP_NO_EXCEPTIONS
    227             flag = 1;
    228             pthread_mutex_unlock(&mut);
    229             func(arg);
    230             pthread_mutex_lock(&mut);
    231             flag = ~0ul;
    232             pthread_mutex_unlock(&mut);
    233             pthread_cond_broadcast(&cv);
    234 #ifndef _LIBCPP_NO_EXCEPTIONS
    235         }
    236         catch (...)
    237         {
    238             pthread_mutex_lock(&mut);
    239             flag = 0ul;
    240             pthread_mutex_unlock(&mut);
    241             pthread_cond_broadcast(&cv);
    242             throw;
    243         }
    244 #endif  // _LIBCPP_NO_EXCEPTIONS
    245     }
    246     else
    247         pthread_mutex_unlock(&mut);
    248 }
    249 
    250 _LIBCPP_END_NAMESPACE_STD
    251