Skip to content

Commit 5ea2ad6

Browse files
committed
[lldb] Expose the Target API lock through the SB API
1 parent 7a7c33d commit 5ea2ad6

File tree

9 files changed

+193
-17
lines changed

9 files changed

+193
-17
lines changed

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: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
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+
15+
#include <mutex>
16+
17+
namespace lldb_private {
18+
struct APILock;
19+
}
20+
21+
namespace lldb {
22+
23+
#ifndef SWIG
24+
class LLDB_API SBLock {
25+
public:
26+
~SBLock();
27+
28+
bool IsValid() const;
29+
30+
private:
31+
friend class SBTarget;
32+
33+
SBLock() = default;
34+
SBLock(std::recursive_mutex &mutex);
35+
SBLock(std::recursive_mutex &mutex, lldb::TargetSP target_sp);
36+
SBLock(const SBLock &rhs) = delete;
37+
const SBLock &operator=(const SBLock &rhs) = delete;
38+
39+
std::unique_ptr<lldb_private::APILock> m_opaque_up;
40+
};
41+
#endif
42+
43+
} // namespace lldb
44+
45+
#endif

lldb/include/lldb/API/SBTarget.h

Lines changed: 5 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,10 @@ 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+
#ifndef SWIG
950+
lldb::SBLock GetAPILock() const;
951+
#endif
952+
949953
protected:
950954
friend class SBAddress;
951955
friend class SBAddressRange;

lldb/include/lldb/Target/Target.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1327,7 +1327,7 @@ class Target : public std::enable_shared_from_this<Target>,
13271327
StopHook(const StopHook &rhs);
13281328
virtual ~StopHook() = default;
13291329

1330-
enum class StopHookKind : uint32_t { CommandBased = 0, ScriptBased };
1330+
enum class StopHookKind : uint32_t { CommandBased = 0, ScriptBased };
13311331
enum class StopHookResult : uint32_t {
13321332
KeepStopped = 0,
13331333
RequestContinue,
@@ -1692,6 +1692,20 @@ class Target : public std::enable_shared_from_this<Target>,
16921692
}
16931693
};
16941694

1695+
/// The private implementation backing SBLock.
1696+
struct APILock {
1697+
APILock(std::recursive_mutex &mutex) : lock(mutex) {}
1698+
std::lock_guard<std::recursive_mutex> lock;
1699+
};
1700+
1701+
/// The private implementation used by SBLock to hand out the target API mutex.
1702+
/// It has a TargetSP to ensure the lock cannot outlive the target.
1703+
struct TargetAPILock : public APILock {
1704+
TargetAPILock(std::recursive_mutex &mutex, lldb::TargetSP target_sp)
1705+
: APILock(mutex), target_sp(target_sp) {}
1706+
lldb::TargetSP target_sp;
1707+
};
1708+
16951709
} // namespace lldb_private
16961710

16971711
#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: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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+
14+
#include <memory>
15+
#include <mutex>
16+
17+
using namespace lldb;
18+
using namespace lldb_private;
19+
20+
#ifndef SWIG
21+
22+
SBLock::SBLock(std::recursive_mutex &mutex)
23+
: m_opaque_up(std::make_unique<APILock>(mutex)) {
24+
LLDB_INSTRUMENT_VA(this);
25+
}
26+
27+
SBLock::SBLock(std::recursive_mutex &mutex, lldb::TargetSP target_sp)
28+
: m_opaque_up(std::make_unique<TargetAPILock>(mutex, target_sp)) {
29+
LLDB_INSTRUMENT_VA(this);
30+
}
31+
32+
SBLock::~SBLock() { LLDB_INSTRUMENT_VA(this); }
33+
34+
bool SBLock::IsValid() const {
35+
LLDB_INSTRUMENT_VA(this);
36+
37+
return static_cast<bool>(m_opaque_up);
38+
}
39+
40+
#endif

lldb/source/API/SBTarget.cpp

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

99
#include "lldb/API/SBTarget.h"
10+
#include "lldb/API/SBLock.h"
1011
#include "lldb/Utility/Instrumentation.h"
1112
#include "lldb/Utility/LLDBLog.h"
1213
#include "lldb/lldb-public.h"
@@ -18,6 +19,7 @@
1819
#include "lldb/API/SBExpressionOptions.h"
1920
#include "lldb/API/SBFileSpec.h"
2021
#include "lldb/API/SBListener.h"
22+
#include "lldb/API/SBLock.h"
2123
#include "lldb/API/SBModule.h"
2224
#include "lldb/API/SBModuleSpec.h"
2325
#include "lldb/API/SBProcess.h"
@@ -544,9 +546,8 @@ lldb::SBProcess SBTarget::ConnectRemote(SBListener &listener, const char *url,
544546
if (target_sp) {
545547
std::lock_guard<std::recursive_mutex> guard(target_sp->GetAPIMutex());
546548
if (listener.IsValid())
547-
process_sp =
548-
target_sp->CreateProcess(listener.m_opaque_sp, plugin_name, nullptr,
549-
true);
549+
process_sp = target_sp->CreateProcess(listener.m_opaque_sp, plugin_name,
550+
nullptr, true);
550551
else
551552
process_sp = target_sp->CreateProcess(
552553
target_sp->GetDebugger().GetListener(), plugin_name, nullptr, true);
@@ -1040,7 +1041,7 @@ SBTarget::BreakpointCreateForException(lldb::LanguageType language,
10401041
std::lock_guard<std::recursive_mutex> guard(target_sp->GetAPIMutex());
10411042
const bool hardware = false;
10421043
sb_bp = target_sp->CreateExceptionBreakpoint(language, catch_bp, throw_bp,
1043-
hardware);
1044+
hardware);
10441045
}
10451046

10461047
return sb_bp;
@@ -1060,14 +1061,9 @@ lldb::SBBreakpoint SBTarget::BreakpointCreateFromScript(
10601061
Status error;
10611062

10621063
StructuredData::ObjectSP obj_sp = extra_args.m_impl_up->GetObjectSP();
1063-
sb_bp =
1064-
target_sp->CreateScriptedBreakpoint(class_name,
1065-
module_list.get(),
1066-
file_list.get(),
1067-
false, /* internal */
1068-
request_hardware,
1069-
obj_sp,
1070-
&error);
1064+
sb_bp = target_sp->CreateScriptedBreakpoint(
1065+
class_name, module_list.get(), file_list.get(), false, /* internal */
1066+
request_hardware, obj_sp, &error);
10711067
}
10721068

10731069
return sb_bp;
@@ -1692,8 +1688,8 @@ uint32_t SBTarget::GetMaximumNumberOfChildrenToDisplay() const {
16921688
LLDB_INSTRUMENT_VA(this);
16931689

16941690
TargetSP target_sp(GetSP());
1695-
if(target_sp){
1696-
return target_sp->GetMaximumNumberOfChildrenToDisplay();
1691+
if (target_sp) {
1692+
return target_sp->GetMaximumNumberOfChildrenToDisplay();
16971693
}
16981694
return 0;
16991695
}
@@ -2193,7 +2189,7 @@ SBError SBTarget::SetModuleLoadAddress(lldb::SBModule module,
21932189
}
21942190

21952191
SBError SBTarget::SetModuleLoadAddress(lldb::SBModule module,
2196-
uint64_t slide_offset) {
2192+
uint64_t slide_offset) {
21972193

21982194
SBError sb_error;
21992195

@@ -2439,3 +2435,13 @@ lldb::SBTrace SBTarget::CreateTrace(lldb::SBError &error) {
24392435
}
24402436
return SBTrace();
24412437
}
2438+
2439+
#ifndef SWIG
2440+
lldb::SBLock SBTarget::GetAPILock() const {
2441+
LLDB_INSTRUMENT_VA(this);
2442+
2443+
if (TargetSP target_sp = GetSP())
2444+
return lldb::SBLock(target_sp->GetAPIMutex(), target_sp);
2445+
return lldb::SBLock();
2446+
}
2447+
#endif

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: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
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+
#include "lldb/API/SBLock.h"
10+
#include "lldb/API/SBDebugger.h"
11+
#include "lldb/API/SBTarget.h"
12+
#include "gtest/gtest.h"
13+
#include <atomic>
14+
#include <chrono>
15+
#include <thread>
16+
17+
TEST(SBLockTest, LockTest) {
18+
lldb::SBDebugger debugger = lldb::SBDebugger::Create();
19+
lldb::SBTarget target = debugger.GetDummyTarget();
20+
21+
std::mutex m;
22+
std::condition_variable cv;
23+
bool wakeup = false;
24+
std::atomic<bool> locked = false;
25+
26+
std::thread test_thread([&]() {
27+
{
28+
{
29+
std::unique_lock lk(m);
30+
cv.wait(lk, [&] { return wakeup; });
31+
}
32+
33+
ASSERT_TRUE(locked);
34+
target.BreakpointCreateByName("foo", "bar");
35+
ASSERT_FALSE(locked);
36+
37+
cv.notify_one();
38+
}
39+
});
40+
41+
// Take the API lock.
42+
{
43+
lldb::SBLock lock = target.GetAPILock();
44+
ASSERT_FALSE(locked.exchange(true));
45+
46+
// Wake up the test thread.
47+
{
48+
std::lock_guard lk(m);
49+
wakeup = true;
50+
}
51+
cv.notify_one();
52+
53+
// Wait 500ms to confirm the thread is blocked.
54+
{
55+
std::unique_lock<std::mutex> lk(m);
56+
auto result = cv.wait_for(lk, std::chrono::milliseconds(500));
57+
ASSERT_EQ(result, std::cv_status::timeout);
58+
}
59+
60+
ASSERT_TRUE(locked.exchange(false));
61+
}
62+
63+
test_thread.join();
64+
}

0 commit comments

Comments
 (0)