Skip to content

Commit dbbb973

Browse files
committed
[lldb] Handle signals in a separate thread in the driver
Handle signals in a separate thread in the driver so that we can stop worrying about signal safety of functions that might get called in libLLDB.
1 parent 36cb81c commit dbbb973

File tree

2 files changed

+52
-31
lines changed

2 files changed

+52
-31
lines changed

lldb/tools/driver/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ add_lldb_tool(lldb
2222

2323
LINK_LIBS
2424
liblldb
25+
lldbHost
2526

2627
LINK_COMPONENTS
2728
Option

lldb/tools/driver/Driver.cpp

Lines changed: 51 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
#include "lldb/API/SBStringList.h"
2020
#include "lldb/API/SBStructuredData.h"
2121
#include "lldb/Host/Config.h"
22-
22+
#include "lldb/Host/MainLoop.h"
23+
#include "lldb/Host/MainLoopBase.h"
2324
#include "llvm/ADT/StringRef.h"
2425
#include "llvm/Support/Format.h"
2526
#include "llvm/Support/InitLLVM.h"
@@ -50,6 +51,8 @@
5051

5152
using namespace lldb;
5253
using namespace llvm;
54+
using lldb_private::MainLoop;
55+
using lldb_private::MainLoopBase;
5356

5457
namespace {
5558
using namespace llvm::opt;
@@ -89,6 +92,7 @@ static struct termios g_old_stdin_termios;
8992
static bool disable_color(const raw_ostream &OS) { return false; }
9093

9194
static Driver *g_driver = nullptr;
95+
static MainLoop g_signal_loop;
9296

9397
// In the Driver::MainLoop, we change the terminal settings. This function is
9498
// added as an atexit handler to make sure we clean them up.
@@ -637,48 +641,54 @@ void Driver::UpdateWindowSize() {
637641
}
638642

639643
void sigwinch_handler(int signo) {
640-
if (g_driver != nullptr)
641-
g_driver->UpdateWindowSize();
644+
g_signal_loop.AddPendingCallback([](MainLoopBase &loop) {
645+
if (g_driver != nullptr)
646+
g_driver->UpdateWindowSize();
647+
});
642648
}
643649

644650
void sigint_handler(int signo) {
645651
#ifdef _WIN32 // Restore handler as it is not persistent on Windows
646652
signal(SIGINT, sigint_handler);
647653
#endif
648-
static std::atomic_flag g_interrupt_sent = ATOMIC_FLAG_INIT;
649-
if (g_driver != nullptr) {
650-
if (!g_interrupt_sent.test_and_set()) {
651-
g_driver->GetDebugger().DispatchInputInterrupt();
652-
g_interrupt_sent.clear();
653-
return;
654+
g_signal_loop.AddPendingCallback([signo](MainLoopBase &loop) {
655+
static std::atomic_flag g_interrupt_sent = ATOMIC_FLAG_INIT;
656+
if (g_driver != nullptr) {
657+
if (!g_interrupt_sent.test_and_set()) {
658+
g_driver->GetDebugger().DispatchInputInterrupt();
659+
g_interrupt_sent.clear();
660+
return;
661+
}
654662
}
655-
}
656663

657-
_exit(signo);
664+
loop.RequestTermination();
665+
_exit(signo);
666+
});
658667
}
659668

660669
#ifndef _WIN32
661670
static void sigtstp_handler(int signo) {
662-
if (g_driver != nullptr)
663-
g_driver->GetDebugger().SaveInputTerminalState();
664-
665-
// Unblock the signal and remove our handler.
666-
sigset_t set;
667-
sigemptyset(&set);
668-
sigaddset(&set, signo);
669-
pthread_sigmask(SIG_UNBLOCK, &set, nullptr);
670-
signal(signo, SIG_DFL);
671-
672-
// Now re-raise the signal. We will immediately suspend...
673-
raise(signo);
674-
// ... and resume after a SIGCONT.
675-
676-
// Now undo the modifications.
677-
pthread_sigmask(SIG_BLOCK, &set, nullptr);
678-
signal(signo, sigtstp_handler);
679-
680-
if (g_driver != nullptr)
681-
g_driver->GetDebugger().RestoreInputTerminalState();
671+
g_signal_loop.AddPendingCallback([](MainLoopBase &loop) {
672+
if (g_driver != nullptr)
673+
g_driver->GetDebugger().SaveInputTerminalState();
674+
});
675+
676+
g_signal_loop.AddPendingCallback([signo](MainLoopBase &loop) {
677+
// Remove our handler.
678+
signal(signo, SIG_DFL);
679+
680+
// Now re-raise the signal. We will immediately suspend...
681+
raise(signo);
682+
// ... and resume after a SIGCONT.
683+
684+
// Now undo the modifications.
685+
signal(signo, sigtstp_handler);
686+
});
687+
688+
g_signal_loop.AddPendingCallback([](MainLoopBase &loop) {
689+
if (g_driver != nullptr)
690+
g_driver->GetDebugger().RestoreInputTerminalState();
691+
});
682692
}
683693
#endif
684694

@@ -794,6 +804,10 @@ int main(int argc, char const *argv[]) {
794804
signal(SIGTSTP, sigtstp_handler);
795805
#endif
796806

807+
// Run the signal handling MainLoop on a separate thread.
808+
std::thread signal_thread([] { g_signal_loop.Run(); });
809+
signal_thread.detach();
810+
797811
int exit_code = 0;
798812
// Create a scope for driver so that the driver object will destroy itself
799813
// before SBDebugger::Terminate() is called.
@@ -824,5 +838,11 @@ int main(int argc, char const *argv[]) {
824838
future.wait();
825839
}
826840

841+
// Stop the signal handler thread. Do this after calling SBDebugger::Terminate
842+
// so that impatient users can send a SIGSTOP if they don't want to wait for
843+
// the background threads to exit cleanly.
844+
g_signal_loop.AddPendingCallback(
845+
[](MainLoopBase &loop) { loop.RequestTermination(); });
846+
827847
return exit_code;
828848
}

0 commit comments

Comments
 (0)