Coverage Report

Created: 2025-12-17 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/brpc/src/bthread/mutex.h
Line
Count
Source
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
// bthread - An M:N threading library to make applications more concurrent.
19
20
// Date: 2015/12/14 18:17:04
21
22
#ifndef  BTHREAD_MUTEX_H
23
#define  BTHREAD_MUTEX_H
24
25
#include "bthread/types.h"
26
#include "butil/scoped_lock.h"
27
#include "bvar/utils/lock_timer.h"
28
29
__BEGIN_DECLS
30
extern int bthread_mutex_init(bthread_mutex_t* __restrict mutex,
31
                              const bthread_mutexattr_t* __restrict attr);
32
extern int bthread_mutex_destroy(bthread_mutex_t* mutex);
33
extern int bthread_mutex_trylock(bthread_mutex_t* mutex);
34
extern int bthread_mutex_lock(bthread_mutex_t* mutex);
35
extern int bthread_mutex_timedlock(bthread_mutex_t* __restrict mutex,
36
                                   const struct timespec* __restrict abstime);
37
extern int bthread_mutex_unlock(bthread_mutex_t* mutex);
38
extern bthread_t bthread_self(void);
39
__END_DECLS
40
41
namespace bthread {
42
43
// The C++ Wrapper of bthread_mutex
44
45
// NOTE: Not aligned to cacheline as the container of Mutex is practically aligned
46
class Mutex {
47
public:
48
    typedef bthread_mutex_t* native_handler_type;
49
0
    Mutex() {
50
0
        int ec = bthread_mutex_init(&_mutex, NULL);
51
0
        if (ec != 0) {
52
0
            throw std::system_error(std::error_code(ec, std::system_category()),
53
0
                                    "Mutex constructor failed");
54
0
        }
55
0
    }
56
0
    ~Mutex() { CHECK_EQ(0, bthread_mutex_destroy(&_mutex)); }
57
0
    native_handler_type native_handler() { return &_mutex; }
58
0
    void lock() {
59
0
        int ec = bthread_mutex_lock(&_mutex);
60
0
        if (ec != 0) {
61
0
            throw std::system_error(std::error_code(ec, std::system_category()),
62
0
                                    "Mutex lock failed");
63
0
        }
64
0
    }
65
0
    void unlock() { bthread_mutex_unlock(&_mutex); }
66
0
    bool try_lock() { return 0 == bthread_mutex_trylock(&_mutex); }
67
0
    bool timed_lock(const struct timespec* abstime) {
68
0
        return !bthread_mutex_timedlock(&_mutex, abstime);
69
0
    }
70
    // TODO(chenzhangyi01): Complement interfaces for C++11
71
private:
72
    DISALLOW_COPY_AND_ASSIGN(Mutex);
73
    bthread_mutex_t _mutex;   
74
};
75
76
namespace internal {
77
#ifdef BTHREAD_USE_FAST_PTHREAD_MUTEX
78
class FastPthreadMutex {
79
public:
80
    FastPthreadMutex();
81
    void lock();
82
    void unlock();
83
    bool try_lock();
84
    bool timed_lock(const struct timespec* abstime);
85
private:
86
    DISALLOW_COPY_AND_ASSIGN(FastPthreadMutex);
87
    int lock_contended(const struct timespec* abstime);
88
89
    unsigned _futex;
90
    // Note: Owner detection of the mutex comes with average execution
91
    // slowdown of about 50%., so it is only used for debugging and is
92
    // only available when the macro `BRPC_DEBUG_LOCK' = 1.
93
    mutex_owner_t _owner;
94
};
95
#else
96
typedef butil::Mutex FastPthreadMutex;
97
#endif
98
}
99
100
class FastPthreadMutex {
101
public:
102
0
    FastPthreadMutex() = default;
103
    ~FastPthreadMutex() = default;
104
    DISALLOW_COPY_AND_ASSIGN(FastPthreadMutex);
105
106
    void lock();
107
    void unlock();
108
0
    bool try_lock() { return _mutex.try_lock(); }
109
#if defined(BTHREAD_USE_FAST_PTHREAD_MUTEX) || HAS_PTHREAD_MUTEX_TIMEDLOCK
110
    bool timed_lock(const struct timespec* abstime);
111
#endif // BTHREAD_USE_FAST_PTHREAD_MUTEX  HAS_PTHREAD_MUTEX_TIMEDLOCK
112
113
private:
114
    internal::FastPthreadMutex _mutex;
115
};
116
117
}  // namespace bthread
118
119
// Specialize std::lock_guard and std::unique_lock for bthread_mutex_t
120
121
namespace std {
122
123
template <> class lock_guard<bthread_mutex_t> {
124
public:
125
0
    explicit lock_guard(bthread_mutex_t& mutex) : _pmutex(&mutex) {
126
0
#if !defined(NDEBUG)
127
0
        const int rc = bthread_mutex_lock(_pmutex);
128
0
        if (rc) {
129
0
            LOG(FATAL) << "Fail to lock bthread_mutex_t=" << _pmutex << ", " << berror(rc);
130
0
            _pmutex = NULL;
131
0
        }
132
#else
133
        bthread_mutex_lock(_pmutex);
134
#endif  // NDEBUG
135
0
    }
136
137
0
    ~lock_guard() {
138
0
#ifndef NDEBUG
139
0
        if (_pmutex) {
140
0
            bthread_mutex_unlock(_pmutex);
141
0
        }
142
#else
143
        bthread_mutex_unlock(_pmutex);
144
#endif
145
0
    }
146
147
private:
148
    DISALLOW_COPY_AND_ASSIGN(lock_guard);
149
    bthread_mutex_t* _pmutex;
150
};
151
152
template <> class unique_lock<bthread_mutex_t> {
153
    DISALLOW_COPY_AND_ASSIGN(unique_lock);
154
public:
155
    typedef bthread_mutex_t         mutex_type;
156
0
    unique_lock() : _mutex(NULL), _owns_lock(false) {}
157
    explicit unique_lock(mutex_type& mutex)
158
0
        : _mutex(&mutex), _owns_lock(false) {
159
0
        lock();
160
0
    }
161
    unique_lock(mutex_type& mutex, defer_lock_t)
162
        : _mutex(&mutex), _owns_lock(false)
163
0
    {}
164
    unique_lock(mutex_type& mutex, try_to_lock_t) 
165
        : _mutex(&mutex), _owns_lock(bthread_mutex_trylock(&mutex) == 0)
166
0
    {}
167
    unique_lock(mutex_type& mutex, adopt_lock_t) 
168
        : _mutex(&mutex), _owns_lock(true)
169
0
    {}
170
171
0
    ~unique_lock() {
172
0
        if (_owns_lock) {
173
0
            unlock();
174
0
        }
175
0
    }
176
177
0
    void lock() {
178
0
        if (!_mutex) {
179
0
            CHECK(false) << "Invalid operation";
180
0
            return;
181
0
        }
182
0
        if (_owns_lock) {
183
0
            CHECK(false) << "Detected deadlock issue";     
184
0
            return;
185
0
        }
186
0
        bthread_mutex_lock(_mutex);
187
0
        _owns_lock = true;
188
0
    }
189
190
0
    bool try_lock() {
191
0
        if (!_mutex) {
192
0
            CHECK(false) << "Invalid operation";
193
0
            return false;
194
0
        }
195
0
        if (_owns_lock) {
196
0
            CHECK(false) << "Detected deadlock issue";     
197
0
            return false;
198
0
        }
199
0
        _owns_lock = !bthread_mutex_trylock(_mutex);
200
0
        return _owns_lock;
201
0
    }
202
203
0
    void unlock() {
204
0
        if (!_owns_lock) {
205
0
            CHECK(false) << "Invalid operation";
206
0
            return;
207
0
        }
208
0
        if (_mutex) {
209
0
            bthread_mutex_unlock(_mutex);
210
0
            _owns_lock = false;
211
0
        }
212
0
    }
213
214
0
    void swap(unique_lock& rhs) {
215
0
        std::swap(_mutex, rhs._mutex);
216
0
        std::swap(_owns_lock, rhs._owns_lock);
217
0
    }
218
219
0
    mutex_type* release() {
220
0
        mutex_type* saved_mutex = _mutex;
221
0
        _mutex = NULL;
222
0
        _owns_lock = false;
223
0
        return saved_mutex;
224
0
    }
225
226
0
    mutex_type* mutex() { return _mutex; }
227
0
    bool owns_lock() const { return _owns_lock; }
228
0
    operator bool() const { return owns_lock(); }
229
230
private:
231
    mutex_type*                     _mutex;
232
    bool                            _owns_lock;
233
};
234
235
}  // namespace std
236
237
namespace bvar {
238
239
template <>
240
struct MutexConstructor<bthread_mutex_t> {
241
0
    bool operator()(bthread_mutex_t* mutex) const { 
242
0
        return bthread_mutex_init(mutex, NULL) == 0;
243
0
    }
244
};
245
246
template <>
247
struct MutexDestructor<bthread_mutex_t> {
248
0
    bool operator()(bthread_mutex_t* mutex) const { 
249
0
        return bthread_mutex_destroy(mutex) == 0;
250
0
    }
251
};
252
253
}  // namespace bvar
254
255
#endif  //BTHREAD_MUTEX_H