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