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_LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
27
28// ~mutex is defined elsewhere
29
30void mutex::lock() {
31 int ec = __libcpp_mutex_lock(m: &__m_);
32 if (ec)
33 std::__throw_system_error(ev: ec, what_arg: "mutex lock failed");
34}
35
36bool mutex::try_lock() noexcept { return __libcpp_mutex_trylock(m: &__m_); }
37
38void mutex::unlock() noexcept {
39 int ec = __libcpp_mutex_unlock(m: &__m_);
40 (void)ec;
41 _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(
42 ec == 0, "call to mutex::unlock failed. A possible reason is that the mutex wasn't locked");
43}
44
45// recursive_mutex
46
47recursive_mutex::recursive_mutex() {
48 int ec = __libcpp_recursive_mutex_init(m: &__m_);
49 if (ec)
50 std::__throw_system_error(ev: ec, what_arg: "recursive_mutex constructor failed");
51}
52
53recursive_mutex::~recursive_mutex() {
54 int e = __libcpp_recursive_mutex_destroy(m: &__m_);
55 (void)e;
56 _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(e == 0, "call to ~recursive_mutex() failed");
57}
58
59void recursive_mutex::lock() {
60 int ec = __libcpp_recursive_mutex_lock(m: &__m_);
61 if (ec)
62 std::__throw_system_error(ev: ec, what_arg: "recursive_mutex lock failed");
63}
64
65void recursive_mutex::unlock() noexcept {
66 int e = __libcpp_recursive_mutex_unlock(m: &__m_);
67 (void)e;
68 _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(
69 e == 0, "call to recursive_mutex::unlock() failed. A possible reason is that the mutex wasn't locked");
70}
71
72bool recursive_mutex::try_lock() noexcept { return __libcpp_recursive_mutex_trylock(m: &__m_); }
73
74// timed_mutex
75
76timed_mutex::timed_mutex() : __locked_(false) {}
77
78timed_mutex::~timed_mutex() { lock_guard<mutex> _(__m_); }
79
80void timed_mutex::lock() {
81 unique_lock<mutex> lk(__m_);
82 while (__locked_)
83 __cv_.wait(lk&: lk);
84 __locked_ = true;
85}
86
87bool timed_mutex::try_lock() noexcept {
88 unique_lock<mutex> lk(__m_, try_to_lock);
89 if (lk.owns_lock() && !__locked_) {
90 __locked_ = true;
91 return true;
92 }
93 return false;
94}
95
96void timed_mutex::unlock() noexcept {
97 lock_guard<mutex> _(__m_);
98 __locked_ = false;
99 __cv_.notify_one();
100}
101
102// recursive_timed_mutex
103
104recursive_timed_mutex::recursive_timed_mutex() : __count_(0), __id_{} {}
105
106recursive_timed_mutex::~recursive_timed_mutex() { lock_guard<mutex> _(__m_); }
107
108void recursive_timed_mutex::lock() {
109 __thread_id id = this_thread::get_id();
110 unique_lock<mutex> lk(__m_);
111 if (id == __id_) {
112 if (__count_ == numeric_limits<size_t>::max())
113 std::__throw_system_error(EAGAIN, what_arg: "recursive_timed_mutex lock limit reached");
114 ++__count_;
115 return;
116 }
117 while (__count_ != 0)
118 __cv_.wait(lk&: lk);
119 __count_ = 1;
120 __id_ = id;
121}
122
123bool recursive_timed_mutex::try_lock() noexcept {
124 __thread_id id = this_thread::get_id();
125 unique_lock<mutex> lk(__m_, try_to_lock);
126 if (lk.owns_lock() && (__count_ == 0 || id == __id_)) {
127 if (__count_ == numeric_limits<size_t>::max())
128 return false;
129 ++__count_;
130 __id_ = id;
131 return true;
132 }
133 return false;
134}
135
136void recursive_timed_mutex::unlock() noexcept {
137 unique_lock<mutex> lk(__m_);
138 if (--__count_ == 0) {
139 __id_.__reset();
140 lk.unlock();
141 __cv_.notify_one();
142 }
143}
144
145_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
146_LIBCPP_END_NAMESPACE_STD
147
148_LIBCPP_POP_MACROS
149