master
  1//===----------------------------------------------------------------------===//
  2//
  3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4// See https://llvm.org/LICENSE.txt for license information.
  5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6//
  7//===----------------------------------------------------------------------===//
  8
  9#include <__assert>
 10#include <__system_error/throw_system_error.h>
 11#include <__thread/id.h>
 12#include <__utility/exception_guard.h>
 13#include <limits>
 14#include <mutex>
 15
 16#include "include/atomic_support.h"
 17
 18#if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
 19#  pragma comment(lib, "pthread")
 20#endif
 21
 22_LIBCPP_PUSH_MACROS
 23#include <__undef_macros>
 24
 25_LIBCPP_BEGIN_NAMESPACE_STD
 26
 27// ~mutex is defined elsewhere
 28
 29void mutex::lock() {
 30  int ec = __libcpp_mutex_lock(&__m_);
 31  if (ec)
 32    std::__throw_system_error(ec, "mutex lock failed");
 33}
 34
 35bool mutex::try_lock() noexcept { return __libcpp_mutex_trylock(&__m_); }
 36
 37void mutex::unlock() noexcept {
 38  int ec = __libcpp_mutex_unlock(&__m_);
 39  (void)ec;
 40  _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(
 41      ec == 0, "call to mutex::unlock failed. A possible reason is that the mutex wasn't locked");
 42}
 43
 44// recursive_mutex
 45
 46recursive_mutex::recursive_mutex() {
 47  int ec = __libcpp_recursive_mutex_init(&__m_);
 48  if (ec)
 49    std::__throw_system_error(ec, "recursive_mutex constructor failed");
 50}
 51
 52recursive_mutex::~recursive_mutex() {
 53  int e = __libcpp_recursive_mutex_destroy(&__m_);
 54  (void)e;
 55  _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(e == 0, "call to ~recursive_mutex() failed");
 56}
 57
 58void recursive_mutex::lock() {
 59  int ec = __libcpp_recursive_mutex_lock(&__m_);
 60  if (ec)
 61    std::__throw_system_error(ec, "recursive_mutex lock failed");
 62}
 63
 64void recursive_mutex::unlock() noexcept {
 65  int e = __libcpp_recursive_mutex_unlock(&__m_);
 66  (void)e;
 67  _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(
 68      e == 0, "call to recursive_mutex::unlock() failed. A possible reason is that the mutex wasn't locked");
 69}
 70
 71bool recursive_mutex::try_lock() noexcept { return __libcpp_recursive_mutex_trylock(&__m_); }
 72
 73// timed_mutex
 74
 75timed_mutex::timed_mutex() : __locked_(false) {}
 76
 77timed_mutex::~timed_mutex() { lock_guard<mutex> _(__m_); }
 78
 79void timed_mutex::lock() {
 80  unique_lock<mutex> lk(__m_);
 81  while (__locked_)
 82    __cv_.wait(lk);
 83  __locked_ = true;
 84}
 85
 86bool timed_mutex::try_lock() noexcept {
 87  unique_lock<mutex> lk(__m_, try_to_lock);
 88  if (lk.owns_lock() && !__locked_) {
 89    __locked_ = true;
 90    return true;
 91  }
 92  return false;
 93}
 94
 95void timed_mutex::unlock() noexcept {
 96  lock_guard<mutex> _(__m_);
 97  __locked_ = false;
 98  __cv_.notify_one();
 99}
100
101// recursive_timed_mutex
102
103recursive_timed_mutex::recursive_timed_mutex() : __count_(0), __id_{} {}
104
105recursive_timed_mutex::~recursive_timed_mutex() { lock_guard<mutex> _(__m_); }
106
107void recursive_timed_mutex::lock() {
108  __thread_id id = this_thread::get_id();
109  unique_lock<mutex> lk(__m_);
110  if (id == __id_) {
111    if (__count_ == numeric_limits<size_t>::max())
112      std::__throw_system_error(EAGAIN, "recursive_timed_mutex lock limit reached");
113    ++__count_;
114    return;
115  }
116  while (__count_ != 0)
117    __cv_.wait(lk);
118  __count_ = 1;
119  __id_    = id;
120}
121
122bool recursive_timed_mutex::try_lock() noexcept {
123  __thread_id id = this_thread::get_id();
124  unique_lock<mutex> lk(__m_, try_to_lock);
125  if (lk.owns_lock() && (__count_ == 0 || id == __id_)) {
126    if (__count_ == numeric_limits<size_t>::max())
127      return false;
128    ++__count_;
129    __id_ = id;
130    return true;
131  }
132  return false;
133}
134
135void recursive_timed_mutex::unlock() noexcept {
136  unique_lock<mutex> lk(__m_);
137  if (--__count_ == 0) {
138    __id_.__reset();
139    lk.unlock();
140    __cv_.notify_one();
141  }
142}
143
144_LIBCPP_END_NAMESPACE_STD
145
146_LIBCPP_POP_MACROS