Coverage Report

Created: 2022-07-16 07:03

/Users/buildslave/jenkins/workspace/coverage/llvm-project/libcxx/src/mutex.cpp
Line
Count
Source (jump to first uncovered line)
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 <limits>
11
#include <mutex>
12
#include <system_error>
13
14
#include "include/atomic_support.h"
15
16
#ifndef _LIBCPP_HAS_NO_THREADS
17
#  if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
18
#    pragma comment(lib, "pthread")
19
#  endif
20
#endif
21
22
_LIBCPP_PUSH_MACROS
23
#include <__undef_macros>
24
25
_LIBCPP_BEGIN_NAMESPACE_STD
26
27
#ifndef _LIBCPP_HAS_NO_THREADS
28
29
const defer_lock_t  defer_lock{};
30
const try_to_lock_t try_to_lock{};
31
const adopt_lock_t  adopt_lock{};
32
33
// ~mutex is defined elsewhere
34
35
void
36
mutex::lock()
37
15.5M
{
38
15.5M
    int ec = __libcpp_mutex_lock(&__m_);
39
15.5M
    if (ec)
40
0
        __throw_system_error(ec, "mutex lock failed");
41
15.5M
}
42
43
bool
44
mutex::try_lock() noexcept
45
30
{
46
30
    return __libcpp_mutex_trylock(&__m_);
47
30
}
48
49
void
50
mutex::unlock() noexcept
51
15.5M
{
52
15.5M
    int ec = __libcpp_mutex_unlock(&__m_);
53
15.5M
    (void)ec;
54
15.5M
    _LIBCPP_ASSERT(ec == 0, "call to mutex::unlock failed");
55
15.5M
}
56
57
// recursive_mutex
58
59
recursive_mutex::recursive_mutex()
60
18.4k
{
61
18.4k
    int ec = __libcpp_recursive_mutex_init(&__m_);
62
18.4k
    if (ec)
63
0
        __throw_system_error(ec, "recursive_mutex constructor failed");
64
18.4k
}
65
66
recursive_mutex::~recursive_mutex()
67
16.6k
{
68
16.6k
    int e = __libcpp_recursive_mutex_destroy(&__m_);
69
16.6k
    (void)e;
70
16.6k
    _LIBCPP_ASSERT(e == 0, "call to ~recursive_mutex() failed");
71
16.6k
}
72
73
void
74
recursive_mutex::lock()
75
259k
{
76
259k
    int ec = __libcpp_recursive_mutex_lock(&__m_);
77
259k
    if (ec)
78
0
        __throw_system_error(ec, "recursive_mutex lock failed");
79
259k
}
80
81
void
82
recursive_mutex::unlock() noexcept
83
260k
{
84
260k
    int e = __libcpp_recursive_mutex_unlock(&__m_);
85
260k
    (void)e;
86
260k
    _LIBCPP_ASSERT(e == 0, "call to recursive_mutex::unlock() failed");
87
260k
}
88
89
bool
90
recursive_mutex::try_lock() noexcept
91
1.06k
{
92
1.06k
    return __libcpp_recursive_mutex_trylock(&__m_);
93
1.06k
}
94
95
// timed_mutex
96
97
timed_mutex::timed_mutex()
98
    : __locked_(false)
99
0
{
100
0
}
101
102
timed_mutex::~timed_mutex()
103
0
{
104
0
    lock_guard<mutex> _(__m_);
105
0
}
106
107
void
108
timed_mutex::lock()
109
0
{
110
0
    unique_lock<mutex> lk(__m_);
111
0
    while (__locked_)
112
0
        __cv_.wait(lk);
113
0
    __locked_ = true;
114
0
}
115
116
bool
117
timed_mutex::try_lock() noexcept
118
0
{
119
0
    unique_lock<mutex> lk(__m_, try_to_lock);
120
0
    if (lk.owns_lock() && !__locked_)
121
0
    {
122
0
        __locked_ = true;
123
0
        return true;
124
0
    }
125
0
    return false;
126
0
}
127
128
void
129
timed_mutex::unlock() noexcept
130
0
{
131
0
    lock_guard<mutex> _(__m_);
132
0
    __locked_ = false;
133
0
    __cv_.notify_one();
134
0
}
135
136
// recursive_timed_mutex
137
138
recursive_timed_mutex::recursive_timed_mutex()
139
    : __count_(0),
140
      __id_{}
141
0
{
142
0
}
143
144
recursive_timed_mutex::~recursive_timed_mutex()
145
0
{
146
0
    lock_guard<mutex> _(__m_);
147
0
}
148
149
void
150
recursive_timed_mutex::lock()
151
0
{
152
0
    __thread_id id = this_thread::get_id();
153
0
    unique_lock<mutex> lk(__m_);
154
0
    if (id ==__id_)
155
0
    {
156
0
        if (__count_ == numeric_limits<size_t>::max())
157
0
            __throw_system_error(EAGAIN, "recursive_timed_mutex lock limit reached");
158
0
        ++__count_;
159
0
        return;
160
0
    }
161
0
    while (__count_ != 0)
162
0
        __cv_.wait(lk);
163
0
    __count_ = 1;
164
0
    __id_ = id;
165
0
}
166
167
bool
168
recursive_timed_mutex::try_lock() noexcept
169
0
{
170
0
    __thread_id id = this_thread::get_id();
171
0
    unique_lock<mutex> lk(__m_, try_to_lock);
172
0
    if (lk.owns_lock() && (__count_ == 0 || id == __id_))
173
0
    {
174
0
        if (__count_ == numeric_limits<size_t>::max())
175
0
            return false;
176
0
        ++__count_;
177
0
        __id_ = id;
178
0
        return true;
179
0
    }
180
0
    return false;
181
0
}
182
183
void
184
recursive_timed_mutex::unlock() noexcept
185
0
{
186
0
    unique_lock<mutex> lk(__m_);
187
0
    if (--__count_ == 0)
188
0
    {
189
0
        __id_.__reset();
190
0
        lk.unlock();
191
0
        __cv_.notify_one();
192
0
    }
193
0
}
194
195
#endif // !_LIBCPP_HAS_NO_THREADS
196
197
// If dispatch_once_f ever handles C++ exceptions, and if one can get to it
198
// without illegal macros (unexpected macros not beginning with _UpperCase or
199
// __lowercase), and if it stops spinning waiting threads, then call_once should
200
// call into dispatch_once_f instead of here. Relevant radar this code needs to
201
// keep in sync with:  7741191.
202
203
#ifndef _LIBCPP_HAS_NO_THREADS
204
static constinit __libcpp_mutex_t mut = _LIBCPP_MUTEX_INITIALIZER;
205
static constinit __libcpp_condvar_t cv = _LIBCPP_CONDVAR_INITIALIZER;
206
#endif
207
208
void __call_once(volatile once_flag::_State_type& flag, void* arg,
209
                 void (*func)(void*))
210
22.2k
{
211
#if defined(_LIBCPP_HAS_NO_THREADS)
212
    if (flag == 0)
213
    {
214
#ifndef _LIBCPP_NO_EXCEPTIONS
215
        try
216
        {
217
#endif // _LIBCPP_NO_EXCEPTIONS
218
            flag = 1;
219
            func(arg);
220
            flag = ~once_flag::_State_type(0);
221
#ifndef _LIBCPP_NO_EXCEPTIONS
222
        }
223
        catch (...)
224
        {
225
            flag = 0;
226
            throw;
227
        }
228
#endif // _LIBCPP_NO_EXCEPTIONS
229
    }
230
#else // !_LIBCPP_HAS_NO_THREADS
231
22.2k
    __libcpp_mutex_lock(&mut);
232
22.2k
    while (flag == 1)
233
3
        __libcpp_condvar_wait(&cv, &mut);
234
22.2k
    if (flag == 0)
235
22.2k
    {
236
22.2k
#ifndef _LIBCPP_NO_EXCEPTIONS
237
22.2k
        try
238
22.2k
        {
239
22.2k
#endif // _LIBCPP_NO_EXCEPTIONS
240
22.2k
            __libcpp_relaxed_store(&flag, once_flag::_State_type(1));
241
22.2k
            __libcpp_mutex_unlock(&mut);
242
22.2k
            func(arg);
243
22.2k
            __libcpp_mutex_lock(&mut);
244
22.2k
            __libcpp_atomic_store(&flag, ~once_flag::_State_type(0),
245
22.2k
                                  _AO_Release);
246
22.2k
            __libcpp_mutex_unlock(&mut);
247
22.2k
            __libcpp_condvar_broadcast(&cv);
248
22.2k
#ifndef _LIBCPP_NO_EXCEPTIONS
249
22.2k
        }
250
22.2k
        catch (...)
251
22.2k
        {
252
0
            __libcpp_mutex_lock(&mut);
253
0
            __libcpp_relaxed_store(&flag, once_flag::_State_type(0));
254
0
            __libcpp_mutex_unlock(&mut);
255
0
            __libcpp_condvar_broadcast(&cv);
256
0
            throw;
257
0
        }
258
22.2k
#endif // _LIBCPP_NO_EXCEPTIONS
259
22.2k
    }
260
3
    else
261
3
        __libcpp_mutex_unlock(&mut);
262
22.2k
#endif // !_LIBCPP_HAS_NO_THREADS
263
22.2k
}
264
265
_LIBCPP_END_NAMESPACE_STD
266
267
_LIBCPP_POP_MACROS