xref: /freebsd/contrib/llvm-project/libcxx/src/mutex.cpp (revision 1db9f3b21e39176dd5b67cf8ac378633b172463e)
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 <__thread/id.h>
11 #include <__utility/exception_guard.h>
12 #include <limits>
13 #include <mutex>
14 
15 #include "include/atomic_support.h"
16 
17 #if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
18 #  pragma comment(lib, "pthread")
19 #endif
20 
21 _LIBCPP_PUSH_MACROS
22 #include <__undef_macros>
23 
24 _LIBCPP_BEGIN_NAMESPACE_STD
25 
26 // ~mutex is defined elsewhere
27 
28 void mutex::lock() {
29   int ec = __libcpp_mutex_lock(&__m_);
30   if (ec)
31     __throw_system_error(ec, "mutex lock failed");
32 }
33 
34 bool mutex::try_lock() noexcept { return __libcpp_mutex_trylock(&__m_); }
35 
36 void mutex::unlock() noexcept {
37   int ec = __libcpp_mutex_unlock(&__m_);
38   (void)ec;
39   _LIBCPP_ASSERT_UNCATEGORIZED(ec == 0, "call to mutex::unlock failed");
40 }
41 
42 // recursive_mutex
43 
44 recursive_mutex::recursive_mutex() {
45   int ec = __libcpp_recursive_mutex_init(&__m_);
46   if (ec)
47     __throw_system_error(ec, "recursive_mutex constructor failed");
48 }
49 
50 recursive_mutex::~recursive_mutex() {
51   int e = __libcpp_recursive_mutex_destroy(&__m_);
52   (void)e;
53   _LIBCPP_ASSERT_UNCATEGORIZED(e == 0, "call to ~recursive_mutex() failed");
54 }
55 
56 void recursive_mutex::lock() {
57   int ec = __libcpp_recursive_mutex_lock(&__m_);
58   if (ec)
59     __throw_system_error(ec, "recursive_mutex lock failed");
60 }
61 
62 void recursive_mutex::unlock() noexcept {
63   int e = __libcpp_recursive_mutex_unlock(&__m_);
64   (void)e;
65   _LIBCPP_ASSERT_UNCATEGORIZED(e == 0, "call to recursive_mutex::unlock() failed");
66 }
67 
68 bool recursive_mutex::try_lock() noexcept { return __libcpp_recursive_mutex_trylock(&__m_); }
69 
70 // timed_mutex
71 
72 timed_mutex::timed_mutex() : __locked_(false) {}
73 
74 timed_mutex::~timed_mutex() { lock_guard<mutex> _(__m_); }
75 
76 void timed_mutex::lock() {
77   unique_lock<mutex> lk(__m_);
78   while (__locked_)
79     __cv_.wait(lk);
80   __locked_ = true;
81 }
82 
83 bool timed_mutex::try_lock() noexcept {
84   unique_lock<mutex> lk(__m_, try_to_lock);
85   if (lk.owns_lock() && !__locked_) {
86     __locked_ = true;
87     return true;
88   }
89   return false;
90 }
91 
92 void timed_mutex::unlock() noexcept {
93   lock_guard<mutex> _(__m_);
94   __locked_ = false;
95   __cv_.notify_one();
96 }
97 
98 // recursive_timed_mutex
99 
100 recursive_timed_mutex::recursive_timed_mutex() : __count_(0), __id_{} {}
101 
102 recursive_timed_mutex::~recursive_timed_mutex() { lock_guard<mutex> _(__m_); }
103 
104 void recursive_timed_mutex::lock() {
105   __thread_id id = this_thread::get_id();
106   unique_lock<mutex> lk(__m_);
107   if (id == __id_) {
108     if (__count_ == numeric_limits<size_t>::max())
109       __throw_system_error(EAGAIN, "recursive_timed_mutex lock limit reached");
110     ++__count_;
111     return;
112   }
113   while (__count_ != 0)
114     __cv_.wait(lk);
115   __count_ = 1;
116   __id_    = id;
117 }
118 
119 bool recursive_timed_mutex::try_lock() noexcept {
120   __thread_id id = this_thread::get_id();
121   unique_lock<mutex> lk(__m_, try_to_lock);
122   if (lk.owns_lock() && (__count_ == 0 || id == __id_)) {
123     if (__count_ == numeric_limits<size_t>::max())
124       return false;
125     ++__count_;
126     __id_ = id;
127     return true;
128   }
129   return false;
130 }
131 
132 void recursive_timed_mutex::unlock() noexcept {
133   unique_lock<mutex> lk(__m_);
134   if (--__count_ == 0) {
135     __id_.__reset();
136     lk.unlock();
137     __cv_.notify_one();
138   }
139 }
140 
141 _LIBCPP_END_NAMESPACE_STD
142 
143 _LIBCPP_POP_MACROS
144