Skip to content

Commit 09fd430

Browse files
authored
[lldb-dap] Refactor event thread (#166948)
Handle each event type in a different function
1 parent aca28f1 commit 09fd430

File tree

2 files changed

+178
-156
lines changed

2 files changed

+178
-156
lines changed

lldb/tools/lldb-dap/DAP.cpp

Lines changed: 174 additions & 156 deletions
Original file line numberDiff line numberDiff line change
@@ -1319,7 +1319,7 @@ void DAP::ProgressEventThread() {
13191319
lldb::SBEvent event;
13201320
bool done = false;
13211321
while (!done) {
1322-
if (listener.WaitForEvent(1, event)) {
1322+
if (listener.WaitForEvent(UINT32_MAX, event)) {
13231323
const auto event_mask = event.GetType();
13241324
if (event.BroadcasterMatchesRef(broadcaster)) {
13251325
if (event_mask & eBroadcastBitStopProgressThread) {
@@ -1377,7 +1377,6 @@ void DAP::ProgressEventThread() {
13771377
// is required.
13781378
void DAP::EventThread() {
13791379
llvm::set_thread_name("lldb.DAP.client." + m_client_name + ".event_handler");
1380-
lldb::SBEvent event;
13811380
lldb::SBListener listener = debugger.GetListener();
13821381
broadcaster.AddListener(listener, eBroadcastBitStopEventThread);
13831382
debugger.GetBroadcaster().AddListener(
@@ -1388,169 +1387,176 @@ void DAP::EventThread() {
13881387
debugger, lldb::SBThread::GetBroadcasterClassName(),
13891388
lldb::SBThread::eBroadcastBitStackChanged);
13901389

1390+
lldb::SBEvent event;
13911391
bool done = false;
13921392
while (!done) {
1393-
if (listener.WaitForEvent(1, event)) {
1394-
const auto event_mask = event.GetType();
1395-
if (lldb::SBProcess::EventIsProcessEvent(event)) {
1396-
lldb::SBProcess process = lldb::SBProcess::GetProcessFromEvent(event);
1397-
if (event_mask & lldb::SBProcess::eBroadcastBitStateChanged) {
1398-
auto state = lldb::SBProcess::GetStateFromEvent(event);
1399-
switch (state) {
1400-
case lldb::eStateConnected:
1401-
case lldb::eStateDetached:
1402-
case lldb::eStateInvalid:
1403-
case lldb::eStateUnloaded:
1404-
break;
1405-
case lldb::eStateAttaching:
1406-
case lldb::eStateCrashed:
1407-
case lldb::eStateLaunching:
1408-
case lldb::eStateStopped:
1409-
case lldb::eStateSuspended:
1410-
// Only report a stopped event if the process was not
1411-
// automatically restarted.
1412-
if (!lldb::SBProcess::GetRestartedFromEvent(event)) {
1413-
SendStdOutStdErr(*this, process);
1414-
if (llvm::Error err = SendThreadStoppedEvent(*this))
1415-
DAP_LOG_ERROR(log, std::move(err),
1416-
"({1}) reporting thread stopped: {0}",
1417-
m_client_name);
1418-
}
1419-
break;
1420-
case lldb::eStateRunning:
1421-
case lldb::eStateStepping:
1422-
WillContinue();
1423-
SendContinuedEvent(*this);
1424-
break;
1425-
case lldb::eStateExited:
1426-
lldb::SBStream stream;
1427-
process.GetStatus(stream);
1428-
SendOutput(OutputType::Console, stream.GetData());
1429-
1430-
// When restarting, we can get an "exited" event for the process we
1431-
// just killed with the old PID, or even with no PID. In that case
1432-
// we don't have to terminate the session.
1433-
if (process.GetProcessID() == LLDB_INVALID_PROCESS_ID ||
1434-
process.GetProcessID() == restarting_process_id) {
1435-
restarting_process_id = LLDB_INVALID_PROCESS_ID;
1436-
} else {
1437-
// Run any exit LLDB commands the user specified in the
1438-
// launch.json
1439-
RunExitCommands();
1440-
SendProcessExitedEvent(*this, process);
1441-
SendTerminatedEvent();
1442-
done = true;
1443-
}
1444-
break;
1445-
}
1446-
} else if ((event_mask & lldb::SBProcess::eBroadcastBitSTDOUT) ||
1447-
(event_mask & lldb::SBProcess::eBroadcastBitSTDERR)) {
1448-
SendStdOutStdErr(*this, process);
1449-
}
1450-
} else if (lldb::SBTarget::EventIsTargetEvent(event)) {
1451-
if (event_mask & lldb::SBTarget::eBroadcastBitModulesLoaded ||
1452-
event_mask & lldb::SBTarget::eBroadcastBitModulesUnloaded ||
1453-
event_mask & lldb::SBTarget::eBroadcastBitSymbolsLoaded ||
1454-
event_mask & lldb::SBTarget::eBroadcastBitSymbolsChanged) {
1455-
const uint32_t num_modules =
1456-
lldb::SBTarget::GetNumModulesFromEvent(event);
1457-
const bool remove_module =
1458-
event_mask & lldb::SBTarget::eBroadcastBitModulesUnloaded;
1459-
1460-
// NOTE: Both mutexes must be acquired to prevent deadlock when
1461-
// handling `modules_request`, which also requires both locks.
1462-
lldb::SBMutex api_mutex = GetAPIMutex();
1463-
const std::scoped_lock<lldb::SBMutex, std::mutex> guard(
1464-
api_mutex, modules_mutex);
1465-
for (uint32_t i = 0; i < num_modules; ++i) {
1466-
lldb::SBModule module =
1467-
lldb::SBTarget::GetModuleAtIndexFromEvent(i, event);
1468-
1469-
std::optional<protocol::Module> p_module =
1470-
CreateModule(target, module, remove_module);
1471-
if (!p_module)
1472-
continue;
1473-
1474-
llvm::StringRef module_id = p_module->id;
1475-
1476-
const bool module_exists = modules.contains(module_id);
1477-
if (remove_module && module_exists) {
1478-
modules.erase(module_id);
1479-
Send(protocol::Event{
1480-
"module", ModuleEventBody{std::move(p_module).value(),
1481-
ModuleEventBody::eReasonRemoved}});
1482-
} else if (module_exists) {
1483-
Send(protocol::Event{
1484-
"module", ModuleEventBody{std::move(p_module).value(),
1485-
ModuleEventBody::eReasonChanged}});
1486-
} else if (!remove_module) {
1487-
modules.insert(module_id);
1488-
Send(protocol::Event{
1489-
"module", ModuleEventBody{std::move(p_module).value(),
1490-
ModuleEventBody::eReasonNew}});
1491-
}
1492-
}
1493-
}
1494-
} else if (lldb::SBBreakpoint::EventIsBreakpointEvent(event)) {
1495-
if (event_mask & lldb::SBTarget::eBroadcastBitBreakpointChanged) {
1496-
auto event_type =
1497-
lldb::SBBreakpoint::GetBreakpointEventTypeFromEvent(event);
1498-
auto bp = Breakpoint(
1499-
*this, lldb::SBBreakpoint::GetBreakpointFromEvent(event));
1500-
// If the breakpoint was set through DAP, it will have the
1501-
// BreakpointBase::kDAPBreakpointLabel. Regardless of whether
1502-
// locations were added, removed, or resolved, the breakpoint isn't
1503-
// going away and the reason is always "changed".
1504-
if ((event_type & lldb::eBreakpointEventTypeLocationsAdded ||
1505-
event_type & lldb::eBreakpointEventTypeLocationsRemoved ||
1506-
event_type & lldb::eBreakpointEventTypeLocationsResolved) &&
1507-
bp.MatchesName(BreakpointBase::kDAPBreakpointLabel)) {
1508-
// As the DAP client already knows the path of this breakpoint, we
1509-
// don't need to send it back as part of the "changed" event. This
1510-
// avoids sending paths that should be source mapped. Note that
1511-
// CreateBreakpoint doesn't apply source mapping and certain
1512-
// implementation ignore the source part of this event anyway.
1513-
protocol::Breakpoint protocol_bp = bp.ToProtocolBreakpoint();
1514-
1515-
// "source" is not needed here, unless we add adapter data to be
1516-
// saved by the client.
1517-
if (protocol_bp.source && !protocol_bp.source->adapterData)
1518-
protocol_bp.source = std::nullopt;
1519-
1520-
llvm::json::Object body;
1521-
body.try_emplace("breakpoint", protocol_bp);
1522-
body.try_emplace("reason", "changed");
1523-
1524-
llvm::json::Object bp_event = CreateEventObject("breakpoint");
1525-
bp_event.try_emplace("body", std::move(body));
1526-
1527-
SendJSON(llvm::json::Value(std::move(bp_event)));
1528-
}
1529-
}
1393+
if (!listener.WaitForEvent(UINT32_MAX, event))
1394+
continue;
15301395

1531-
} else if (lldb::SBThread::EventIsThreadEvent(event)) {
1532-
HandleThreadEvent(event);
1533-
} else if (event_mask & lldb::eBroadcastBitError ||
1534-
event_mask & lldb::eBroadcastBitWarning) {
1535-
lldb::SBStructuredData data =
1536-
lldb::SBDebugger::GetDiagnosticFromEvent(event);
1537-
if (!data.IsValid())
1538-
continue;
1539-
std::string type = GetStringValue(data.GetValueForKey("type"));
1540-
std::string message = GetStringValue(data.GetValueForKey("message"));
1541-
SendOutput(OutputType::Important,
1542-
llvm::formatv("{0}: {1}", type, message).str());
1543-
} else if (event.BroadcasterMatchesRef(broadcaster)) {
1544-
if (event_mask & eBroadcastBitStopEventThread) {
1545-
done = true;
1546-
}
1396+
const uint32_t event_mask = event.GetType();
1397+
if (lldb::SBProcess::EventIsProcessEvent(event)) {
1398+
HandleProcessEvent(event, /*&process_exited=*/done);
1399+
} else if (lldb::SBTarget::EventIsTargetEvent(event)) {
1400+
HandleTargetEvent(event);
1401+
} else if (lldb::SBBreakpoint::EventIsBreakpointEvent(event)) {
1402+
HandleBreakpointEvent(event);
1403+
} else if (lldb::SBThread::EventIsThreadEvent(event)) {
1404+
HandleThreadEvent(event);
1405+
} else if (event_mask & lldb::eBroadcastBitError ||
1406+
event_mask & lldb::eBroadcastBitWarning) {
1407+
HandleDiagnosticEvent(event);
1408+
} else if (event.BroadcasterMatchesRef(broadcaster)) {
1409+
if (event_mask & eBroadcastBitStopEventThread) {
1410+
done = true;
1411+
}
1412+
}
1413+
}
1414+
}
1415+
1416+
void DAP::HandleProcessEvent(const lldb::SBEvent &event, bool &process_exited) {
1417+
lldb::SBProcess process = lldb::SBProcess::GetProcessFromEvent(event);
1418+
const uint32_t event_mask = event.GetType();
1419+
if (event_mask & lldb::SBProcess::eBroadcastBitStateChanged) {
1420+
auto state = lldb::SBProcess::GetStateFromEvent(event);
1421+
switch (state) {
1422+
case lldb::eStateConnected:
1423+
case lldb::eStateDetached:
1424+
case lldb::eStateInvalid:
1425+
case lldb::eStateUnloaded:
1426+
break;
1427+
case lldb::eStateAttaching:
1428+
case lldb::eStateCrashed:
1429+
case lldb::eStateLaunching:
1430+
case lldb::eStateStopped:
1431+
case lldb::eStateSuspended:
1432+
// Only report a stopped event if the process was not
1433+
// automatically restarted.
1434+
if (!lldb::SBProcess::GetRestartedFromEvent(event)) {
1435+
SendStdOutStdErr(*this, process);
1436+
if (llvm::Error err = SendThreadStoppedEvent(*this))
1437+
DAP_LOG_ERROR(log, std::move(err),
1438+
"({1}) reporting thread stopped: {0}", m_client_name);
1439+
}
1440+
break;
1441+
case lldb::eStateRunning:
1442+
case lldb::eStateStepping:
1443+
WillContinue();
1444+
SendContinuedEvent(*this);
1445+
break;
1446+
case lldb::eStateExited:
1447+
lldb::SBStream stream;
1448+
process.GetStatus(stream);
1449+
SendOutput(OutputType::Console, stream.GetData());
1450+
1451+
// When restarting, we can get an "exited" event for the process we
1452+
// just killed with the old PID, or even with no PID. In that case
1453+
// we don't have to terminate the session.
1454+
if (process.GetProcessID() == LLDB_INVALID_PROCESS_ID ||
1455+
process.GetProcessID() == restarting_process_id) {
1456+
restarting_process_id = LLDB_INVALID_PROCESS_ID;
1457+
} else {
1458+
// Run any exit LLDB commands the user specified in the
1459+
// launch.json
1460+
RunExitCommands();
1461+
SendProcessExitedEvent(*this, process);
1462+
SendTerminatedEvent();
1463+
process_exited = true;
1464+
}
1465+
break;
1466+
}
1467+
} else if ((event_mask & lldb::SBProcess::eBroadcastBitSTDOUT) ||
1468+
(event_mask & lldb::SBProcess::eBroadcastBitSTDERR)) {
1469+
SendStdOutStdErr(*this, process);
1470+
}
1471+
}
1472+
1473+
void DAP::HandleTargetEvent(const lldb::SBEvent &event) {
1474+
const uint32_t event_mask = event.GetType();
1475+
if (event_mask & lldb::SBTarget::eBroadcastBitModulesLoaded ||
1476+
event_mask & lldb::SBTarget::eBroadcastBitModulesUnloaded ||
1477+
event_mask & lldb::SBTarget::eBroadcastBitSymbolsLoaded ||
1478+
event_mask & lldb::SBTarget::eBroadcastBitSymbolsChanged) {
1479+
const uint32_t num_modules = lldb::SBTarget::GetNumModulesFromEvent(event);
1480+
const bool remove_module =
1481+
event_mask & lldb::SBTarget::eBroadcastBitModulesUnloaded;
1482+
1483+
// NOTE: Both mutexes must be acquired to prevent deadlock when
1484+
// handling `modules_request`, which also requires both locks.
1485+
lldb::SBMutex api_mutex = GetAPIMutex();
1486+
const std::scoped_lock<lldb::SBMutex, std::mutex> guard(api_mutex,
1487+
modules_mutex);
1488+
for (uint32_t i = 0; i < num_modules; ++i) {
1489+
lldb::SBModule module =
1490+
lldb::SBTarget::GetModuleAtIndexFromEvent(i, event);
1491+
1492+
std::optional<protocol::Module> p_module =
1493+
CreateModule(target, module, remove_module);
1494+
if (!p_module)
1495+
continue;
1496+
1497+
const llvm::StringRef module_id = p_module->id;
1498+
1499+
const bool module_exists = modules.contains(module_id);
1500+
if (remove_module && module_exists) {
1501+
modules.erase(module_id);
1502+
Send(protocol::Event{"module",
1503+
ModuleEventBody{std::move(p_module).value(),
1504+
ModuleEventBody::eReasonRemoved}});
1505+
} else if (module_exists) {
1506+
Send(protocol::Event{"module",
1507+
ModuleEventBody{std::move(p_module).value(),
1508+
ModuleEventBody::eReasonChanged}});
1509+
} else if (!remove_module) {
1510+
modules.insert(module_id);
1511+
Send(protocol::Event{"module",
1512+
ModuleEventBody{std::move(p_module).value(),
1513+
ModuleEventBody::eReasonNew}});
15471514
}
15481515
}
15491516
}
15501517
}
15511518

1519+
void DAP::HandleBreakpointEvent(const lldb::SBEvent &event) {
1520+
const uint32_t event_mask = event.GetType();
1521+
if (!(event_mask & lldb::SBTarget::eBroadcastBitBreakpointChanged))
1522+
return;
1523+
1524+
auto event_type = lldb::SBBreakpoint::GetBreakpointEventTypeFromEvent(event);
1525+
auto bp =
1526+
Breakpoint(*this, lldb::SBBreakpoint::GetBreakpointFromEvent(event));
1527+
// If the breakpoint was set through DAP, it will have the
1528+
// BreakpointBase::kDAPBreakpointLabel. Regardless of whether
1529+
// locations were added, removed, or resolved, the breakpoint isn't
1530+
// going away and the reason is always "changed".
1531+
if ((event_type & lldb::eBreakpointEventTypeLocationsAdded ||
1532+
event_type & lldb::eBreakpointEventTypeLocationsRemoved ||
1533+
event_type & lldb::eBreakpointEventTypeLocationsResolved) &&
1534+
bp.MatchesName(BreakpointBase::kDAPBreakpointLabel)) {
1535+
// As the DAP client already knows the path of this breakpoint, we
1536+
// don't need to send it back as part of the "changed" event. This
1537+
// avoids sending paths that should be source mapped. Note that
1538+
// CreateBreakpoint doesn't apply source mapping and certain
1539+
// implementation ignore the source part of this event anyway.
1540+
protocol::Breakpoint protocol_bp = bp.ToProtocolBreakpoint();
1541+
1542+
// "source" is not needed here, unless we add adapter data to be
1543+
// saved by the client.
1544+
if (protocol_bp.source && !protocol_bp.source->adapterData)
1545+
protocol_bp.source = std::nullopt;
1546+
1547+
llvm::json::Object body;
1548+
body.try_emplace("breakpoint", protocol_bp);
1549+
body.try_emplace("reason", "changed");
1550+
1551+
llvm::json::Object bp_event = CreateEventObject("breakpoint");
1552+
bp_event.try_emplace("body", std::move(body));
1553+
1554+
SendJSON(llvm::json::Value(std::move(bp_event)));
1555+
}
1556+
}
1557+
15521558
void DAP::HandleThreadEvent(const lldb::SBEvent &event) {
1553-
uint32_t event_type = event.GetType();
1559+
const uint32_t event_type = event.GetType();
15541560

15551561
if (event_type & lldb::SBThread::eBroadcastBitStackChanged) {
15561562
const lldb::SBThread evt_thread = lldb::SBThread::GetThreadFromEvent(event);
@@ -1559,6 +1565,18 @@ void DAP::HandleThreadEvent(const lldb::SBEvent &event) {
15591565
}
15601566
}
15611567

1568+
void DAP::HandleDiagnosticEvent(const lldb::SBEvent &event) {
1569+
const lldb::SBStructuredData data =
1570+
lldb::SBDebugger::GetDiagnosticFromEvent(event);
1571+
if (!data.IsValid())
1572+
return;
1573+
1574+
std::string type = GetStringValue(data.GetValueForKey("type"));
1575+
std::string message = GetStringValue(data.GetValueForKey("message"));
1576+
SendOutput(OutputType::Important,
1577+
llvm::formatv("{0}: {1}", type, message).str());
1578+
}
1579+
15621580
std::vector<protocol::Breakpoint> DAP::SetSourceBreakpoints(
15631581
const protocol::Source &source,
15641582
const std::optional<std::vector<protocol::SourceBreakpoint>> &breakpoints) {

lldb/tools/lldb-dap/DAP.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,11 @@ struct DAP final : public DAPTransport::MessageHandler {
454454
/// Event threads.
455455
/// @{
456456
void EventThread();
457+
void HandleProcessEvent(const lldb::SBEvent &event, bool &process_exited);
458+
void HandleTargetEvent(const lldb::SBEvent &event);
459+
void HandleBreakpointEvent(const lldb::SBEvent &event);
457460
void HandleThreadEvent(const lldb::SBEvent &event);
461+
void HandleDiagnosticEvent(const lldb::SBEvent &event);
458462
void ProgressEventThread();
459463

460464
std::thread event_thread;

0 commit comments

Comments
 (0)