Skip to content

Commit 50949eb

Browse files
authored
[lldb] Expose the Target API mutex through the SB API (llvm#133295)
Expose u target API mutex through the SB API. This is motivated by lldb-dap, which is built on top of the SB API and needs a way to execute a series of SB API calls in an atomic manner (see llvm#131242). We can solve this problem by either introducing an additional layer of locking at the DAP level or by exposing the existing locking at the SB API level. This patch implements the second approach. This was discussed in an RFC on Discourse [0]. The original implementation exposed a move-only lock rather than a mutex [1] which doesn't work well with SWIG 4.0 [2]. This implement the alternative solution of exposing the mutex rather than the lock. The SBMutex conforms to the BasicLockable requirement [3] (which is why the methods are called `lock` and `unlock` rather than Lock and Unlock) so it can be used as `std::lock_guard<lldb::SBMutex>` and `std::unique_lock<lldb::SBMutex>`. [0]: https://discourse.llvm.org/t/rfc-exposing-the-target-api-lock-through-the-sb-api/85215/6 [1]: llvm#131404 [2]: https://discourse.llvm.org/t/rfc-bumping-the-minimum-swig-version-to-4-1-0/85377/9 [3]: https://en.cppreference.com/w/cpp/named_req/BasicLockable
1 parent 74b7abf commit 50949eb

File tree

12 files changed

+220
-6
lines changed

12 files changed

+220
-6
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
%extend lldb::SBMutex {
2+
#ifdef SWIGPYTHON
3+
%pythoncode %{
4+
def __enter__(self):
5+
self.lock()
6+
return self
7+
8+
def __exit__(self, exc_type, exc_value, traceback):
9+
self.unlock()
10+
%}
11+
#endif
12+
}

lldb/bindings/interfaces.swig

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
%include "./interface/SBMemoryRegionInfoListDocstrings.i"
5252
%include "./interface/SBModuleDocstrings.i"
5353
%include "./interface/SBModuleSpecDocstrings.i"
54+
%include "./interface/SBMutexExtensions.i"
5455
%include "./interface/SBPlatformDocstrings.i"
5556
%include "./interface/SBProcessDocstrings.i"
5657
%include "./interface/SBProcessInfoDocstrings.i"
@@ -121,15 +122,16 @@
121122
%include "lldb/API/SBHostOS.h"
122123
%include "lldb/API/SBInstruction.h"
123124
%include "lldb/API/SBInstructionList.h"
124-
%include "lldb/API/SBLanguages.h"
125125
%include "lldb/API/SBLanguageRuntime.h"
126+
%include "lldb/API/SBLanguages.h"
126127
%include "lldb/API/SBLaunchInfo.h"
127128
%include "lldb/API/SBLineEntry.h"
128129
%include "lldb/API/SBListener.h"
129130
%include "lldb/API/SBMemoryRegionInfo.h"
130131
%include "lldb/API/SBMemoryRegionInfoList.h"
131132
%include "lldb/API/SBModule.h"
132133
%include "lldb/API/SBModuleSpec.h"
134+
%include "lldb/API/SBMutex.h"
133135
%include "lldb/API/SBPlatform.h"
134136
%include "lldb/API/SBProcess.h"
135137
%include "lldb/API/SBProcessInfo.h"

lldb/include/lldb/API/LLDB.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
#include "lldb/API/SBMemoryRegionInfoList.h"
5151
#include "lldb/API/SBModule.h"
5252
#include "lldb/API/SBModuleSpec.h"
53+
#include "lldb/API/SBMutex.h"
5354
#include "lldb/API/SBPlatform.h"
5455
#include "lldb/API/SBProcess.h"
5556
#include "lldb/API/SBProcessInfo.h"

lldb/include/lldb/API/SBDefines.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ class LLDB_API SBMemoryRegionInfoList;
8989
class LLDB_API SBModule;
9090
class LLDB_API SBModuleSpec;
9191
class LLDB_API SBModuleSpecList;
92+
class LLDB_API SBMutex;
9293
class LLDB_API SBPlatform;
9394
class LLDB_API SBPlatformConnectOptions;
9495
class LLDB_API SBPlatformShellCommand;

lldb/include/lldb/API/SBMutex.h

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//===-- SBMutex.h ---------------------------------------------------------===//
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 LLDB_API_SBMUTEX_H
10+
#define LLDB_API_SBMUTEX_H
11+
12+
#include "lldb/API/SBDefines.h"
13+
#include "lldb/lldb-forward.h"
14+
#include <mutex>
15+
16+
namespace lldb {
17+
18+
class LLDB_API SBMutex {
19+
public:
20+
SBMutex();
21+
SBMutex(const SBMutex &rhs);
22+
const SBMutex &operator=(const SBMutex &rhs);
23+
~SBMutex();
24+
25+
/// Returns true if this lock has ownership of the underlying mutex.
26+
bool IsValid() const;
27+
28+
/// Blocking operation that takes ownership of this lock.
29+
void lock() const;
30+
31+
/// Releases ownership of this lock.
32+
void unlock() const;
33+
34+
private:
35+
// Private constructor used by SBTarget to create the Target API mutex.
36+
// Requires a friend declaration.
37+
SBMutex(lldb::TargetSP target_sp);
38+
friend class SBTarget;
39+
40+
std::shared_ptr<std::recursive_mutex> m_opaque_sp;
41+
};
42+
43+
} // namespace lldb
44+
45+
#endif

lldb/include/lldb/API/SBTarget.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ class LLDB_API SBTarget {
342342
uint32_t GetAddressByteSize();
343343

344344
const char *GetTriple();
345-
345+
346346
const char *GetABIName();
347347

348348
const char *GetLabel() const;
@@ -946,6 +946,8 @@ class LLDB_API SBTarget {
946946
/// An error if a Trace already exists or the trace couldn't be created.
947947
lldb::SBTrace CreateTrace(SBError &error);
948948

949+
lldb::SBMutex GetAPIMutex() const;
950+
949951
protected:
950952
friend class SBAddress;
951953
friend class SBAddressRange;

lldb/source/API/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ add_lldb_library(liblldb SHARED ${option_framework}
8181
SBMemoryRegionInfoList.cpp
8282
SBModule.cpp
8383
SBModuleSpec.cpp
84+
SBMutex.cpp
8485
SBPlatform.cpp
8586
SBProcess.cpp
8687
SBProcessInfo.cpp

lldb/source/API/SBMutex.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
//===-- SBMutex.cpp -------------------------------------------------------===//
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 "lldb/API/SBMutex.h"
10+
#include "lldb/Target/Target.h"
11+
#include "lldb/Utility/Instrumentation.h"
12+
#include "lldb/lldb-forward.h"
13+
#include <memory>
14+
#include <mutex>
15+
16+
using namespace lldb;
17+
using namespace lldb_private;
18+
19+
SBMutex::SBMutex() : m_opaque_sp(std::make_shared<std::recursive_mutex>()) {
20+
LLDB_INSTRUMENT_VA(this);
21+
}
22+
23+
SBMutex::SBMutex(const SBMutex &rhs) : m_opaque_sp(rhs.m_opaque_sp) {
24+
LLDB_INSTRUMENT_VA(this);
25+
}
26+
27+
const SBMutex &SBMutex::operator=(const SBMutex &rhs) {
28+
LLDB_INSTRUMENT_VA(this);
29+
30+
m_opaque_sp = rhs.m_opaque_sp;
31+
return *this;
32+
}
33+
34+
SBMutex::SBMutex(lldb::TargetSP target_sp)
35+
: m_opaque_sp(std::shared_ptr<std::recursive_mutex>(
36+
target_sp, &target_sp->GetAPIMutex())) {
37+
LLDB_INSTRUMENT_VA(this, target_sp);
38+
}
39+
40+
SBMutex::~SBMutex() { LLDB_INSTRUMENT_VA(this); }
41+
42+
bool SBMutex::IsValid() const {
43+
LLDB_INSTRUMENT_VA(this);
44+
45+
return static_cast<bool>(m_opaque_sp);
46+
}
47+
48+
void SBMutex::lock() const {
49+
LLDB_INSTRUMENT_VA(this);
50+
51+
if (m_opaque_sp)
52+
m_opaque_sp->lock();
53+
}
54+
55+
void SBMutex::unlock() const {
56+
LLDB_INSTRUMENT_VA(this);
57+
58+
if (m_opaque_sp)
59+
m_opaque_sp->unlock();
60+
}

lldb/source/API/SBTarget.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,6 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "lldb/API/SBTarget.h"
10-
#include "lldb/Utility/Instrumentation.h"
11-
#include "lldb/Utility/LLDBLog.h"
12-
#include "lldb/lldb-public.h"
13-
1410
#include "lldb/API/SBBreakpoint.h"
1511
#include "lldb/API/SBDebugger.h"
1612
#include "lldb/API/SBEnvironment.h"
@@ -20,6 +16,7 @@
2016
#include "lldb/API/SBListener.h"
2117
#include "lldb/API/SBModule.h"
2218
#include "lldb/API/SBModuleSpec.h"
19+
#include "lldb/API/SBMutex.h"
2320
#include "lldb/API/SBProcess.h"
2421
#include "lldb/API/SBSourceManager.h"
2522
#include "lldb/API/SBStream.h"
@@ -58,11 +55,14 @@
5855
#include "lldb/Utility/ArchSpec.h"
5956
#include "lldb/Utility/Args.h"
6057
#include "lldb/Utility/FileSpec.h"
58+
#include "lldb/Utility/Instrumentation.h"
59+
#include "lldb/Utility/LLDBLog.h"
6160
#include "lldb/Utility/ProcessInfo.h"
6261
#include "lldb/Utility/RegularExpression.h"
6362
#include "lldb/ValueObject/ValueObjectConstResult.h"
6463
#include "lldb/ValueObject/ValueObjectList.h"
6564
#include "lldb/ValueObject/ValueObjectVariable.h"
65+
#include "lldb/lldb-public.h"
6666

6767
#include "Commands/CommandObjectBreakpoint.h"
6868
#include "lldb/Interpreter/CommandReturnObject.h"
@@ -2439,3 +2439,11 @@ lldb::SBTrace SBTarget::CreateTrace(lldb::SBError &error) {
24392439
}
24402440
return SBTrace();
24412441
}
2442+
2443+
lldb::SBMutex SBTarget::GetAPIMutex() const {
2444+
LLDB_INSTRUMENT_VA(this);
2445+
2446+
if (TargetSP target_sp = GetSP())
2447+
return lldb::SBMutex(target_sp);
2448+
return lldb::SBMutex();
2449+
}

lldb/test/API/python_api/target/TestTargetAPI.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,3 +537,27 @@ def test_setting_selected_target_with_invalid_target(self):
537537
"""Make sure we don't crash when trying to select invalid target."""
538538
target = lldb.SBTarget()
539539
self.dbg.SetSelectedTarget(target)
540+
541+
@no_debug_info_test
542+
def test_get_api_mutex(self):
543+
"""Make sure we can lock and unlock the API mutex from Python."""
544+
target = self.dbg.GetDummyTarget()
545+
546+
mutex = target.GetAPIMutex()
547+
self.assertTrue(mutex.IsValid())
548+
mutex.lock()
549+
# The API call below doesn't actually matter, it's just there to
550+
# confirm we don't block on the API lock.
551+
target.BreakpointCreateByName("foo", "bar")
552+
mutex.unlock()
553+
554+
@no_debug_info_test
555+
def test_get_api_mutex_with_statement(self):
556+
"""Make sure we can lock and unlock the API mutex using a with-statement from Python."""
557+
target = self.dbg.GetDummyTarget()
558+
559+
with target.GetAPIMutex() as mutex:
560+
self.assertTrue(mutex.IsValid())
561+
# The API call below doesn't actually matter, it's just there to
562+
# confirm we don't block on the API lock.
563+
target.BreakpointCreateByName("foo", "bar")

lldb/unittests/API/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
add_lldb_unittest(APITests
22
SBCommandInterpreterTest.cpp
33
SBLineEntryTest.cpp
4+
SBMutexTest.cpp
45

56
LINK_LIBS
67
liblldb

lldb/unittests/API/SBMutexTest.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
//===-- SBMutexTest.cpp ---------------------------------------------------===//
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+
// Use the umbrella header for -Wdocumentation.
10+
#include "lldb/API/LLDB.h"
11+
12+
#include "TestingSupport/SubsystemRAII.h"
13+
#include "lldb/API/SBDebugger.h"
14+
#include "lldb/API/SBTarget.h"
15+
#include "gtest/gtest.h"
16+
#include <atomic>
17+
#include <chrono>
18+
#include <future>
19+
#include <mutex>
20+
21+
using namespace lldb;
22+
using namespace lldb_private;
23+
24+
class SBMutexTest : public testing::Test {
25+
protected:
26+
void SetUp() override { debugger = SBDebugger::Create(); }
27+
void TearDown() override { SBDebugger::Destroy(debugger); }
28+
29+
SubsystemRAII<lldb::SBDebugger> subsystems;
30+
SBDebugger debugger;
31+
};
32+
33+
TEST_F(SBMutexTest, LockTest) {
34+
lldb::SBTarget target = debugger.GetDummyTarget();
35+
36+
std::future<void> f;
37+
{
38+
std::atomic<bool> locked = false;
39+
lldb::SBMutex lock = target.GetAPIMutex();
40+
std::lock_guard<lldb::SBMutex> lock_guard(lock);
41+
ASSERT_FALSE(locked.exchange(true));
42+
43+
f = std::async(std::launch::async, [&]() {
44+
ASSERT_TRUE(locked);
45+
target.BreakpointCreateByName("foo", "bar");
46+
ASSERT_FALSE(locked);
47+
});
48+
ASSERT_TRUE(f.valid());
49+
50+
// Wait 500ms to confirm the thread is blocked.
51+
auto status = f.wait_for(std::chrono::milliseconds(500));
52+
ASSERT_EQ(status, std::future_status::timeout);
53+
54+
ASSERT_TRUE(locked.exchange(false));
55+
}
56+
f.wait();
57+
}

0 commit comments

Comments
 (0)