[Lldb-commits] [lldb] [lldb] Expose the Target API lock through the SB API (PR #131404)
Jonas Devlieghere via lldb-commits
lldb-commits at lists.llvm.org
Fri Mar 14 16:21:00 PDT 2025
https://github.com/JDevlieghere updated https://github.com/llvm/llvm-project/pull/131404
>From 5ea2ad6ecb388818b009fa89c4aebe1e0e4213df Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Fri, 14 Mar 2025 15:19:58 -0700
Subject: [PATCH 1/2] [lldb] Expose the Target API lock through the SB API
---
lldb/include/lldb/API/SBDefines.h | 1 +
lldb/include/lldb/API/SBLock.h | 45 ++++++++++++++++++++++
lldb/include/lldb/API/SBTarget.h | 6 ++-
lldb/include/lldb/Target/Target.h | 16 +++++++-
lldb/source/API/CMakeLists.txt | 1 +
lldb/source/API/SBLock.cpp | 40 +++++++++++++++++++
lldb/source/API/SBTarget.cpp | 36 +++++++++--------
lldb/unittests/API/CMakeLists.txt | 1 +
lldb/unittests/API/SBLockTest.cpp | 64 +++++++++++++++++++++++++++++++
9 files changed, 193 insertions(+), 17 deletions(-)
create mode 100644 lldb/include/lldb/API/SBLock.h
create mode 100644 lldb/source/API/SBLock.cpp
create mode 100644 lldb/unittests/API/SBLockTest.cpp
diff --git a/lldb/include/lldb/API/SBDefines.h b/lldb/include/lldb/API/SBDefines.h
index ed5a80da117a5..7fa5150d69d8a 100644
--- a/lldb/include/lldb/API/SBDefines.h
+++ b/lldb/include/lldb/API/SBDefines.h
@@ -84,6 +84,7 @@ class LLDB_API SBLanguageRuntime;
class LLDB_API SBLaunchInfo;
class LLDB_API SBLineEntry;
class LLDB_API SBListener;
+class LLDB_API SBLock;
class LLDB_API SBMemoryRegionInfo;
class LLDB_API SBMemoryRegionInfoList;
class LLDB_API SBModule;
diff --git a/lldb/include/lldb/API/SBLock.h b/lldb/include/lldb/API/SBLock.h
new file mode 100644
index 0000000000000..8d6fdfb959dfb
--- /dev/null
+++ b/lldb/include/lldb/API/SBLock.h
@@ -0,0 +1,45 @@
+//===-- SBLock.h ----------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_API_SBLOCK_H
+#define LLDB_API_SBLOCK_H
+
+#include "lldb/API/SBDefines.h"
+#include "lldb/lldb-forward.h"
+
+#include <mutex>
+
+namespace lldb_private {
+struct APILock;
+}
+
+namespace lldb {
+
+#ifndef SWIG
+class LLDB_API SBLock {
+public:
+ ~SBLock();
+
+ bool IsValid() const;
+
+private:
+ friend class SBTarget;
+
+ SBLock() = default;
+ SBLock(std::recursive_mutex &mutex);
+ SBLock(std::recursive_mutex &mutex, lldb::TargetSP target_sp);
+ SBLock(const SBLock &rhs) = delete;
+ const SBLock &operator=(const SBLock &rhs) = delete;
+
+ std::unique_ptr<lldb_private::APILock> m_opaque_up;
+};
+#endif
+
+} // namespace lldb
+
+#endif
diff --git a/lldb/include/lldb/API/SBTarget.h b/lldb/include/lldb/API/SBTarget.h
index bb912ab41d0fe..6120c289743e3 100644
--- a/lldb/include/lldb/API/SBTarget.h
+++ b/lldb/include/lldb/API/SBTarget.h
@@ -342,7 +342,7 @@ class LLDB_API SBTarget {
uint32_t GetAddressByteSize();
const char *GetTriple();
-
+
const char *GetABIName();
const char *GetLabel() const;
@@ -946,6 +946,10 @@ class LLDB_API SBTarget {
/// An error if a Trace already exists or the trace couldn't be created.
lldb::SBTrace CreateTrace(SBError &error);
+#ifndef SWIG
+ lldb::SBLock GetAPILock() const;
+#endif
+
protected:
friend class SBAddress;
friend class SBAddressRange;
diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h
index 80ce5f013344c..8321a963d4c5b 100644
--- a/lldb/include/lldb/Target/Target.h
+++ b/lldb/include/lldb/Target/Target.h
@@ -1327,7 +1327,7 @@ class Target : public std::enable_shared_from_this<Target>,
StopHook(const StopHook &rhs);
virtual ~StopHook() = default;
- enum class StopHookKind : uint32_t { CommandBased = 0, ScriptBased };
+ enum class StopHookKind : uint32_t { CommandBased = 0, ScriptBased };
enum class StopHookResult : uint32_t {
KeepStopped = 0,
RequestContinue,
@@ -1692,6 +1692,20 @@ class Target : public std::enable_shared_from_this<Target>,
}
};
+/// The private implementation backing SBLock.
+struct APILock {
+ APILock(std::recursive_mutex &mutex) : lock(mutex) {}
+ std::lock_guard<std::recursive_mutex> lock;
+};
+
+/// The private implementation used by SBLock to hand out the target API mutex.
+/// It has a TargetSP to ensure the lock cannot outlive the target.
+struct TargetAPILock : public APILock {
+ TargetAPILock(std::recursive_mutex &mutex, lldb::TargetSP target_sp)
+ : APILock(mutex), target_sp(target_sp) {}
+ lldb::TargetSP target_sp;
+};
+
} // namespace lldb_private
#endif // LLDB_TARGET_TARGET_H
diff --git a/lldb/source/API/CMakeLists.txt b/lldb/source/API/CMakeLists.txt
index 48d5cde5bf592..c9a9433b2329d 100644
--- a/lldb/source/API/CMakeLists.txt
+++ b/lldb/source/API/CMakeLists.txt
@@ -77,6 +77,7 @@ add_lldb_library(liblldb SHARED ${option_framework}
SBLaunchInfo.cpp
SBLineEntry.cpp
SBListener.cpp
+ SBLock.cpp
SBMemoryRegionInfo.cpp
SBMemoryRegionInfoList.cpp
SBModule.cpp
diff --git a/lldb/source/API/SBLock.cpp b/lldb/source/API/SBLock.cpp
new file mode 100644
index 0000000000000..448c8ccd46747
--- /dev/null
+++ b/lldb/source/API/SBLock.cpp
@@ -0,0 +1,40 @@
+//===-- SBLock.cpp --------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/API/SBLock.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/Instrumentation.h"
+#include "lldb/lldb-forward.h"
+
+#include <memory>
+#include <mutex>
+
+using namespace lldb;
+using namespace lldb_private;
+
+#ifndef SWIG
+
+SBLock::SBLock(std::recursive_mutex &mutex)
+ : m_opaque_up(std::make_unique<APILock>(mutex)) {
+ LLDB_INSTRUMENT_VA(this);
+}
+
+SBLock::SBLock(std::recursive_mutex &mutex, lldb::TargetSP target_sp)
+ : m_opaque_up(std::make_unique<TargetAPILock>(mutex, target_sp)) {
+ LLDB_INSTRUMENT_VA(this);
+}
+
+SBLock::~SBLock() { LLDB_INSTRUMENT_VA(this); }
+
+bool SBLock::IsValid() const {
+ LLDB_INSTRUMENT_VA(this);
+
+ return static_cast<bool>(m_opaque_up);
+}
+
+#endif
diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp
index dd9caa724ea36..a2761de8bfc5e 100644
--- a/lldb/source/API/SBTarget.cpp
+++ b/lldb/source/API/SBTarget.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "lldb/API/SBTarget.h"
+#include "lldb/API/SBLock.h"
#include "lldb/Utility/Instrumentation.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/lldb-public.h"
@@ -18,6 +19,7 @@
#include "lldb/API/SBExpressionOptions.h"
#include "lldb/API/SBFileSpec.h"
#include "lldb/API/SBListener.h"
+#include "lldb/API/SBLock.h"
#include "lldb/API/SBModule.h"
#include "lldb/API/SBModuleSpec.h"
#include "lldb/API/SBProcess.h"
@@ -544,9 +546,8 @@ lldb::SBProcess SBTarget::ConnectRemote(SBListener &listener, const char *url,
if (target_sp) {
std::lock_guard<std::recursive_mutex> guard(target_sp->GetAPIMutex());
if (listener.IsValid())
- process_sp =
- target_sp->CreateProcess(listener.m_opaque_sp, plugin_name, nullptr,
- true);
+ process_sp = target_sp->CreateProcess(listener.m_opaque_sp, plugin_name,
+ nullptr, true);
else
process_sp = target_sp->CreateProcess(
target_sp->GetDebugger().GetListener(), plugin_name, nullptr, true);
@@ -1040,7 +1041,7 @@ SBTarget::BreakpointCreateForException(lldb::LanguageType language,
std::lock_guard<std::recursive_mutex> guard(target_sp->GetAPIMutex());
const bool hardware = false;
sb_bp = target_sp->CreateExceptionBreakpoint(language, catch_bp, throw_bp,
- hardware);
+ hardware);
}
return sb_bp;
@@ -1060,14 +1061,9 @@ lldb::SBBreakpoint SBTarget::BreakpointCreateFromScript(
Status error;
StructuredData::ObjectSP obj_sp = extra_args.m_impl_up->GetObjectSP();
- sb_bp =
- target_sp->CreateScriptedBreakpoint(class_name,
- module_list.get(),
- file_list.get(),
- false, /* internal */
- request_hardware,
- obj_sp,
- &error);
+ sb_bp = target_sp->CreateScriptedBreakpoint(
+ class_name, module_list.get(), file_list.get(), false, /* internal */
+ request_hardware, obj_sp, &error);
}
return sb_bp;
@@ -1692,8 +1688,8 @@ uint32_t SBTarget::GetMaximumNumberOfChildrenToDisplay() const {
LLDB_INSTRUMENT_VA(this);
TargetSP target_sp(GetSP());
- if(target_sp){
- return target_sp->GetMaximumNumberOfChildrenToDisplay();
+ if (target_sp) {
+ return target_sp->GetMaximumNumberOfChildrenToDisplay();
}
return 0;
}
@@ -2193,7 +2189,7 @@ SBError SBTarget::SetModuleLoadAddress(lldb::SBModule module,
}
SBError SBTarget::SetModuleLoadAddress(lldb::SBModule module,
- uint64_t slide_offset) {
+ uint64_t slide_offset) {
SBError sb_error;
@@ -2439,3 +2435,13 @@ lldb::SBTrace SBTarget::CreateTrace(lldb::SBError &error) {
}
return SBTrace();
}
+
+#ifndef SWIG
+lldb::SBLock SBTarget::GetAPILock() const {
+ LLDB_INSTRUMENT_VA(this);
+
+ if (TargetSP target_sp = GetSP())
+ return lldb::SBLock(target_sp->GetAPIMutex(), target_sp);
+ return lldb::SBLock();
+}
+#endif
diff --git a/lldb/unittests/API/CMakeLists.txt b/lldb/unittests/API/CMakeLists.txt
index fe2ff684a5d92..5a88d06b601a3 100644
--- a/lldb/unittests/API/CMakeLists.txt
+++ b/lldb/unittests/API/CMakeLists.txt
@@ -1,6 +1,7 @@
add_lldb_unittest(APITests
SBCommandInterpreterTest.cpp
SBLineEntryTest.cpp
+ SBLockTest.cpp
LINK_LIBS
liblldb
diff --git a/lldb/unittests/API/SBLockTest.cpp b/lldb/unittests/API/SBLockTest.cpp
new file mode 100644
index 0000000000000..1fa9c184bf79b
--- /dev/null
+++ b/lldb/unittests/API/SBLockTest.cpp
@@ -0,0 +1,64 @@
+//===-- SBLockTest.cpp ----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===/
+
+#include "lldb/API/SBLock.h"
+#include "lldb/API/SBDebugger.h"
+#include "lldb/API/SBTarget.h"
+#include "gtest/gtest.h"
+#include <atomic>
+#include <chrono>
+#include <thread>
+
+TEST(SBLockTest, LockTest) {
+ lldb::SBDebugger debugger = lldb::SBDebugger::Create();
+ lldb::SBTarget target = debugger.GetDummyTarget();
+
+ std::mutex m;
+ std::condition_variable cv;
+ bool wakeup = false;
+ std::atomic<bool> locked = false;
+
+ std::thread test_thread([&]() {
+ {
+ {
+ std::unique_lock lk(m);
+ cv.wait(lk, [&] { return wakeup; });
+ }
+
+ ASSERT_TRUE(locked);
+ target.BreakpointCreateByName("foo", "bar");
+ ASSERT_FALSE(locked);
+
+ cv.notify_one();
+ }
+ });
+
+ // Take the API lock.
+ {
+ lldb::SBLock lock = target.GetAPILock();
+ ASSERT_FALSE(locked.exchange(true));
+
+ // Wake up the test thread.
+ {
+ std::lock_guard lk(m);
+ wakeup = true;
+ }
+ cv.notify_one();
+
+ // Wait 500ms to confirm the thread is blocked.
+ {
+ std::unique_lock<std::mutex> lk(m);
+ auto result = cv.wait_for(lk, std::chrono::milliseconds(500));
+ ASSERT_EQ(result, std::cv_status::timeout);
+ }
+
+ ASSERT_TRUE(locked.exchange(false));
+ }
+
+ test_thread.join();
+}
>From acb6a6ed6051d5d8297645f12a136ad7b2754b8e Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Fri, 14 Mar 2025 16:20:35 -0700
Subject: [PATCH 2/2] Address code review feedback
---
lldb/include/lldb/API/SBLock.h | 8 +++++---
lldb/include/lldb/API/SBTarget.h | 2 +-
lldb/include/lldb/Target/Target.h | 2 ++
lldb/source/API/SBLock.cpp | 5 -----
lldb/source/API/SBTarget.cpp | 10 ++++------
lldb/unittests/API/SBLockTest.cpp | 2 +-
6 files changed, 13 insertions(+), 16 deletions(-)
diff --git a/lldb/include/lldb/API/SBLock.h b/lldb/include/lldb/API/SBLock.h
index 8d6fdfb959dfb..d13fec989990b 100644
--- a/lldb/include/lldb/API/SBLock.h
+++ b/lldb/include/lldb/API/SBLock.h
@@ -28,11 +28,13 @@ class LLDB_API SBLock {
bool IsValid() const;
private:
- friend class SBTarget;
-
SBLock() = default;
- SBLock(std::recursive_mutex &mutex);
+
+ // Private constructor used by SBTarget to create the Target API lock.
+ // Requires a friend declaration.
SBLock(std::recursive_mutex &mutex, lldb::TargetSP target_sp);
+ friend class SBTarget;
+
SBLock(const SBLock &rhs) = delete;
const SBLock &operator=(const SBLock &rhs) = delete;
diff --git a/lldb/include/lldb/API/SBTarget.h b/lldb/include/lldb/API/SBTarget.h
index 6120c289743e3..03d6b623fd425 100644
--- a/lldb/include/lldb/API/SBTarget.h
+++ b/lldb/include/lldb/API/SBTarget.h
@@ -947,7 +947,7 @@ class LLDB_API SBTarget {
lldb::SBTrace CreateTrace(SBError &error);
#ifndef SWIG
- lldb::SBLock GetAPILock() const;
+ lldb::SBLock AcquireAPILock() const;
#endif
protected:
diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h
index 8321a963d4c5b..4379f73936d0c 100644
--- a/lldb/include/lldb/Target/Target.h
+++ b/lldb/include/lldb/Target/Target.h
@@ -1695,6 +1695,7 @@ class Target : public std::enable_shared_from_this<Target>,
/// The private implementation backing SBLock.
struct APILock {
APILock(std::recursive_mutex &mutex) : lock(mutex) {}
+ virtual ~APILock() = default;
std::lock_guard<std::recursive_mutex> lock;
};
@@ -1703,6 +1704,7 @@ struct APILock {
struct TargetAPILock : public APILock {
TargetAPILock(std::recursive_mutex &mutex, lldb::TargetSP target_sp)
: APILock(mutex), target_sp(target_sp) {}
+ ~TargetAPILock() override = default;
lldb::TargetSP target_sp;
};
diff --git a/lldb/source/API/SBLock.cpp b/lldb/source/API/SBLock.cpp
index 448c8ccd46747..4338049cb1689 100644
--- a/lldb/source/API/SBLock.cpp
+++ b/lldb/source/API/SBLock.cpp
@@ -19,11 +19,6 @@ using namespace lldb_private;
#ifndef SWIG
-SBLock::SBLock(std::recursive_mutex &mutex)
- : m_opaque_up(std::make_unique<APILock>(mutex)) {
- LLDB_INSTRUMENT_VA(this);
-}
-
SBLock::SBLock(std::recursive_mutex &mutex, lldb::TargetSP target_sp)
: m_opaque_up(std::make_unique<TargetAPILock>(mutex, target_sp)) {
LLDB_INSTRUMENT_VA(this);
diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp
index a2761de8bfc5e..96d5fd1cbf31a 100644
--- a/lldb/source/API/SBTarget.cpp
+++ b/lldb/source/API/SBTarget.cpp
@@ -7,11 +7,6 @@
//===----------------------------------------------------------------------===//
#include "lldb/API/SBTarget.h"
-#include "lldb/API/SBLock.h"
-#include "lldb/Utility/Instrumentation.h"
-#include "lldb/Utility/LLDBLog.h"
-#include "lldb/lldb-public.h"
-
#include "lldb/API/SBBreakpoint.h"
#include "lldb/API/SBDebugger.h"
#include "lldb/API/SBEnvironment.h"
@@ -60,11 +55,14 @@
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/Args.h"
#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/Instrumentation.h"
+#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/ProcessInfo.h"
#include "lldb/Utility/RegularExpression.h"
#include "lldb/ValueObject/ValueObjectConstResult.h"
#include "lldb/ValueObject/ValueObjectList.h"
#include "lldb/ValueObject/ValueObjectVariable.h"
+#include "lldb/lldb-public.h"
#include "Commands/CommandObjectBreakpoint.h"
#include "lldb/Interpreter/CommandReturnObject.h"
@@ -2437,7 +2435,7 @@ lldb::SBTrace SBTarget::CreateTrace(lldb::SBError &error) {
}
#ifndef SWIG
-lldb::SBLock SBTarget::GetAPILock() const {
+lldb::SBLock SBTarget::AcquireAPILock() const {
LLDB_INSTRUMENT_VA(this);
if (TargetSP target_sp = GetSP())
diff --git a/lldb/unittests/API/SBLockTest.cpp b/lldb/unittests/API/SBLockTest.cpp
index 1fa9c184bf79b..33bf94ead1dd3 100644
--- a/lldb/unittests/API/SBLockTest.cpp
+++ b/lldb/unittests/API/SBLockTest.cpp
@@ -40,7 +40,7 @@ TEST(SBLockTest, LockTest) {
// Take the API lock.
{
- lldb::SBLock lock = target.GetAPILock();
+ lldb::SBLock lock = target.AcquireAPILock();
ASSERT_FALSE(locked.exchange(true));
// Wake up the test thread.
More information about the lldb-commits
mailing list