Skip to content

Commit c4a3d18

Browse files
vmishelcsgchatelet
andauthored
[libc] Replace MutexLock with cpp::lock_guard (#89340)
This PR address issue #89002. #### Changes in this PR * Added a simple implementation of `cpp::lock_guard` (an equivalent of `std::lock_guard`) in libc/src/__support/CPP inspired by the libstdc++ implementation * Added tests for `cpp::lock_guard` in /libc/test/src/__support/CPP/mutex_test.cpp * Replaced all references to `MutexLock` with `cpp::lock_guard` --------- Co-authored-by: Guillaume Chatelet <[email protected]>
1 parent aacea0d commit c4a3d18

File tree

13 files changed

+165
-14
lines changed

13 files changed

+165
-14
lines changed

libc/src/__support/CPP/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@ add_header_library(
5151
libc.src.__support.macros.properties.types
5252
)
5353

54+
add_header_library(
55+
mutex
56+
HDRS
57+
mutex.h
58+
)
59+
5460
add_header_library(
5561
span
5662
HDRS

libc/src/__support/CPP/mutex.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//===--- A self contained equivalent of std::mutex --------------*- C++ -*-===//
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+
#ifndef LLVM_LIBC_SRC___SUPPORT_CPP_MUTEX_H
10+
#define LLVM_LIBC_SRC___SUPPORT_CPP_MUTEX_H
11+
12+
namespace LIBC_NAMESPACE {
13+
namespace cpp {
14+
15+
// Assume the calling thread has already obtained mutex ownership.
16+
struct adopt_lock_t {
17+
explicit adopt_lock_t() = default;
18+
};
19+
20+
// Tag used to make a scoped lock take ownership of a locked mutex.
21+
constexpr adopt_lock_t adopt_lock{};
22+
23+
// An RAII class for easy locking and unlocking of mutexes.
24+
template <typename MutexType> class lock_guard {
25+
MutexType &mutex;
26+
27+
public:
28+
// Calls `m.lock()` upon resource acquisition.
29+
explicit lock_guard(MutexType &m) : mutex(m) { mutex.lock(); }
30+
31+
// Acquires ownership of the mutex object `m` without attempting to lock
32+
// it. The behavior is undefined if the current thread does not hold the
33+
// lock on `m`. Does not call `m.lock()` upon resource acquisition.
34+
lock_guard(MutexType &m, adopt_lock_t t) : mutex(m) {}
35+
36+
~lock_guard() { mutex.unlock(); }
37+
38+
// non-copyable
39+
lock_guard &operator=(const lock_guard &) = delete;
40+
lock_guard(const lock_guard &) = delete;
41+
};
42+
43+
} // namespace cpp
44+
} // namespace LIBC_NAMESPACE
45+
46+
#endif // LLVM_LIBC_SRC___SUPPORT_CPP_MUTEX_H

libc/src/__support/File/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ add_object_library(
2525
HDRS
2626
dir.h
2727
DEPENDS
28+
libc.src.__support.CPP.mutex
2829
libc.src.__support.CPP.new
2930
libc.src.__support.CPP.span
3031
libc.src.__support.threads.mutex

libc/src/__support/File/dir.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "dir.h"
1010

11+
#include "src/__support/CPP/mutex.h" // lock_guard
1112
#include "src/__support/CPP/new.h"
1213
#include "src/__support/error_or.h"
1314
#include "src/errno/libc_errno.h" // For error macros
@@ -27,7 +28,7 @@ ErrorOr<Dir *> Dir::open(const char *path) {
2728
}
2829

2930
ErrorOr<struct ::dirent *> Dir::read() {
30-
MutexLock lock(&mutex);
31+
cpp::lock_guard lock(mutex);
3132
if (readptr >= fillsize) {
3233
auto readsize = platform_fetch_dirents(fd, buffer);
3334
if (!readsize)
@@ -51,7 +52,7 @@ ErrorOr<struct ::dirent *> Dir::read() {
5152

5253
int Dir::close() {
5354
{
54-
MutexLock lock(&mutex);
55+
cpp::lock_guard lock(mutex);
5556
int retval = platform_closedir(fd);
5657
if (retval != 0)
5758
return retval;

libc/src/__support/threads/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ if(TARGET libc.src.__support.threads.${LIBC_TARGET_OS}.mutex)
3131
fork_callbacks.h
3232
DEPENDS
3333
.mutex
34+
libc.src.__support.CPP.mutex
3435
)
3536
endif()
3637

@@ -57,6 +58,7 @@ if(TARGET libc.src.__support.threads.${LIBC_TARGET_OS}.thread)
5758
libc.src.__support.common
5859
libc.src.__support.fixedvector
5960
libc.src.__support.CPP.array
61+
libc.src.__support.CPP.mutex
6062
libc.src.__support.CPP.optional
6163
)
6264
endif()

libc/src/__support/threads/fork_callbacks.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "fork_callbacks.h"
1010

11+
#include "src/__support/CPP/mutex.h" // lock_guard
1112
#include "src/__support/threads/mutex.h"
1213

1314
#include <stddef.h> // For size_t
@@ -35,7 +36,7 @@ class AtForkCallbackManager {
3536
constexpr AtForkCallbackManager() : mtx(false, false, false), next_index(0) {}
3637

3738
bool register_triple(const ForkCallbackTriple &triple) {
38-
MutexLock lock(&mtx);
39+
cpp::lock_guard lock(mtx);
3940
if (next_index >= CALLBACK_SIZE)
4041
return false;
4142
list[next_index] = triple;
@@ -44,7 +45,7 @@ class AtForkCallbackManager {
4445
}
4546

4647
void invoke_prepare() {
47-
MutexLock lock(&mtx);
48+
cpp::lock_guard lock(mtx);
4849
for (size_t i = 0; i < next_index; ++i) {
4950
auto prepare = list[i].prepare;
5051
if (prepare)
@@ -53,7 +54,7 @@ class AtForkCallbackManager {
5354
}
5455

5556
void invoke_parent() {
56-
MutexLock lock(&mtx);
57+
cpp::lock_guard lock(mtx);
5758
for (size_t i = 0; i < next_index; ++i) {
5859
auto parent = list[i].parent;
5960
if (parent)
@@ -62,7 +63,7 @@ class AtForkCallbackManager {
6263
}
6364

6465
void invoke_child() {
65-
MutexLock lock(&mtx);
66+
cpp::lock_guard lock(mtx);
6667
for (size_t i = 0; i < next_index; ++i) {
6768
auto child = list[i].child;
6869
if (child)

libc/src/__support/threads/thread.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "src/__support/threads/mutex.h"
1111

1212
#include "src/__support/CPP/array.h"
13+
#include "src/__support/CPP/mutex.h" // lock_guard
1314
#include "src/__support/CPP/optional.h"
1415
#include "src/__support/fixedvector.h"
1516
#include "src/__support/macros/attributes.h"
@@ -56,7 +57,7 @@ class TSSKeyMgr {
5657
constexpr TSSKeyMgr() : mtx(false, false, false) {}
5758

5859
cpp::optional<unsigned int> new_key(TSSDtor *dtor) {
59-
MutexLock lock(&mtx);
60+
cpp::lock_guard lock(mtx);
6061
for (unsigned int i = 0; i < TSS_KEY_COUNT; ++i) {
6162
TSSKeyUnit &u = units[i];
6263
if (!u.active) {
@@ -70,20 +71,20 @@ class TSSKeyMgr {
7071
TSSDtor *get_dtor(unsigned int key) {
7172
if (key >= TSS_KEY_COUNT)
7273
return nullptr;
73-
MutexLock lock(&mtx);
74+
cpp::lock_guard lock(mtx);
7475
return units[key].dtor;
7576
}
7677

7778
bool remove_key(unsigned int key) {
7879
if (key >= TSS_KEY_COUNT)
7980
return false;
80-
MutexLock lock(&mtx);
81+
cpp::lock_guard lock(mtx);
8182
units[key].reset();
8283
return true;
8384
}
8485

8586
bool is_valid_key(unsigned int key) {
86-
MutexLock lock(&mtx);
87+
cpp::lock_guard lock(mtx);
8788
return units[key].active;
8889
}
8990
};
@@ -113,7 +114,7 @@ class ThreadAtExitCallbackMgr {
113114
constexpr ThreadAtExitCallbackMgr() : mtx(false, false, false) {}
114115

115116
int add_callback(AtExitCallback *callback, void *obj) {
116-
MutexLock lock(&mtx);
117+
cpp::lock_guard lock(mtx);
117118
return callback_list.push_back({callback, obj});
118119
}
119120

libc/src/stdlib/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,7 @@ add_entrypoint_object(
414414
CXX_STANDARD
415415
20 # For constinit of the atexit callback list.
416416
DEPENDS
417+
libc.src.__support.CPP.mutex
417418
libc.src.__support.CPP.new
418419
libc.src.__support.OSUtil.osutil
419420
libc.src.__support.blockstore

libc/src/stdlib/atexit.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "src/stdlib/atexit.h"
10+
#include "src/__support/CPP/mutex.h" // lock_guard
1011
#include "src/__support/blockstore.h"
1112
#include "src/__support/common.h"
1213
#include "src/__support/fixedvector.h"
@@ -68,7 +69,7 @@ void call_exit_callbacks() {
6869
}
6970

7071
int add_atexit_unit(const AtExitUnit &unit) {
71-
MutexLock lock(&handler_list_mtx);
72+
cpp::lock_guard lock(handler_list_mtx);
7273
if (exit_callbacks.push_back(unit))
7374
return 0;
7475
return -1;

libc/src/threads/linux/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ add_header_library(
77
libc.include.sys_syscall
88
libc.include.threads
99
libc.src.__support.CPP.atomic
10+
libc.src.__support.CPP.mutex
1011
libc.src.__support.OSUtil.osutil
1112
libc.src.__support.threads.mutex
1213
libc.src.__support.threads.linux.futex_utils

libc/src/threads/linux/CndVar.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define LLVM_LIBC_SRC_THREADS_LINUX_CNDVAR_H
1111

1212
#include "src/__support/CPP/atomic.h"
13+
#include "src/__support/CPP/mutex.h" // lock_guard
1314
#include "src/__support/CPP/optional.h"
1415
#include "src/__support/OSUtil/syscall.h" // For syscall functions.
1516
#include "src/__support/threads/linux/futex_utils.h"
@@ -59,7 +60,7 @@ struct CndVar {
5960

6061
CndWaiter waiter;
6162
{
62-
MutexLock ml(&qmtx);
63+
cpp::lock_guard ml(qmtx);
6364
CndWaiter *old_back = nullptr;
6465
if (waitq_front == nullptr) {
6566
waitq_front = waitq_back = &waiter;
@@ -118,7 +119,7 @@ struct CndVar {
118119
}
119120

120121
int broadcast() {
121-
MutexLock ml(&qmtx);
122+
cpp::lock_guard ml(qmtx);
122123
uint32_t dummy_futex_word;
123124
CndWaiter *waiter = waitq_front;
124125
waitq_front = waitq_back = nullptr;

libc/test/src/__support/CPP/CMakeLists.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,16 @@ add_libc_test(
6464
libc.src.__support.macros.properties.types
6565
)
6666

67+
add_libc_test(
68+
mutex_test
69+
SUITE
70+
libc-cpp-utils-tests
71+
SRCS
72+
mutex_test.cpp
73+
DEPENDS
74+
libc.src.__support.CPP.mutex
75+
)
76+
6777
add_libc_test(
6878
int_seq_test
6979
SUITE
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
//===-- Unittests for mutex -----------------------------------------------===//
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 "src/__support/CPP/mutex.h"
10+
#include "test/UnitTest/Test.h"
11+
12+
using LIBC_NAMESPACE::cpp::adopt_lock;
13+
using LIBC_NAMESPACE::cpp::lock_guard;
14+
15+
// Simple struct for testing cpp::lock_guard. It defines methods 'lock' and
16+
// 'unlock' which are required for the cpp::lock_guard class template.
17+
struct Mutex {
18+
// Flag to show whether this mutex is locked.
19+
bool locked = false;
20+
21+
// Flag to show if this mutex has been double locked.
22+
bool double_locked = false;
23+
24+
// Flag to show if this mutex has been double unlocked.
25+
bool double_unlocked = false;
26+
27+
Mutex() {}
28+
29+
void lock() {
30+
if (locked)
31+
double_locked = true;
32+
33+
locked = true;
34+
}
35+
36+
void unlock() {
37+
if (!locked)
38+
double_unlocked = true;
39+
40+
locked = false;
41+
}
42+
};
43+
44+
TEST(LlvmLibcMutexTest, Basic) {
45+
Mutex m;
46+
ASSERT_FALSE(m.locked);
47+
ASSERT_FALSE(m.double_locked);
48+
ASSERT_FALSE(m.double_unlocked);
49+
50+
{
51+
lock_guard lg(m);
52+
ASSERT_TRUE(m.locked);
53+
ASSERT_FALSE(m.double_locked);
54+
}
55+
56+
ASSERT_FALSE(m.locked);
57+
ASSERT_FALSE(m.double_unlocked);
58+
}
59+
60+
TEST(LlvmLibcMutexTest, AcquireLocked) {
61+
Mutex m;
62+
ASSERT_FALSE(m.locked);
63+
ASSERT_FALSE(m.double_locked);
64+
ASSERT_FALSE(m.double_unlocked);
65+
66+
// Lock the mutex before placing a lock guard on it.
67+
m.lock();
68+
ASSERT_TRUE(m.locked);
69+
ASSERT_FALSE(m.double_locked);
70+
71+
{
72+
lock_guard lg(m, adopt_lock);
73+
ASSERT_TRUE(m.locked);
74+
ASSERT_FALSE(m.double_locked);
75+
}
76+
77+
ASSERT_FALSE(m.locked);
78+
ASSERT_FALSE(m.double_unlocked);
79+
}

0 commit comments

Comments
 (0)