Skip to content

Commit c820994

Browse files
authored
[lldb] Improve locking in PathMappingLists (NFC) (#114576)
In [D148380](https://reviews.llvm.org/D148380), Alex added locking to PathMappingLists. The current implementation runs the callback under the lock, which I don't believe is necessary. As far as I can tell, no users of the callback are relying on the list not having been modified until the callback is handled. This patch implements my suggestion to unlock the mutex before the callback. I also switched to a non-recursive mutex as I don't believe the recursive property is needed. To make the class fully thread safe, I did have to introduce another mutex to protect the callback members. The motivation for this change is #114507. Specifically, Target::SetExecutableModule calls Target::GetOrCreateModule, which potentially performs path remapping, which in turns has a callback to Target::SetExecutableModule.
1 parent 8ff60c4 commit c820994

File tree

2 files changed

+107
-75
lines changed

2 files changed

+107
-75
lines changed

lldb/include/lldb/Target/PathMappingList.h

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ class PathMappingList {
2525
typedef void (*ChangedCallback)(const PathMappingList &path_list,
2626
void *baton);
2727

28-
// Constructors and Destructors
2928
PathMappingList();
3029

3130
PathMappingList(ChangedCallback callback, void *callback_baton);
@@ -53,12 +52,12 @@ class PathMappingList {
5352
llvm::json::Value ToJSON();
5453

5554
bool IsEmpty() const {
56-
std::lock_guard<std::recursive_mutex> lock(m_mutex);
55+
std::lock_guard<std::mutex> lock(m_pairs_mutex);
5756
return m_pairs.empty();
5857
}
5958

6059
size_t GetSize() const {
61-
std::lock_guard<std::recursive_mutex> lock(m_mutex);
60+
std::lock_guard<std::mutex> lock(m_pairs_mutex);
6261
return m_pairs.size();
6362
}
6463

@@ -137,25 +136,33 @@ class PathMappingList {
137136
uint32_t FindIndexForPath(llvm::StringRef path) const;
138137

139138
uint32_t GetModificationID() const {
140-
std::lock_guard<std::recursive_mutex> lock(m_mutex);
139+
std::lock_guard<std::mutex> lock(m_pairs_mutex);
141140
return m_mod_id;
142141
}
143142

144143
protected:
145-
mutable std::recursive_mutex m_mutex;
146144
typedef std::pair<ConstString, ConstString> pair;
147145
typedef std::vector<pair> collection;
148146
typedef collection::iterator iterator;
149147
typedef collection::const_iterator const_iterator;
150148

149+
void AppendImpl(llvm::StringRef path, llvm::StringRef replacement);
150+
void Notify(bool notify) const;
151+
151152
iterator FindIteratorForPath(ConstString path);
152153

153154
const_iterator FindIteratorForPath(ConstString path) const;
154155

155156
collection m_pairs;
157+
mutable std::mutex m_pairs_mutex;
158+
156159
ChangedCallback m_callback = nullptr;
157160
void *m_callback_baton = nullptr;
158-
uint32_t m_mod_id = 0; // Incremented anytime anything is added or removed.
161+
mutable std::mutex m_callback_mutex;
162+
163+
/// Incremented anytime anything is added to or removed from m_pairs. Also
164+
/// protected by m_pairs_mutex.
165+
uint32_t m_mod_id = 0;
159166
};
160167

161168
} // namespace lldb_private

lldb/source/Target/PathMappingList.cpp

Lines changed: 94 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,10 @@ PathMappingList::PathMappingList(const PathMappingList &rhs)
4848

4949
const PathMappingList &PathMappingList::operator=(const PathMappingList &rhs) {
5050
if (this != &rhs) {
51-
std::scoped_lock<std::recursive_mutex, std::recursive_mutex> locks(m_mutex, rhs.m_mutex);
51+
std::scoped_lock<std::mutex, std::mutex> callback_locks(
52+
m_callback_mutex, rhs.m_callback_mutex);
53+
std::scoped_lock<std::mutex, std::mutex> pairs_locks(m_pairs_mutex,
54+
rhs.m_pairs_mutex);
5255
m_pairs = rhs.m_pairs;
5356
m_callback = nullptr;
5457
m_callback_baton = nullptr;
@@ -59,85 +62,105 @@ const PathMappingList &PathMappingList::operator=(const PathMappingList &rhs) {
5962

6063
PathMappingList::~PathMappingList() = default;
6164

62-
void PathMappingList::Append(llvm::StringRef path, llvm::StringRef replacement,
63-
bool notify) {
64-
std::lock_guard<std::recursive_mutex> lock(m_mutex);
65+
void PathMappingList::AppendImpl(llvm::StringRef path,
66+
llvm::StringRef replacement) {
6567
++m_mod_id;
6668
m_pairs.emplace_back(pair(NormalizePath(path), NormalizePath(replacement)));
69+
}
70+
71+
void PathMappingList::Notify(bool notify) const {
72+
std::lock_guard<std::mutex> lock(m_callback_mutex);
6773
if (notify && m_callback)
6874
m_callback(*this, m_callback_baton);
6975
}
7076

77+
void PathMappingList::Append(llvm::StringRef path, llvm::StringRef replacement,
78+
bool notify) {
79+
{
80+
std::lock_guard<std::mutex> lock(m_pairs_mutex);
81+
AppendImpl(path, replacement);
82+
}
83+
Notify(notify);
84+
}
85+
7186
void PathMappingList::Append(const PathMappingList &rhs, bool notify) {
72-
std::scoped_lock<std::recursive_mutex, std::recursive_mutex> locks(m_mutex, rhs.m_mutex);
73-
++m_mod_id;
74-
if (!rhs.m_pairs.empty()) {
87+
{
88+
std::scoped_lock<std::mutex, std::mutex> locks(m_pairs_mutex,
89+
rhs.m_pairs_mutex);
90+
++m_mod_id;
91+
if (rhs.m_pairs.empty())
92+
return;
7593
const_iterator pos, end = rhs.m_pairs.end();
7694
for (pos = rhs.m_pairs.begin(); pos != end; ++pos)
7795
m_pairs.push_back(*pos);
78-
if (notify && m_callback)
79-
m_callback(*this, m_callback_baton);
8096
}
97+
Notify(notify);
8198
}
8299

83100
bool PathMappingList::AppendUnique(llvm::StringRef path,
84101
llvm::StringRef replacement, bool notify) {
85102
auto normalized_path = NormalizePath(path);
86103
auto normalized_replacement = NormalizePath(replacement);
87-
std::lock_guard<std::recursive_mutex> lock(m_mutex);
88-
for (const auto &pair : m_pairs) {
89-
if (pair.first.GetStringRef() == normalized_path &&
90-
pair.second.GetStringRef() == normalized_replacement)
91-
return false;
104+
{
105+
std::lock_guard<std::mutex> lock(m_pairs_mutex);
106+
for (const auto &pair : m_pairs) {
107+
if (pair.first.GetStringRef() == normalized_path &&
108+
pair.second.GetStringRef() == normalized_replacement)
109+
return false;
110+
}
111+
AppendImpl(path, replacement);
92112
}
93-
Append(path, replacement, notify);
113+
Notify(notify);
94114
return true;
95115
}
96116

97117
void PathMappingList::Insert(llvm::StringRef path, llvm::StringRef replacement,
98118
uint32_t index, bool notify) {
99-
std::lock_guard<std::recursive_mutex> lock(m_mutex);
100-
++m_mod_id;
101-
iterator insert_iter;
102-
if (index >= m_pairs.size())
103-
insert_iter = m_pairs.end();
104-
else
105-
insert_iter = m_pairs.begin() + index;
106-
m_pairs.emplace(insert_iter, pair(NormalizePath(path),
107-
NormalizePath(replacement)));
108-
if (notify && m_callback)
109-
m_callback(*this, m_callback_baton);
119+
{
120+
std::lock_guard<std::mutex> lock(m_pairs_mutex);
121+
++m_mod_id;
122+
iterator insert_iter;
123+
if (index >= m_pairs.size())
124+
insert_iter = m_pairs.end();
125+
else
126+
insert_iter = m_pairs.begin() + index;
127+
m_pairs.emplace(insert_iter,
128+
pair(NormalizePath(path), NormalizePath(replacement)));
129+
}
130+
Notify(notify);
110131
}
111132

112133
bool PathMappingList::Replace(llvm::StringRef path, llvm::StringRef replacement,
113134
uint32_t index, bool notify) {
114-
std::lock_guard<std::recursive_mutex> lock(m_mutex);
115-
if (index >= m_pairs.size())
116-
return false;
117-
++m_mod_id;
118-
m_pairs[index] = pair(NormalizePath(path), NormalizePath(replacement));
119-
if (notify && m_callback)
120-
m_callback(*this, m_callback_baton);
135+
{
136+
std::lock_guard<std::mutex> lock(m_pairs_mutex);
137+
if (index >= m_pairs.size())
138+
return false;
139+
++m_mod_id;
140+
m_pairs[index] = pair(NormalizePath(path), NormalizePath(replacement));
141+
}
142+
Notify(notify);
121143
return true;
122144
}
123145

124146
bool PathMappingList::Remove(size_t index, bool notify) {
125-
std::lock_guard<std::recursive_mutex> lock(m_mutex);
126-
if (index >= m_pairs.size())
127-
return false;
147+
{
148+
std::lock_guard<std::mutex> lock(m_pairs_mutex);
149+
if (index >= m_pairs.size())
150+
return false;
128151

129-
++m_mod_id;
130-
iterator iter = m_pairs.begin() + index;
131-
m_pairs.erase(iter);
132-
if (notify && m_callback)
133-
m_callback(*this, m_callback_baton);
152+
++m_mod_id;
153+
iterator iter = m_pairs.begin() + index;
154+
m_pairs.erase(iter);
155+
}
156+
Notify(notify);
134157
return true;
135158
}
136159

137160
// For clients which do not need the pair index dumped, pass a pair_index >= 0
138161
// to only dump the indicated pair.
139162
void PathMappingList::Dump(Stream *s, int pair_index) {
140-
std::lock_guard<std::recursive_mutex> lock(m_mutex);
163+
std::lock_guard<std::mutex> lock(m_pairs_mutex);
141164
unsigned int numPairs = m_pairs.size();
142165

143166
if (pair_index < 0) {
@@ -155,7 +178,7 @@ void PathMappingList::Dump(Stream *s, int pair_index) {
155178

156179
llvm::json::Value PathMappingList::ToJSON() {
157180
llvm::json::Array entries;
158-
std::lock_guard<std::recursive_mutex> lock(m_mutex);
181+
std::lock_guard<std::mutex> lock(m_pairs_mutex);
159182
for (const auto &pair : m_pairs) {
160183
llvm::json::Array entry{pair.first.GetStringRef().str(),
161184
pair.second.GetStringRef().str()};
@@ -165,12 +188,13 @@ llvm::json::Value PathMappingList::ToJSON() {
165188
}
166189

167190
void PathMappingList::Clear(bool notify) {
168-
std::lock_guard<std::recursive_mutex> lock(m_mutex);
169-
if (!m_pairs.empty())
170-
++m_mod_id;
171-
m_pairs.clear();
172-
if (notify && m_callback)
173-
m_callback(*this, m_callback_baton);
191+
{
192+
std::lock_guard<std::mutex> lock(m_pairs_mutex);
193+
if (!m_pairs.empty())
194+
++m_mod_id;
195+
m_pairs.clear();
196+
}
197+
Notify(notify);
174198
}
175199

176200
bool PathMappingList::RemapPath(ConstString path,
@@ -196,7 +220,7 @@ static void AppendPathComponents(FileSpec &path, llvm::StringRef components,
196220

197221
std::optional<FileSpec> PathMappingList::RemapPath(llvm::StringRef mapping_path,
198222
bool only_if_exists) const {
199-
std::lock_guard<std::recursive_mutex> lock(m_mutex);
223+
std::lock_guard<std::mutex> lock(m_pairs_mutex);
200224
if (m_pairs.empty() || mapping_path.empty())
201225
return {};
202226
LazyBool path_is_relative = eLazyBoolCalculate;
@@ -235,7 +259,7 @@ std::optional<llvm::StringRef>
235259
PathMappingList::ReverseRemapPath(const FileSpec &file, FileSpec &fixed) const {
236260
std::string path = file.GetPath();
237261
llvm::StringRef path_ref(path);
238-
std::lock_guard<std::recursive_mutex> lock(m_mutex);
262+
std::lock_guard<std::mutex> lock(m_pairs_mutex);
239263
for (const auto &it : m_pairs) {
240264
llvm::StringRef removed_prefix = it.second.GetStringRef();
241265
if (!path_ref.consume_front(it.second.GetStringRef()))
@@ -264,34 +288,35 @@ PathMappingList::FindFile(const FileSpec &orig_spec) const {
264288

265289
bool PathMappingList::Replace(llvm::StringRef path, llvm::StringRef new_path,
266290
bool notify) {
267-
std::lock_guard<std::recursive_mutex> lock(m_mutex);
268-
uint32_t idx = FindIndexForPath(path);
269-
if (idx < m_pairs.size()) {
291+
{
292+
std::lock_guard<std::mutex> lock(m_pairs_mutex);
293+
uint32_t idx = FindIndexForPath(path);
294+
if (idx >= m_pairs.size())
295+
return false;
270296
++m_mod_id;
271297
m_pairs[idx].second = ConstString(new_path);
272-
if (notify && m_callback)
273-
m_callback(*this, m_callback_baton);
274-
return true;
275298
}
276-
return false;
299+
Notify(notify);
300+
return true;
277301
}
278302

279303
bool PathMappingList::Remove(ConstString path, bool notify) {
280-
std::lock_guard<std::recursive_mutex> lock(m_mutex);
281-
iterator pos = FindIteratorForPath(path);
282-
if (pos != m_pairs.end()) {
304+
{
305+
std::lock_guard<std::mutex> lock(m_pairs_mutex);
306+
iterator pos = FindIteratorForPath(path);
307+
if (pos == m_pairs.end())
308+
return false;
309+
283310
++m_mod_id;
284311
m_pairs.erase(pos);
285-
if (notify && m_callback)
286-
m_callback(*this, m_callback_baton);
287-
return true;
288312
}
289-
return false;
313+
Notify(notify);
314+
return true;
290315
}
291316

292317
PathMappingList::const_iterator
293318
PathMappingList::FindIteratorForPath(ConstString path) const {
294-
std::lock_guard<std::recursive_mutex> lock(m_mutex);
319+
std::lock_guard<std::mutex> lock(m_pairs_mutex);
295320
const_iterator pos;
296321
const_iterator begin = m_pairs.begin();
297322
const_iterator end = m_pairs.end();
@@ -305,7 +330,7 @@ PathMappingList::FindIteratorForPath(ConstString path) const {
305330

306331
PathMappingList::iterator
307332
PathMappingList::FindIteratorForPath(ConstString path) {
308-
std::lock_guard<std::recursive_mutex> lock(m_mutex);
333+
std::lock_guard<std::mutex> lock(m_pairs_mutex);
309334
iterator pos;
310335
iterator begin = m_pairs.begin();
311336
iterator end = m_pairs.end();
@@ -319,7 +344,7 @@ PathMappingList::FindIteratorForPath(ConstString path) {
319344

320345
bool PathMappingList::GetPathsAtIndex(uint32_t idx, ConstString &path,
321346
ConstString &new_path) const {
322-
std::lock_guard<std::recursive_mutex> lock(m_mutex);
347+
std::lock_guard<std::mutex> lock(m_pairs_mutex);
323348
if (idx < m_pairs.size()) {
324349
path = m_pairs[idx].first;
325350
new_path = m_pairs[idx].second;
@@ -330,7 +355,7 @@ bool PathMappingList::GetPathsAtIndex(uint32_t idx, ConstString &path,
330355

331356
uint32_t PathMappingList::FindIndexForPath(llvm::StringRef orig_path) const {
332357
const ConstString path = ConstString(NormalizePath(orig_path));
333-
std::lock_guard<std::recursive_mutex> lock(m_mutex);
358+
std::lock_guard<std::mutex> lock(m_pairs_mutex);
334359
const_iterator pos;
335360
const_iterator begin = m_pairs.begin();
336361
const_iterator end = m_pairs.end();

0 commit comments

Comments
 (0)