Skip to content

Commit 6493345

Browse files
authored
[lldb] Handle signals in a separate thread in the driver (llvm#134956)
Handle signals in a separate thread in the driver so that we can stop worrying about signal safety of functions in libLLDB that may get called from a signal handler.
1 parent 9102ccd commit 6493345

File tree

2 files changed

+61
-34
lines changed

2 files changed

+61
-34
lines changed

lldb/tools/driver/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ add_lldb_tool(lldb
2222

2323
LINK_LIBS
2424
liblldb
25+
lldbHost
26+
lldbUtility
2527

2628
LINK_COMPONENTS
2729
Option

lldb/tools/driver/Driver.cpp

+59-34
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
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"
24+
#include "lldb/Utility/Status.h"
2325
#include "llvm/ADT/StringRef.h"
2426
#include "llvm/Support/Format.h"
2527
#include "llvm/Support/InitLLVM.h"
@@ -50,6 +52,9 @@
5052

5153
using namespace lldb;
5254
using namespace llvm;
55+
using lldb_private::MainLoop;
56+
using lldb_private::MainLoopBase;
57+
using lldb_private::Status;
5358

5459
namespace {
5560
using namespace llvm::opt;
@@ -636,15 +641,12 @@ void Driver::UpdateWindowSize() {
636641
}
637642
}
638643

639-
void sigwinch_handler(int signo) {
640-
if (g_driver != nullptr)
641-
g_driver->UpdateWindowSize();
642-
}
643-
644644
void sigint_handler(int signo) {
645-
#ifdef _WIN32 // Restore handler as it is not persistent on Windows
645+
#ifdef _WIN32
646+
// Restore handler as it is not persistent on Windows.
646647
signal(SIGINT, sigint_handler);
647648
#endif
649+
648650
static std::atomic_flag g_interrupt_sent = ATOMIC_FLAG_INIT;
649651
if (g_driver != nullptr) {
650652
if (!g_interrupt_sent.test_and_set()) {
@@ -657,31 +659,6 @@ void sigint_handler(int signo) {
657659
_exit(signo);
658660
}
659661

660-
#ifndef _WIN32
661-
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();
682-
}
683-
#endif
684-
685662
static void printHelp(LLDBOptTable &table, llvm::StringRef tool_name) {
686663
std::string usage_str = tool_name.str() + " [options]";
687664
table.printHelp(llvm::outs(), usage_str.c_str(), "LLDB", false);
@@ -787,11 +764,53 @@ int main(int argc, char const *argv[]) {
787764
// Setup LLDB signal handlers once the debugger has been initialized.
788765
SBDebugger::PrintDiagnosticsOnError();
789766

767+
// FIXME: Migrate the SIGINT handler to be handled by the signal loop below.
790768
signal(SIGINT, sigint_handler);
791769
#if !defined(_WIN32)
792770
signal(SIGPIPE, SIG_IGN);
793-
signal(SIGWINCH, sigwinch_handler);
794-
signal(SIGTSTP, sigtstp_handler);
771+
772+
// Handle signals in a MainLoop running on a separate thread.
773+
MainLoop signal_loop;
774+
Status signal_status;
775+
776+
auto sigwinch_handler = signal_loop.RegisterSignal(
777+
SIGWINCH,
778+
[&](MainLoopBase &) {
779+
if (g_driver)
780+
g_driver->UpdateWindowSize();
781+
},
782+
signal_status);
783+
assert(sigwinch_handler && signal_status.Success());
784+
785+
auto sigtstp_handler = signal_loop.RegisterSignal(
786+
SIGTSTP,
787+
[&](MainLoopBase &) {
788+
if (g_driver)
789+
g_driver->GetDebugger().SaveInputTerminalState();
790+
791+
struct sigaction old_action;
792+
struct sigaction new_action = {};
793+
new_action.sa_handler = SIG_DFL;
794+
sigemptyset(&new_action.sa_mask);
795+
sigaddset(&new_action.sa_mask, SIGTSTP);
796+
797+
int ret = sigaction(SIGTSTP, &new_action, &old_action);
798+
UNUSED_IF_ASSERT_DISABLED(ret);
799+
assert(ret == 0 && "sigaction failed");
800+
801+
raise(SIGTSTP);
802+
803+
ret = sigaction(SIGTSTP, &old_action, nullptr);
804+
UNUSED_IF_ASSERT_DISABLED(ret);
805+
assert(ret == 0 && "sigaction failed");
806+
807+
if (g_driver)
808+
g_driver->GetDebugger().RestoreInputTerminalState();
809+
},
810+
signal_status);
811+
assert(sigtstp_handler && signal_status.Success());
812+
813+
std::thread signal_thread([&] { signal_loop.Run(); });
795814
#endif
796815

797816
int exit_code = 0;
@@ -824,5 +843,11 @@ int main(int argc, char const *argv[]) {
824843
future.wait();
825844
}
826845

846+
#if !defined(_WIN32)
847+
signal_loop.AddPendingCallback(
848+
[](MainLoopBase &loop) { loop.RequestTermination(); });
849+
signal_thread.join();
850+
#endif
851+
827852
return exit_code;
828853
}

0 commit comments

Comments
 (0)