Skip to content

Commit fbc2eaa

Browse files
Merge pull request #7120 from adrian-prantl/112025620
Replace hand-rolled SharedMutex with C++17 std::shared_mutex (NFCI)
2 parents 492b878 + e90fe50 commit fbc2eaa

File tree

4 files changed

+115
-130
lines changed

4 files changed

+115
-130
lines changed

lldb/include/lldb/Core/SwiftScratchContextReader.h

Lines changed: 13 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -13,64 +13,14 @@
1313
#ifndef liblldb_SwiftASTContextReader_h_
1414
#define liblldb_SwiftASTContextReader_h_
1515

16-
#include "llvm/Support/RWMutex.h"
16+
#include <shared_mutex>
1717

1818
namespace lldb_private {
1919

2020
class TypeSystemSwiftTypeRefForExpressions;
2121
class ExecutionContext;
2222
class ExecutionContextRef;
2323

24-
/// This is like llvm::sys::SmartRWMutex<true>, but with a try_lock method.
25-
///
26-
/// FIXME: Replace this with a C++14 shared_timed_mutex or a C++17
27-
/// share_mutex as soon as possible.
28-
class SharedMutex {
29-
llvm::sys::SmartRWMutex<true> m_impl;
30-
unsigned m_readers = 0;
31-
std::mutex m_reader_mutex;
32-
public:
33-
SharedMutex() = default;
34-
SharedMutex(const SharedMutex &) = delete;
35-
SharedMutex &operator=(const SharedMutex &) = delete;
36-
bool lock_shared() {
37-
std::lock_guard<std::mutex> lock(m_reader_mutex);
38-
++m_readers;
39-
return m_impl.lock_shared();
40-
}
41-
bool unlock_shared() {
42-
std::lock_guard<std::mutex> lock(m_reader_mutex);
43-
assert(m_readers > 0);
44-
--m_readers;
45-
return m_impl.unlock_shared();
46-
}
47-
bool try_lock() {
48-
std::lock_guard<std::mutex> lock(m_reader_mutex);
49-
return m_readers ? false : m_impl.lock();
50-
}
51-
bool unlock() { return m_impl.unlock(); }
52-
};
53-
54-
/// RAII acquisition of a reader lock.
55-
struct ScopedSharedMutexReader {
56-
SharedMutex *m_mutex;
57-
explicit ScopedSharedMutexReader(SharedMutex *m) : m_mutex(m) {
58-
if (m_mutex)
59-
m_mutex->lock_shared();
60-
}
61-
62-
ScopedSharedMutexReader(const ScopedSharedMutexReader &copy)
63-
: m_mutex(copy.m_mutex) {
64-
if (m_mutex)
65-
m_mutex->lock_shared();
66-
}
67-
68-
~ScopedSharedMutexReader() {
69-
if (m_mutex)
70-
m_mutex->unlock_shared();
71-
}
72-
};
73-
7424
/// A scratch Swift context pointer and its reader lock.
7525
/// The Swift scratch context may need to be replaced when it gets corrupted,
7626
/// for example due to incompatible ClangImporter options. This locking
@@ -97,27 +47,25 @@ struct ScopedSharedMutexReader {
9747
/// or even separate scratch contexts for each lldb::Module. But it
9848
/// will only do this if no client holds on to a read lock on \b
9949
/// m_scratch_typesystem_lock.
100-
class SwiftScratchContextReader : ScopedSharedMutexReader {
101-
TypeSystemSwiftTypeRefForExpressions *m_ptr;
50+
class SwiftScratchContextReader {
51+
std::shared_lock<std::shared_mutex> m_lock;
52+
TypeSystemSwiftTypeRefForExpressions *m_ts;
10253

10354
public:
104-
SwiftScratchContextReader(SharedMutex &mutex,
105-
TypeSystemSwiftTypeRefForExpressions &ctx)
106-
: ScopedSharedMutexReader(&mutex), m_ptr(&ctx) {
107-
assert(m_ptr && "invalid context");
108-
}
109-
110-
TypeSystemSwiftTypeRefForExpressions *get() {
111-
assert(m_ptr && "invalid context");
112-
return m_ptr;
113-
}
114-
55+
SwiftScratchContextReader(std::shared_lock<std::shared_mutex> &&lock,
56+
TypeSystemSwiftTypeRefForExpressions &ts);
57+
SwiftScratchContextReader(const SwiftScratchContextReader &) = delete;
58+
SwiftScratchContextReader(SwiftScratchContextReader &&other) = default;
59+
SwiftScratchContextReader &
60+
operator=(SwiftScratchContextReader &&other) = default;
61+
TypeSystemSwiftTypeRefForExpressions *get() { return m_ts; }
11562
TypeSystemSwiftTypeRefForExpressions *operator->() { return get(); }
11663
TypeSystemSwiftTypeRefForExpressions &operator*() { return *get(); }
11764
};
11865

11966
/// An RAII object that just acquires the reader lock.
120-
struct SwiftScratchContextLock : ScopedSharedMutexReader {
67+
struct SwiftScratchContextLock {
68+
std::shared_lock<std::shared_mutex> lock;
12169
SwiftScratchContextLock(const ExecutionContextRef *exe_ctx_ref);
12270
SwiftScratchContextLock(const ExecutionContext *exe_ctx);
12371
};

lldb/include/lldb/Target/Target.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1257,7 +1257,7 @@ class Target : public std::enable_shared_from_this<Target>,
12571257

12581258
#ifdef LLDB_ENABLE_SWIFT
12591259
/// Get the lock guarding the scratch typesystem from being re-initialized.
1260-
SharedMutex &GetSwiftScratchContextLock() {
1260+
std::shared_mutex &GetSwiftScratchContextLock() {
12611261
return m_scratch_typesystem_lock;
12621262
}
12631263

@@ -1694,7 +1694,7 @@ class Target : public std::enable_shared_from_this<Target>,
16941694
m_scratch_typesystem_for_module;
16951695

16961696
/// Guards the scratch typesystem from being re-initialized.
1697-
SharedMutex m_scratch_typesystem_lock;
1697+
std::shared_mutex m_scratch_typesystem_lock;
16981698

16991699
static void ImageSearchPathsChanged(const PathMappingList &path_list,
17001700
void *baton);

lldb/source/Core/ValueObjectDynamicValue.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -450,8 +450,8 @@ bool ValueObjectDynamicValue::DynamicValueTypeInfoNeedsUpdate() {
450450

451451
#ifdef LLDB_ENABLE_SWIFT
452452
auto cached_ctx = m_value.GetCompilerType().GetTypeSystem();
453-
llvm::Optional<SwiftScratchContextReader> scratch_ctx =
454-
GetSwiftScratchContext();
453+
llvm::Optional<SwiftScratchContextReader> scratch_ctx(
454+
GetSwiftScratchContext());
455455

456456
if (!scratch_ctx || !cached_ctx)
457457
return true;

lldb/source/Target/Target.cpp

Lines changed: 98 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -2426,12 +2426,12 @@ Target::GetScratchTypeSystemForLanguage(lldb::LanguageType language,
24262426
if (swift_ast_ctx && (swift_ast_ctx->CheckProcessChanged() ||
24272427
swift_ast_ctx->HasFatalErrors())) {
24282428
// If it is safe to replace the scratch context, do so. If
2429-
// try_lock() fails, then higher stack frame (or another
2429+
// try_lock() fails, then a higher stack frame (or another
24302430
// thread) is holding a read lock to the scratch context and
24312431
// replacing it could cause a use-after-free later on.
2432-
if (GetSwiftScratchContextLock().try_lock()) {
2433-
auto unlock = llvm::make_scope_exit(
2434-
[this] { GetSwiftScratchContextLock().unlock(); });
2432+
auto &lock = GetSwiftScratchContextLock();
2433+
if (lock.try_lock()) {
2434+
std::lock_guard<std::shared_mutex> unlock(lock, std::adopt_lock);
24352435
if (m_use_scratch_typesystem_per_module)
24362436
DisplayFallbackSwiftContextErrors(swift_ast_ctx);
24372437
else if (StreamSP errs = GetDebugger().GetAsyncErrorStream()) {
@@ -2716,66 +2716,77 @@ llvm::Optional<SwiftScratchContextReader> Target::GetSwiftScratchContext(
27162716
}
27172717
}
27182718
}
2719-
2720-
auto get_or_create_fallback_context =
2721-
[&]() -> TypeSystemSwiftTypeRefForExpressions * {
2722-
if (!lldb_module || !m_use_scratch_typesystem_per_module)
2723-
return nullptr;
27242719

2725-
ModuleLanguage idx = {lldb_module, lldb::eLanguageTypeSwift};
2726-
auto cached = m_scratch_typesystem_for_module.find(idx);
2727-
if (cached != m_scratch_typesystem_for_module.end()) {
2728-
auto *cached_ts =
2729-
llvm::cast<TypeSystemSwiftTypeRefForExpressions>(cached->second.get());
2730-
if (!cached_ts)
2731-
return nullptr;
2720+
auto get_cached_module_ts =
2721+
[&](Module *lldb_module) -> TypeSystemSwiftTypeRefForExpressions * {
2722+
ModuleLanguage key = {lldb_module, lldb::eLanguageTypeSwift};
2723+
auto cached = m_scratch_typesystem_for_module.find(key);
2724+
if (cached != m_scratch_typesystem_for_module.end())
2725+
return llvm::cast<TypeSystemSwiftTypeRefForExpressions>(cached->second.get());
2726+
return nullptr;
2727+
};
2728+
2729+
auto maybe_create_fallback_context = [&]() {
2730+
ModuleLanguage key = {lldb_module, lldb::eLanguageTypeSwift};
2731+
if (auto *cached_ts = get_cached_module_ts(lldb_module)) {
27322732
auto *cached_ast_ctx =
27332733
llvm::dyn_cast_or_null<SwiftASTContextForExpressions>(
27342734
cached_ts->GetSwiftASTContext());
27352735
if (cached_ast_ctx && cached_ast_ctx->HasFatalErrors() &&
27362736
!m_cant_make_scratch_type_system.count(lldb::eLanguageTypeSwift)) {
27372737
DisplayFallbackSwiftContextErrors(cached_ast_ctx);
27382738
// Try again.
2739-
m_scratch_typesystem_for_module.erase(cached);
2740-
return nullptr;
2739+
// FIXME: Shouldn't this continue rather than return?
2740+
auto &lock = GetSwiftScratchContextLock();
2741+
if (!lock.try_lock()) {
2742+
if (log)
2743+
log->Printf("module scratch context has errors but couldn't "
2744+
"acquire scratch context lock\n");
2745+
return;
2746+
}
2747+
std::lock_guard<std::shared_mutex> unlock(lock, std::adopt_lock);
2748+
m_scratch_typesystem_for_module.erase(key);
2749+
if (log)
2750+
log->Printf("erased module-wide scratch context with errors\n");
2751+
return;
27412752
}
27422753
if (log)
27432754
log->Printf("returned cached module-wide scratch context\n");
2744-
return cached_ts;
2755+
return;
27452756
}
27462757

27472758
if (!create_on_demand) {
27482759
if (log)
27492760
log->Printf("not allowed to create a new context\n");
2750-
return nullptr;
2761+
return;
27512762
}
27522763

2753-
// Call for its side effects of establishing the Swift scratch type system.
2764+
// Call for its side effects of establishing the Swift scratch type
2765+
// system.
27542766
auto type_system_or_err =
27552767
GetScratchTypeSystemForLanguage(eLanguageTypeSwift, false);
27562768
if (!type_system_or_err) {
27572769
llvm::consumeError(type_system_or_err.takeError());
2758-
return nullptr;
2770+
return;
27592771
}
27602772

2761-
if (!GetSwiftScratchContextLock().try_lock()) {
2773+
auto &lock = GetSwiftScratchContextLock();
2774+
if (!lock.try_lock()) {
27622775
if (log)
27632776
log->Printf("couldn't acquire scratch context lock\n");
2764-
return nullptr;
2777+
return;
27652778
}
2779+
std::lock_guard<std::shared_mutex> unlock(lock, std::adopt_lock);
27662780

2767-
auto unlock = llvm::make_scope_exit(
2768-
[this] { GetSwiftScratchContextLock().unlock(); });
2769-
2770-
// With the lock held, get the current scratch type system. This ensures the
2771-
// current instance is used even in the unlikely event it was changed during
2772-
// the brief window between the call to `GetScratchTypeSystemForLanguage`
2773-
// and taking the lock.
2781+
// With the lock held, get the current scratch type system. This ensures
2782+
// the current instance is used even in the unlikely event it was changed
2783+
// during the brief window between the call to
2784+
// `GetScratchTypeSystemForLanguage` and taking the lock.
27742785
type_system_or_err = m_scratch_type_system_map.GetTypeSystemForLanguage(
27752786
eLanguageTypeSwift, this, false);
27762787
if (!type_system_or_err) {
27772788
llvm::consumeError(type_system_or_err.takeError());
2778-
return nullptr;
2789+
return;
27792790
}
27802791

27812792
if (auto *global_scratch_ctx =
@@ -2789,42 +2800,55 @@ llvm::Optional<SwiftScratchContextReader> Target::GetSwiftScratchContext(
27892800
auto typesystem_sp = std::make_shared<TypeSystemSwiftTypeRefForExpressions>(
27902801
lldb::eLanguageTypeSwift, *this, *lldb_module);
27912802
typesystem_sp->GetSwiftASTContext();
2792-
m_scratch_typesystem_for_module.insert({idx, typesystem_sp});
2803+
m_scratch_typesystem_for_module.insert({key, typesystem_sp});
27932804
if (log)
27942805
log->Printf("created module-wide scratch context\n");
2795-
return typesystem_sp.get();
2806+
return;
27962807
};
27972808

2798-
auto *swift_scratch_ctx = get_or_create_fallback_context();
2799-
if (!swift_scratch_ctx) {
2800-
if (log)
2801-
log->Printf("returned project-wide scratch context\n");
2809+
llvm::Optional<SwiftScratchContextReader> reader;
2810+
if (lldb_module && m_use_scratch_typesystem_per_module) {
2811+
maybe_create_fallback_context();
2812+
std::shared_lock<std::shared_mutex> lock(GetSwiftScratchContextLock());
2813+
if (auto *cached_ts = get_cached_module_ts(lldb_module)) {
2814+
reader = SwiftScratchContextReader(std::move(lock), *cached_ts);
2815+
if (log)
2816+
log->Printf("returned module-wide scratch context\n");
2817+
}
2818+
}
2819+
// FIXME: Don't return the project-wide context after requesting the
2820+
// module-wide one.
2821+
if (!reader) {
2822+
std::shared_lock<std::shared_mutex> lock(GetSwiftScratchContextLock());
28022823
auto type_system_or_err =
28032824
GetScratchTypeSystemForLanguage(eLanguageTypeSwift, create_on_demand);
2804-
if (type_system_or_err)
2805-
swift_scratch_ctx =
2806-
llvm::cast_or_null<TypeSystemSwiftTypeRefForExpressions>(
2807-
type_system_or_err->get());
2808-
else
2825+
if (type_system_or_err) {
2826+
if (auto *ts = llvm::cast_or_null<TypeSystemSwiftTypeRefForExpressions>(
2827+
type_system_or_err->get())) {
2828+
reader = SwiftScratchContextReader(std::move(lock), *ts);
2829+
if (log)
2830+
log->Printf("returned project-wide scratch context\n");
2831+
}
2832+
} else
28092833
llvm::consumeError(type_system_or_err.takeError());
28102834
}
28112835

2812-
StackFrameSP frame_sp = exe_scope.CalculateStackFrame();
2813-
if (frame_sp && frame_sp.get() && swift_scratch_ctx) {
2814-
SymbolContext sc =
2815-
frame_sp->GetSymbolContext(lldb::eSymbolContextEverything);
2816-
Status status = swift_scratch_ctx->PerformCompileUnitImports(sc);
2817-
if (status.Fail())
2818-
Debugger::ReportError(status.AsCString(), GetDebugger().GetID());
2836+
if (reader) {
2837+
// Perform compile unit imports.
2838+
assert(reader->get());
2839+
StackFrameSP frame_sp = exe_scope.CalculateStackFrame();
2840+
if (frame_sp && frame_sp.get()) {
2841+
SymbolContext sc =
2842+
frame_sp->GetSymbolContext(lldb::eSymbolContextEverything);
2843+
Status status = reader->get()->PerformCompileUnitImports(sc);
2844+
if (status.Fail())
2845+
Debugger::ReportError(status.AsCString(), GetDebugger().GetID());
2846+
}
28192847
}
2820-
2821-
if (!swift_scratch_ctx)
2822-
return llvm::None;
2823-
return SwiftScratchContextReader(GetSwiftScratchContextLock(),
2824-
*swift_scratch_ctx);
2848+
return reader;
28252849
}
28262850

2827-
static SharedMutex *
2851+
static std::shared_mutex *
28282852
GetSwiftScratchContextMutex(const ExecutionContext *exe_ctx) {
28292853
if (!exe_ctx)
28302854
return nullptr;
@@ -2834,11 +2858,20 @@ GetSwiftScratchContextMutex(const ExecutionContext *exe_ctx) {
28342858
return nullptr;
28352859
}
28362860

2861+
SwiftScratchContextReader::SwiftScratchContextReader(
2862+
std::shared_lock<std::shared_mutex> &&lock,
2863+
TypeSystemSwiftTypeRefForExpressions &ts)
2864+
: m_lock(std::move(lock)), m_ts(&ts) {}
2865+
28372866
SwiftScratchContextLock::SwiftScratchContextLock(
2838-
const ExecutionContext *exe_ctx)
2839-
: ScopedSharedMutexReader(GetSwiftScratchContextMutex(exe_ctx)) {}
2867+
const ExecutionContext *exe_ctx) {
2868+
if (auto *mutex = GetSwiftScratchContextMutex(exe_ctx)) {
2869+
std::shared_lock<std::shared_mutex> tmp(*mutex);
2870+
lock.swap(tmp);
2871+
}
2872+
}
28402873

2841-
static SharedMutex *
2874+
static std::shared_mutex *
28422875
GetSwiftScratchContextMutex(const ExecutionContextRef *exe_ctx_ref) {
28432876
if (!exe_ctx_ref)
28442877
return nullptr;
@@ -2847,8 +2880,12 @@ GetSwiftScratchContextMutex(const ExecutionContextRef *exe_ctx_ref) {
28472880
}
28482881

28492882
SwiftScratchContextLock::SwiftScratchContextLock(
2850-
const ExecutionContextRef *exe_ctx_ref)
2851-
: ScopedSharedMutexReader(GetSwiftScratchContextMutex(exe_ctx_ref)) {}
2883+
const ExecutionContextRef *exe_ctx_ref) {
2884+
if (auto *mutex = GetSwiftScratchContextMutex(exe_ctx_ref)) {
2885+
std::shared_lock<std::shared_mutex> tmp(*mutex);
2886+
lock.swap(tmp);
2887+
}
2888+
}
28522889

28532890
void Target::DisplayFallbackSwiftContextErrors(
28542891
SwiftASTContextForExpressions *swift_ast_ctx) {

0 commit comments

Comments
 (0)