Skip to content

Commit ab4700b

Browse files
committed
[lldb] Expose the Target API lock through the SB API
1 parent 029cb8a commit ab4700b

File tree

13 files changed

+230
-5
lines changed

13 files changed

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

lldb/bindings/interfaces.swig

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
%include "./interface/SBLaunchInfoDocstrings.i"
4848
%include "./interface/SBLineEntryDocstrings.i"
4949
%include "./interface/SBListenerDocstrings.i"
50+
%include "./interface/SBLockExtensions.i"
5051
%include "./interface/SBMemoryRegionInfoDocstrings.i"
5152
%include "./interface/SBMemoryRegionInfoListDocstrings.i"
5253
%include "./interface/SBModuleDocstrings.i"
@@ -121,11 +122,12 @@
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"
130+
%include "lldb/API/SBLock.h"
129131
%include "lldb/API/SBMemoryRegionInfo.h"
130132
%include "lldb/API/SBMemoryRegionInfoList.h"
131133
%include "lldb/API/SBModule.h"

lldb/include/lldb/API/LLDB.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
#include "lldb/API/SBLaunchInfo.h"
4747
#include "lldb/API/SBLineEntry.h"
4848
#include "lldb/API/SBListener.h"
49+
#include "lldb/API/SBLock.h"
4950
#include "lldb/API/SBMemoryRegionInfo.h"
5051
#include "lldb/API/SBMemoryRegionInfoList.h"
5152
#include "lldb/API/SBModule.h"

lldb/include/lldb/API/SBDefines.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ class LLDB_API SBLanguageRuntime;
8484
class LLDB_API SBLaunchInfo;
8585
class LLDB_API SBLineEntry;
8686
class LLDB_API SBListener;
87+
class LLDB_API SBLock;
8788
class LLDB_API SBMemoryRegionInfo;
8889
class LLDB_API SBMemoryRegionInfoList;
8990
class LLDB_API SBModule;

lldb/include/lldb/API/SBLock.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//===-- SBLock.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_SBLOCK_H
10+
#define LLDB_API_SBLOCK_H
11+
12+
#include "lldb/API/SBDefines.h"
13+
#include "lldb/lldb-forward.h"
14+
#include <mutex>
15+
16+
namespace lldb_private {
17+
class APILock;
18+
}
19+
20+
namespace lldb {
21+
22+
class LLDB_API SBLock {
23+
public:
24+
SBLock();
25+
SBLock(SBLock &&rhs);
26+
SBLock &operator=(SBLock &&rhs);
27+
~SBLock();
28+
29+
bool IsValid() const;
30+
31+
void Unlock() const;
32+
33+
private:
34+
// Private constructor used by SBTarget to create the Target API lock.
35+
// Requires a friend declaration.
36+
SBLock(lldb::TargetSP target_sp);
37+
friend class SBTarget;
38+
39+
SBLock(const SBLock &rhs) = delete;
40+
const SBLock &operator=(const SBLock &rhs) = delete;
41+
42+
std::unique_ptr<lldb_private::APILock> m_opaque_up;
43+
};
44+
#endif
45+
46+
} // namespace lldb

lldb/include/lldb/API/SBTarget.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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::SBLock AcquireAPILock() const;
950+
949951
protected:
950952
friend class SBAddress;
951953
friend class SBAddressRange;

lldb/include/lldb/Target/Target.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1692,6 +1692,21 @@ class Target : public std::enable_shared_from_this<Target>,
16921692
}
16931693
};
16941694

1695+
/// The private implementation backing SBLock.
1696+
class APILock {
1697+
public:
1698+
APILock(std::shared_ptr<std::recursive_mutex> mutex_sp)
1699+
: m_mutex(std::move(mutex_sp)), m_lock(*m_mutex) {}
1700+
1701+
void Unlock() { m_lock.unlock(); }
1702+
1703+
operator bool() const { return static_cast<bool>(m_lock); }
1704+
1705+
private:
1706+
std::shared_ptr<std::recursive_mutex> m_mutex;
1707+
std::unique_lock<std::recursive_mutex> m_lock;
1708+
};
1709+
16951710
} // namespace lldb_private
16961711

16971712
#endif // LLDB_TARGET_TARGET_H

lldb/source/API/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ add_lldb_library(liblldb SHARED ${option_framework}
7777
SBLaunchInfo.cpp
7878
SBLineEntry.cpp
7979
SBListener.cpp
80+
SBLock.cpp
8081
SBMemoryRegionInfo.cpp
8182
SBMemoryRegionInfoList.cpp
8283
SBModule.cpp

lldb/source/API/SBLock.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
//===-- SBLock.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/SBLock.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+
SBLock::SBLock() { LLDB_INSTRUMENT_VA(this); }
20+
21+
SBLock::SBLock(SBLock &&rhs) : m_opaque_up(std::move(rhs.m_opaque_up)) {
22+
LLDB_INSTRUMENT_VA(this);
23+
}
24+
25+
SBLock &SBLock::operator=(SBLock &&rhs) {
26+
LLDB_INSTRUMENT_VA(this);
27+
28+
m_opaque_up = std::move(rhs.m_opaque_up);
29+
return *this;
30+
}
31+
32+
SBLock::SBLock(lldb::TargetSP target_sp)
33+
: m_opaque_up(
34+
std::make_unique<APILock>(std::shared_ptr<std::recursive_mutex>(
35+
target_sp, &target_sp->GetAPIMutex()))) {
36+
LLDB_INSTRUMENT_VA(this, target_sp);
37+
}
38+
39+
SBLock::~SBLock() { LLDB_INSTRUMENT_VA(this); }
40+
41+
bool SBLock::IsValid() const {
42+
LLDB_INSTRUMENT_VA(this);
43+
44+
return static_cast<bool>(m_opaque_up) && static_cast<bool>(*m_opaque_up);
45+
}
46+
47+
void SBLock::Unlock() const {
48+
LLDB_INSTRUMENT_VA(this);
49+
50+
if (m_opaque_up)
51+
m_opaque_up->Unlock();
52+
}

lldb/source/API/SBTarget.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,14 @@
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"
1713
#include "lldb/API/SBEvent.h"
1814
#include "lldb/API/SBExpressionOptions.h"
1915
#include "lldb/API/SBFileSpec.h"
2016
#include "lldb/API/SBListener.h"
17+
#include "lldb/API/SBLock.h"
2118
#include "lldb/API/SBModule.h"
2219
#include "lldb/API/SBModuleSpec.h"
2320
#include "lldb/API/SBProcess.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::SBLock SBTarget::AcquireAPILock() const {
2444+
LLDB_INSTRUMENT_VA(this);
2445+
2446+
if (TargetSP target_sp = GetSP())
2447+
return lldb::SBLock(target_sp);
2448+
return lldb::SBLock();
2449+
}

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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -537,3 +537,31 @@ 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_acquire_sblock(self):
543+
"""Make sure we can acquire the API lock from Python."""
544+
target = self.dbg.GetDummyTarget()
545+
546+
lock = target.AcquireAPILock()
547+
self.assertTrue(lock.IsValid())
548+
# The API call below doesn't actually matter, it's just there to
549+
# confirm we don't block on the API lock.
550+
target.BreakpointCreateByName("foo", "bar")
551+
lock.Unlock()
552+
self.assertFalse(lock.IsValid())
553+
554+
@no_debug_info_test
555+
def test_acquire_sblock_with_statement(self):
556+
"""Make sure we can acquire the API lock using a with-statement from Python."""
557+
target = self.dbg.GetDummyTarget()
558+
559+
lock_copy = None
560+
with target.AcquireAPILock() as lock:
561+
self.assertTrue(lock.IsValid())
562+
# The API call below doesn't actually matter, it's just there to
563+
# confirm we don't block on the API lock.
564+
target.BreakpointCreateByName("foo", "bar")
565+
lock_copy = lock
566+
self.assertTrue(lock.IsValid())
567+
self.assertFalse(lock_copy.IsValid())

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+
SBLockTest.cpp
45

56
LINK_LIBS
67
liblldb

lldb/unittests/API/SBLockTest.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
//===-- SBLockTest.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+
20+
using namespace lldb;
21+
using namespace lldb_private;
22+
23+
class SBLockTest : public testing::Test {
24+
protected:
25+
void SetUp() override { debugger = SBDebugger::Create(); }
26+
void TearDown() override { SBDebugger::Destroy(debugger); }
27+
28+
SubsystemRAII<lldb::SBDebugger> subsystems;
29+
SBDebugger debugger;
30+
};
31+
32+
TEST_F(SBLockTest, LockTest) {
33+
lldb::SBTarget target = debugger.GetDummyTarget();
34+
35+
std::future<void> f;
36+
{
37+
std::atomic<bool> locked = false;
38+
lldb::SBLock lock = target.AcquireAPILock();
39+
ASSERT_FALSE(locked.exchange(true));
40+
41+
f = std::async(std::launch::async, [&]() {
42+
{
43+
ASSERT_TRUE(locked);
44+
target.BreakpointCreateByName("foo", "bar");
45+
ASSERT_FALSE(locked);
46+
}
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)