Skip to content

Commit 987402a

Browse files
committed
[lldb] Improve locking in PathMappingLists (NFC) (llvm#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 llvm#114507. Specifically, Target::SetExecutableModule calls Target::GetOrCreateModule, which potentially performs path remapping, which in turns has a callback to Target::SetExecutableModule. (cherry picked from commit 8f8e2b7)
1 parent fa4e2c1 commit 987402a

File tree

2 files changed

+115
-80
lines changed

2 files changed

+115
-80
lines changed

lldb/include/lldb/Target/PathMappingList.h

Lines changed: 14 additions & 8 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

@@ -134,28 +133,35 @@ class PathMappingList {
134133
/// The newly remapped filespec that is guaranteed to exist.
135134
std::optional<FileSpec> FindFile(const FileSpec &orig_spec) const;
136135

137-
uint32_t FindIndexForPath(llvm::StringRef path) const;
138-
139136
uint32_t GetModificationID() const {
140-
std::lock_guard<std::recursive_mutex> lock(m_mutex);
137+
std::lock_guard<std::mutex> lock(m_pairs_mutex);
141138
return m_mod_id;
142139
}
143140

144141
protected:
145-
mutable std::recursive_mutex m_mutex;
146142
typedef std::pair<ConstString, ConstString> pair;
147143
typedef std::vector<pair> collection;
148144
typedef collection::iterator iterator;
149145
typedef collection::const_iterator const_iterator;
150146

147+
void AppendNoLock(llvm::StringRef path, llvm::StringRef replacement);
148+
uint32_t FindIndexForPathNoLock(llvm::StringRef path) const;
149+
void Notify(bool notify) const;
150+
151151
iterator FindIteratorForPath(ConstString path);
152152

153153
const_iterator FindIteratorForPath(ConstString path) const;
154154

155155
collection m_pairs;
156+
mutable std::mutex m_pairs_mutex;
157+
156158
ChangedCallback m_callback = nullptr;
157159
void *m_callback_baton = nullptr;
158-
uint32_t m_mod_id = 0; // Incremented anytime anything is added or removed.
160+
mutable std::mutex m_callback_mutex;
161+
162+
/// Incremented anytime anything is added to or removed from m_pairs. Also
163+
/// protected by m_pairs_mutex.
164+
uint32_t m_mod_id = 0;
159165
};
160166

161167
} // namespace lldb_private

lldb/source/Target/PathMappingList.cpp

Lines changed: 101 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ 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, std::mutex> locks(
52+
m_callback_mutex, m_pairs_mutex, rhs.m_pairs_mutex);
5253
m_pairs = rhs.m_pairs;
5354
m_callback = nullptr;
5455
m_callback_baton = nullptr;
@@ -59,85 +60,111 @@ const PathMappingList &PathMappingList::operator=(const PathMappingList &rhs) {
5960

6061
PathMappingList::~PathMappingList() = default;
6162

62-
void PathMappingList::Append(llvm::StringRef path, llvm::StringRef replacement,
63-
bool notify) {
64-
std::lock_guard<std::recursive_mutex> lock(m_mutex);
63+
void PathMappingList::AppendNoLock(llvm::StringRef path,
64+
llvm::StringRef replacement) {
6565
++m_mod_id;
6666
m_pairs.emplace_back(pair(NormalizePath(path), NormalizePath(replacement)));
67-
if (notify && m_callback)
68-
m_callback(*this, m_callback_baton);
67+
}
68+
69+
void PathMappingList::Notify(bool notify) const {
70+
ChangedCallback callback = nullptr;
71+
void *baton = nullptr;
72+
{
73+
std::lock_guard<std::mutex> lock(m_callback_mutex);
74+
callback = m_callback;
75+
baton = m_callback_baton;
76+
}
77+
if (notify && callback)
78+
callback(*this, baton);
79+
}
80+
81+
void PathMappingList::Append(llvm::StringRef path, llvm::StringRef replacement,
82+
bool notify) {
83+
{
84+
std::lock_guard<std::mutex> lock(m_pairs_mutex);
85+
AppendNoLock(path, replacement);
86+
}
87+
Notify(notify);
6988
}
7089

7190
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()) {
91+
{
92+
std::scoped_lock<std::mutex, std::mutex> locks(m_pairs_mutex,
93+
rhs.m_pairs_mutex);
94+
++m_mod_id;
95+
if (rhs.m_pairs.empty())
96+
return;
7597
const_iterator pos, end = rhs.m_pairs.end();
7698
for (pos = rhs.m_pairs.begin(); pos != end; ++pos)
7799
m_pairs.push_back(*pos);
78-
if (notify && m_callback)
79-
m_callback(*this, m_callback_baton);
80100
}
101+
Notify(notify);
81102
}
82103

83104
bool PathMappingList::AppendUnique(llvm::StringRef path,
84105
llvm::StringRef replacement, bool notify) {
85106
auto normalized_path = NormalizePath(path);
86107
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;
108+
{
109+
std::lock_guard<std::mutex> lock(m_pairs_mutex);
110+
for (const auto &pair : m_pairs) {
111+
if (pair.first.GetStringRef() == normalized_path &&
112+
pair.second.GetStringRef() == normalized_replacement)
113+
return false;
114+
}
115+
AppendNoLock(path, replacement);
92116
}
93-
Append(path, replacement, notify);
117+
Notify(notify);
94118
return true;
95119
}
96120

97121
void PathMappingList::Insert(llvm::StringRef path, llvm::StringRef replacement,
98122
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);
123+
{
124+
std::lock_guard<std::mutex> lock(m_pairs_mutex);
125+
++m_mod_id;
126+
iterator insert_iter;
127+
if (index >= m_pairs.size())
128+
insert_iter = m_pairs.end();
129+
else
130+
insert_iter = m_pairs.begin() + index;
131+
m_pairs.emplace(insert_iter,
132+
pair(NormalizePath(path), NormalizePath(replacement)));
133+
}
134+
Notify(notify);
110135
}
111136

112137
bool PathMappingList::Replace(llvm::StringRef path, llvm::StringRef replacement,
113138
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);
139+
{
140+
std::lock_guard<std::mutex> lock(m_pairs_mutex);
141+
if (index >= m_pairs.size())
142+
return false;
143+
++m_mod_id;
144+
m_pairs[index] = pair(NormalizePath(path), NormalizePath(replacement));
145+
}
146+
Notify(notify);
121147
return true;
122148
}
123149

124150
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;
151+
{
152+
std::lock_guard<std::mutex> lock(m_pairs_mutex);
153+
if (index >= m_pairs.size())
154+
return false;
128155

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);
156+
++m_mod_id;
157+
iterator iter = m_pairs.begin() + index;
158+
m_pairs.erase(iter);
159+
}
160+
Notify(notify);
134161
return true;
135162
}
136163

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

143170
if (pair_index < 0) {
@@ -155,7 +182,7 @@ void PathMappingList::Dump(Stream *s, int pair_index) {
155182

156183
llvm::json::Value PathMappingList::ToJSON() {
157184
llvm::json::Array entries;
158-
std::lock_guard<std::recursive_mutex> lock(m_mutex);
185+
std::lock_guard<std::mutex> lock(m_pairs_mutex);
159186
for (const auto &pair : m_pairs) {
160187
llvm::json::Array entry{pair.first.GetStringRef().str(),
161188
pair.second.GetStringRef().str()};
@@ -165,12 +192,13 @@ llvm::json::Value PathMappingList::ToJSON() {
165192
}
166193

167194
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);
195+
{
196+
std::lock_guard<std::mutex> lock(m_pairs_mutex);
197+
if (!m_pairs.empty())
198+
++m_mod_id;
199+
m_pairs.clear();
200+
}
201+
Notify(notify);
174202
}
175203

176204
bool PathMappingList::RemapPath(ConstString path,
@@ -196,7 +224,7 @@ static void AppendPathComponents(FileSpec &path, llvm::StringRef components,
196224

197225
std::optional<FileSpec> PathMappingList::RemapPath(llvm::StringRef mapping_path,
198226
bool only_if_exists) const {
199-
std::lock_guard<std::recursive_mutex> lock(m_mutex);
227+
std::lock_guard<std::mutex> lock(m_pairs_mutex);
200228
if (m_pairs.empty() || mapping_path.empty())
201229
return {};
202230
LazyBool path_is_relative = eLazyBoolCalculate;
@@ -235,7 +263,7 @@ std::optional<llvm::StringRef>
235263
PathMappingList::ReverseRemapPath(const FileSpec &file, FileSpec &fixed) const {
236264
std::string path = file.GetPath();
237265
llvm::StringRef path_ref(path);
238-
std::lock_guard<std::recursive_mutex> lock(m_mutex);
266+
std::lock_guard<std::mutex> lock(m_pairs_mutex);
239267
for (const auto &it : m_pairs) {
240268
llvm::StringRef removed_prefix = it.second.GetStringRef();
241269
if (!path_ref.consume_front(it.second.GetStringRef()))
@@ -264,34 +292,35 @@ PathMappingList::FindFile(const FileSpec &orig_spec) const {
264292

265293
bool PathMappingList::Replace(llvm::StringRef path, llvm::StringRef new_path,
266294
bool notify) {
267-
std::lock_guard<std::recursive_mutex> lock(m_mutex);
268-
uint32_t idx = FindIndexForPath(path);
269-
if (idx < m_pairs.size()) {
295+
{
296+
std::lock_guard<std::mutex> lock(m_pairs_mutex);
297+
uint32_t idx = FindIndexForPathNoLock(path);
298+
if (idx >= m_pairs.size())
299+
return false;
270300
++m_mod_id;
271301
m_pairs[idx].second = ConstString(new_path);
272-
if (notify && m_callback)
273-
m_callback(*this, m_callback_baton);
274-
return true;
275302
}
276-
return false;
303+
Notify(notify);
304+
return true;
277305
}
278306

279307
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()) {
308+
{
309+
std::lock_guard<std::mutex> lock(m_pairs_mutex);
310+
iterator pos = FindIteratorForPath(path);
311+
if (pos == m_pairs.end())
312+
return false;
313+
283314
++m_mod_id;
284315
m_pairs.erase(pos);
285-
if (notify && m_callback)
286-
m_callback(*this, m_callback_baton);
287-
return true;
288316
}
289-
return false;
317+
Notify(notify);
318+
return true;
290319
}
291320

292321
PathMappingList::const_iterator
293322
PathMappingList::FindIteratorForPath(ConstString path) const {
294-
std::lock_guard<std::recursive_mutex> lock(m_mutex);
323+
std::lock_guard<std::mutex> lock(m_pairs_mutex);
295324
const_iterator pos;
296325
const_iterator begin = m_pairs.begin();
297326
const_iterator end = m_pairs.end();
@@ -305,7 +334,7 @@ PathMappingList::FindIteratorForPath(ConstString path) const {
305334

306335
PathMappingList::iterator
307336
PathMappingList::FindIteratorForPath(ConstString path) {
308-
std::lock_guard<std::recursive_mutex> lock(m_mutex);
337+
std::lock_guard<std::mutex> lock(m_pairs_mutex);
309338
iterator pos;
310339
iterator begin = m_pairs.begin();
311340
iterator end = m_pairs.end();
@@ -319,7 +348,7 @@ PathMappingList::FindIteratorForPath(ConstString path) {
319348

320349
bool PathMappingList::GetPathsAtIndex(uint32_t idx, ConstString &path,
321350
ConstString &new_path) const {
322-
std::lock_guard<std::recursive_mutex> lock(m_mutex);
351+
std::lock_guard<std::mutex> lock(m_pairs_mutex);
323352
if (idx < m_pairs.size()) {
324353
path = m_pairs[idx].first;
325354
new_path = m_pairs[idx].second;
@@ -328,9 +357,9 @@ bool PathMappingList::GetPathsAtIndex(uint32_t idx, ConstString &path,
328357
return false;
329358
}
330359

331-
uint32_t PathMappingList::FindIndexForPath(llvm::StringRef orig_path) const {
360+
uint32_t
361+
PathMappingList::FindIndexForPathNoLock(llvm::StringRef orig_path) const {
332362
const ConstString path = ConstString(NormalizePath(orig_path));
333-
std::lock_guard<std::recursive_mutex> lock(m_mutex);
334363
const_iterator pos;
335364
const_iterator begin = m_pairs.begin();
336365
const_iterator end = m_pairs.end();

0 commit comments

Comments
 (0)