Skip to content

Commit c27cab4

Browse files
committed
[lldb][progress] Hook up new broadcast bit and progress manager
This commit adds the functionality to broadcast events using the `Debugger::eBroadcastProgressCategory` bit (llvm#81169) by keeping track of these reports with the `ProgressManager` class (llvm#81319). The new bit is used in such a way that it will only broadcast the initial and final progress reports for specific progress categories that are managed by the progress manager. This commit also adds a new test to the progress report unit test that checks that only the initial/final reports are broadcasted when using the new bit.
1 parent f01ed3b commit c27cab4

File tree

5 files changed

+164
-23
lines changed

5 files changed

+164
-23
lines changed

lldb/include/lldb/Core/Debugger.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,7 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
593593
friend class CommandInterpreter;
594594
friend class REPL;
595595
friend class Progress;
596+
friend class ProgressManager;
596597

597598
/// Report progress events.
598599
///
@@ -626,7 +627,8 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
626627
static void ReportProgress(uint64_t progress_id, std::string title,
627628
std::string details, uint64_t completed,
628629
uint64_t total,
629-
std::optional<lldb::user_id_t> debugger_id);
630+
std::optional<lldb::user_id_t> debugger_id,
631+
uint32_t progress_category_bit);
630632

631633
static void ReportDiagnosticImpl(DiagnosticEventData::Type type,
632634
std::string message,

lldb/include/lldb/Core/Progress.h

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@
99
#ifndef LLDB_CORE_PROGRESS_H
1010
#define LLDB_CORE_PROGRESS_H
1111

12-
#include "lldb/Utility/ConstString.h"
12+
#include "lldb/lldb-forward.h"
1313
#include "lldb/lldb-types.h"
1414
#include "llvm/ADT/StringMap.h"
1515
#include <atomic>
16+
#include <cstdint>
1617
#include <mutex>
1718
#include <optional>
1819

@@ -97,12 +98,32 @@ class Progress {
9798
/// Used to indicate a non-deterministic progress report
9899
static constexpr uint64_t kNonDeterministicTotal = UINT64_MAX;
99100

101+
/// Use a struct to send data from a Progress object to
102+
/// ProgressManager::ReportProgress. In addition to the Progress member fields
103+
/// this also passes the debugger progress broadcast bit. Using the progress
104+
/// category bit indicates that the given progress report is the initial or
105+
/// final report for its category.
106+
struct ProgressData {
107+
std::string title;
108+
std::string details;
109+
uint64_t progress_id;
110+
uint64_t completed;
111+
uint64_t total;
112+
std::optional<lldb::user_id_t> debugger_id;
113+
uint32_t progress_broadcast_bit;
114+
};
115+
100116
private:
117+
friend class Debugger;
101118
void ReportProgress();
102119
static std::atomic<uint64_t> g_id;
103-
/// The title of the progress activity.
120+
/// The title of the progress activity, also used as a category to group
121+
/// reports.
104122
std::string m_title;
123+
/// More specific information about the current file being displayed in the
124+
/// report.
105125
std::string m_details;
126+
/// Mutex for synchronization.
106127
std::mutex m_mutex;
107128
/// A unique integer identifier for progress reporting.
108129
const uint64_t m_id;
@@ -118,6 +139,8 @@ class Progress {
118139
/// to ensure that we don't send progress updates after progress has
119140
/// completed.
120141
bool m_complete = false;
142+
/// Data needed by the debugger to broadcast a progress event.
143+
ProgressData m_progress_data;
121144
};
122145

123146
/// A class used to group progress reports by category. This is done by using a
@@ -130,13 +153,21 @@ class ProgressManager {
130153
~ProgressManager();
131154

132155
/// Control the refcount of the progress report category as needed.
133-
void Increment(std::string category);
134-
void Decrement(std::string category);
156+
void Increment(Progress::ProgressData);
157+
void Decrement(Progress::ProgressData);
135158

136159
static ProgressManager &Instance();
137160

161+
llvm::StringMap<std::pair<uint64_t, Progress::ProgressData>>
162+
GetProgressCategoryMap() {
163+
return m_progress_category_map;
164+
}
165+
166+
void ReportProgress(Progress::ProgressData);
167+
138168
private:
139-
llvm::StringMap<uint64_t> m_progress_category_map;
169+
llvm::StringMap<std::pair<uint64_t, Progress::ProgressData>>
170+
m_progress_category_map;
140171
std::mutex m_progress_map_mutex;
141172
};
142173

lldb/source/Core/Debugger.cpp

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "lldb/Core/ModuleList.h"
1616
#include "lldb/Core/ModuleSpec.h"
1717
#include "lldb/Core/PluginManager.h"
18+
#include "lldb/Core/Progress.h"
1819
#include "lldb/Core/StreamAsynchronousIO.h"
1920
#include "lldb/DataFormatters/DataVisualization.h"
2021
#include "lldb/Expression/REPL.h"
@@ -1433,11 +1434,30 @@ void Debugger::SetDestroyCallback(
14331434
static void PrivateReportProgress(Debugger &debugger, uint64_t progress_id,
14341435
std::string title, std::string details,
14351436
uint64_t completed, uint64_t total,
1436-
bool is_debugger_specific) {
1437+
bool is_debugger_specific,
1438+
uint32_t progress_broadcast_bit) {
14371439
// Only deliver progress events if we have any progress listeners.
14381440
const uint32_t event_type = Debugger::eBroadcastBitProgress;
1439-
if (!debugger.GetBroadcaster().EventTypeHasListeners(event_type))
1441+
const uint32_t category_event_type = Debugger::eBroadcastBitProgressCategory;
1442+
if (!debugger.GetBroadcaster().EventTypeHasListeners(event_type |
1443+
category_event_type))
14401444
return;
1445+
1446+
if (debugger.GetBroadcaster().EventTypeHasListeners(category_event_type)) {
1447+
ProgressManager &progress_manager = ProgressManager::Instance();
1448+
auto map_refcount = progress_manager.GetProgressCategoryMap().lookup(title);
1449+
1450+
// Only broadcast the event to the progress category bit if it's an initial
1451+
// or final report for that category. Since we're broadcasting for the
1452+
// category specifically, clear the details.
1453+
if (progress_broadcast_bit == Debugger::eBroadcastBitProgressCategory) {
1454+
EventSP event_sp(new Event(
1455+
category_event_type,
1456+
new ProgressEventData(progress_id, std::move(title), "", completed,
1457+
total, is_debugger_specific)));
1458+
debugger.GetBroadcaster().BroadcastEvent(event_sp);
1459+
}
1460+
}
14411461
EventSP event_sp(new Event(
14421462
event_type,
14431463
new ProgressEventData(progress_id, std::move(title), std::move(details),
@@ -1448,7 +1468,8 @@ static void PrivateReportProgress(Debugger &debugger, uint64_t progress_id,
14481468
void Debugger::ReportProgress(uint64_t progress_id, std::string title,
14491469
std::string details, uint64_t completed,
14501470
uint64_t total,
1451-
std::optional<lldb::user_id_t> debugger_id) {
1471+
std::optional<lldb::user_id_t> debugger_id,
1472+
uint32_t progress_category_bit) {
14521473
// Check if this progress is for a specific debugger.
14531474
if (debugger_id) {
14541475
// It is debugger specific, grab it and deliver the event if the debugger
@@ -1457,7 +1478,8 @@ void Debugger::ReportProgress(uint64_t progress_id, std::string title,
14571478
if (debugger_sp)
14581479
PrivateReportProgress(*debugger_sp, progress_id, std::move(title),
14591480
std::move(details), completed, total,
1460-
/*is_debugger_specific*/ true);
1481+
/*is_debugger_specific*/ true,
1482+
progress_category_bit);
14611483
return;
14621484
}
14631485
// The progress event is not debugger specific, iterate over all debuggers
@@ -1467,7 +1489,8 @@ void Debugger::ReportProgress(uint64_t progress_id, std::string title,
14671489
DebuggerList::iterator pos, end = g_debugger_list_ptr->end();
14681490
for (pos = g_debugger_list_ptr->begin(); pos != end; ++pos)
14691491
PrivateReportProgress(*(*pos), progress_id, title, details, completed,
1470-
total, /*is_debugger_specific*/ false);
1492+
total, /*is_debugger_specific*/ false,
1493+
progress_category_bit);
14711494
}
14721495
}
14731496

@@ -1875,7 +1898,8 @@ lldb::thread_result_t Debugger::DefaultEventHandler() {
18751898

18761899
listener_sp->StartListeningForEvents(
18771900
&m_broadcaster, eBroadcastBitProgress | eBroadcastBitWarning |
1878-
eBroadcastBitError | eBroadcastSymbolChange);
1901+
eBroadcastBitError | eBroadcastSymbolChange |
1902+
eBroadcastBitProgressCategory);
18791903

18801904
// Let the thread that spawned us know that we have started up and that we
18811905
// are now listening to all required events so no events get missed
@@ -1929,6 +1953,8 @@ lldb::thread_result_t Debugger::DefaultEventHandler() {
19291953
} else if (broadcaster == &m_broadcaster) {
19301954
if (event_type & Debugger::eBroadcastBitProgress)
19311955
HandleProgressEvent(event_sp);
1956+
else if (event_type & Debugger::eBroadcastBitProgressCategory)
1957+
HandleProgressEvent(event_sp);
19321958
else if (event_type & Debugger::eBroadcastBitWarning)
19331959
HandleDiagnosticEvent(event_sp);
19341960
else if (event_type & Debugger::eBroadcastBitError)

lldb/source/Core/Progress.cpp

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,16 @@ Progress::Progress(std::string title, std::string details,
2929

3030
if (debugger)
3131
m_debugger_id = debugger->GetID();
32+
33+
m_progress_data = {m_title,
34+
m_details,
35+
m_id,
36+
m_completed,
37+
m_total,
38+
m_debugger_id,
39+
Debugger::eBroadcastBitProgress};
3240
std::lock_guard<std::mutex> guard(m_mutex);
33-
ReportProgress();
41+
ProgressManager::Instance().Increment(m_progress_data);
3442
}
3543

3644
Progress::~Progress() {
@@ -39,7 +47,8 @@ Progress::~Progress() {
3947
std::lock_guard<std::mutex> guard(m_mutex);
4048
if (!m_completed)
4149
m_completed = m_total;
42-
ReportProgress();
50+
m_progress_data.completed = m_completed;
51+
ProgressManager::Instance().Decrement(m_progress_data);
4352
}
4453

4554
void Progress::Increment(uint64_t amount,
@@ -64,7 +73,7 @@ void Progress::ReportProgress() {
6473
// complete
6574
m_complete = m_completed == m_total;
6675
Debugger::ReportProgress(m_id, m_title, m_details, m_completed, m_total,
67-
m_debugger_id);
76+
m_debugger_id, Debugger::eBroadcastBitProgress);
6877
}
6978
}
7079

@@ -82,20 +91,36 @@ ProgressManager &ProgressManager::Instance() {
8291
return *g_progress_manager;
8392
}
8493

85-
void ProgressManager::Increment(std::string title) {
94+
void ProgressManager::Increment(Progress::ProgressData progress_data) {
8695
std::lock_guard<std::mutex> lock(m_progress_map_mutex);
87-
m_progress_category_map[title]++;
96+
progress_data.progress_broadcast_bit =
97+
m_progress_category_map.contains(progress_data.title)
98+
? Debugger::eBroadcastBitProgress
99+
: Debugger::eBroadcastBitProgressCategory;
100+
ReportProgress(progress_data);
101+
m_progress_category_map[progress_data.title].first++;
88102
}
89103

90-
void ProgressManager::Decrement(std::string title) {
104+
void ProgressManager::Decrement(Progress::ProgressData progress_data) {
91105
std::lock_guard<std::mutex> lock(m_progress_map_mutex);
92-
auto pos = m_progress_category_map.find(title);
106+
auto pos = m_progress_category_map.find(progress_data.title);
93107

94108
if (pos == m_progress_category_map.end())
95109
return;
96110

97-
if (pos->second <= 1)
98-
m_progress_category_map.erase(title);
99-
else
100-
--pos->second;
111+
if (pos->second.first <= 1) {
112+
progress_data.progress_broadcast_bit =
113+
Debugger::eBroadcastBitProgressCategory;
114+
m_progress_category_map.erase(progress_data.title);
115+
} else
116+
--pos->second.first;
117+
118+
ReportProgress(progress_data);
119+
}
120+
121+
void ProgressManager::ReportProgress(Progress::ProgressData progress_data) {
122+
Debugger::ReportProgress(progress_data.progress_id, progress_data.title,
123+
progress_data.details, progress_data.completed,
124+
progress_data.total, progress_data.debugger_id,
125+
progress_data.progress_broadcast_bit);
101126
}

lldb/unittests/Core/ProgressReportTest.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,3 +126,60 @@ TEST_F(ProgressReportTest, TestReportCreation) {
126126
ASSERT_FALSE(data->IsFinite());
127127
ASSERT_EQ(data->GetMessage(), "Progress report 1: Starting report 1");
128128
}
129+
130+
TEST_F(ProgressReportTest, TestProgressManager) {
131+
std::chrono::milliseconds timeout(100);
132+
133+
// Set up the debugger, make sure that was done properly.
134+
ArchSpec arch("x86_64-apple-macosx-");
135+
Platform::SetHostPlatform(PlatformRemoteMacOSX::CreateInstance(true, &arch));
136+
137+
DebuggerSP debugger_sp = Debugger::CreateInstance();
138+
ASSERT_TRUE(debugger_sp);
139+
140+
// Get the debugger's broadcaster.
141+
Broadcaster &broadcaster = debugger_sp->GetBroadcaster();
142+
143+
// Create a listener, make sure it can receive events and that it's
144+
// listening to the correct broadcast bit.
145+
ListenerSP listener_sp = Listener::MakeListener("progress-category-listener");
146+
147+
listener_sp->StartListeningForEvents(&broadcaster,
148+
Debugger::eBroadcastBitProgressCategory);
149+
EXPECT_TRUE(broadcaster.EventTypeHasListeners(
150+
Debugger::eBroadcastBitProgressCategory));
151+
152+
EventSP event_sp;
153+
const ProgressEventData *data;
154+
155+
// Create three progress events with the same category then try to pop 2
156+
// events from the queue in a row before the progress reports are destroyed.
157+
// Since only 1 event should've been broadcast for this category, the second
158+
// GetEvent() call should return false.
159+
{
160+
Progress progress1("Progress report 1", "Starting report 1");
161+
Progress progress2("Progress report 1", "Starting report 2");
162+
Progress progress3("Progress report 1", "Starting report 3");
163+
EXPECT_TRUE(listener_sp->GetEvent(event_sp, timeout));
164+
EXPECT_FALSE(listener_sp->GetEvent(event_sp, timeout));
165+
}
166+
167+
data = ProgressEventData::GetEventDataFromEvent(event_sp.get());
168+
169+
ASSERT_EQ(data->GetDetails(), "");
170+
ASSERT_FALSE(data->IsFinite());
171+
ASSERT_FALSE(data->GetCompleted());
172+
ASSERT_EQ(data->GetTotal(), Progress::kNonDeterministicTotal);
173+
ASSERT_EQ(data->GetMessage(), "Progress report 1");
174+
175+
// Pop another event from the queue, this should be the event for the final
176+
// report for this category.
177+
EXPECT_TRUE(listener_sp->GetEvent(event_sp, timeout));
178+
179+
data = ProgressEventData::GetEventDataFromEvent(event_sp.get());
180+
ASSERT_EQ(data->GetDetails(), "");
181+
ASSERT_FALSE(data->IsFinite());
182+
ASSERT_TRUE(data->GetCompleted());
183+
ASSERT_EQ(data->GetTotal(), Progress::kNonDeterministicTotal);
184+
ASSERT_EQ(data->GetMessage(), "Progress report 1");
185+
}

0 commit comments

Comments
 (0)