Skip to content

Commit 1ed233a

Browse files
committed
[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 (cherry picked from commit 50949eb)
1 parent 5628f41 commit 1ed233a

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;
@@ -957,6 +957,8 @@ class LLDB_API SBTarget {
957957
/// An error if a Trace already exists or the trace couldn't be created.
958958
lldb::SBTrace CreateTrace(SBError &error);
959959

960+
lldb::SBMutex GetAPIMutex() const;
961+
960962
protected:
961963
friend class SBAddress;
962964
friend class SBAddressRange;

lldb/source/API/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ add_lldb_library(liblldb SHARED ${option_framework}
9292
SBMemoryRegionInfoList.cpp
9393
SBModule.cpp
9494
SBModuleSpec.cpp
95+
SBMutex.cpp
9596
SBPlatform.cpp
9697
SBProgress.cpp
9798
SBProcess.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 "Plugins/TypeSystem/Clang/TypeSystemClang.h"
1511
#include "lldb/API/SBBreakpoint.h"
1612
#include "lldb/API/SBDebugger.h"
@@ -21,6 +17,7 @@
2117
#include "lldb/API/SBListener.h"
2218
#include "lldb/API/SBModule.h"
2319
#include "lldb/API/SBModuleSpec.h"
20+
#include "lldb/API/SBMutex.h"
2421
#include "lldb/API/SBProcess.h"
2522
#include "lldb/API/SBSourceManager.h"
2623
#include "lldb/API/SBStream.h"
@@ -59,11 +56,14 @@
5956
#include "lldb/Utility/ArchSpec.h"
6057
#include "lldb/Utility/Args.h"
6158
#include "lldb/Utility/FileSpec.h"
59+
#include "lldb/Utility/Instrumentation.h"
60+
#include "lldb/Utility/LLDBLog.h"
6261
#include "lldb/Utility/ProcessInfo.h"
6362
#include "lldb/Utility/RegularExpression.h"
6463
#include "lldb/ValueObject/ValueObjectConstResult.h"
6564
#include "lldb/ValueObject/ValueObjectList.h"
6665
#include "lldb/ValueObject/ValueObjectVariable.h"
66+
#include "lldb/lldb-public.h"
6767

6868
#include "Commands/CommandObjectBreakpoint.h"
6969
#include "lldb/Interpreter/CommandReturnObject.h"
@@ -2497,3 +2497,11 @@ lldb::SBTrace SBTarget::CreateTrace(lldb::SBError &error) {
24972497
}
24982498
return SBTrace();
24992499
}
2500+
2501+
lldb::SBMutex SBTarget::GetAPIMutex() const {
2502+
LLDB_INSTRUMENT_VA(this);
2503+
2504+
if (TargetSP target_sp = GetSP())
2505+
return lldb::SBMutex(target_sp);
2506+
return lldb::SBMutex();
2507+
}

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

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

lldb/unittests/API/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
add_lldb_unittest(APITests
22
SBCommandInterpreterTest.cpp
3+
SBMutexTest.cpp
34

45
LINK_LIBS
56
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)