Skip to content

Commit 3943112

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 in libLLDB that may get called from a signal handler.
1 parent 36cb81c commit 3943112

File tree

2 files changed

+84
-35
lines changed

2 files changed

+84
-35
lines changed

lldb/tools/driver/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
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

Lines changed: 82 additions & 35 deletions
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,11 @@ void Driver::UpdateWindowSize() {
636641
}
637642
}
638643

639-
void sigwinch_handler(int signo) {
640-
if (g_driver != nullptr)
641-
g_driver->UpdateWindowSize();
642-
}
643-
644+
#ifdef _WIN32
644645
void sigint_handler(int signo) {
645-
#ifdef _WIN32 // Restore handler as it is not persistent on Windows
646+
// Restore handler as it is not persistent on Windows.
646647
signal(SIGINT, sigint_handler);
647-
#endif
648+
648649
static std::atomic_flag g_interrupt_sent = ATOMIC_FLAG_INIT;
649650
if (g_driver != nullptr) {
650651
if (!g_interrupt_sent.test_and_set()) {
@@ -656,30 +657,6 @@ void sigint_handler(int signo) {
656657

657658
_exit(signo);
658659
}
659-
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-
}
683660
#endif
684661

685662
static void printHelp(LLDBOptTable &table, llvm::StringRef tool_name) {
@@ -787,11 +764,75 @@ int main(int argc, char const *argv[]) {
787764
// Setup LLDB signal handlers once the debugger has been initialized.
788765
SBDebugger::PrintDiagnosticsOnError();
789766

767+
#if defined(_WIN32)
768+
// FIXME: Support signals in MainLoopWindows and handle SIGINT in the signal
769+
// loop below.
790770
signal(SIGINT, sigint_handler);
791-
#if !defined(_WIN32)
771+
#else
792772
signal(SIGPIPE, SIG_IGN);
793-
signal(SIGWINCH, sigwinch_handler);
794-
signal(SIGTSTP, sigtstp_handler);
773+
774+
// Handle signals in a MainLoop running on a separate thread.
775+
MainLoop signal_loop;
776+
Status signal_status;
777+
778+
auto sigint_handler = signal_loop.RegisterSignal(
779+
SIGINT,
780+
[&](MainLoopBase &loop) {
781+
static std::atomic_flag g_interrupt_sent = ATOMIC_FLAG_INIT;
782+
if (g_driver) {
783+
if (!g_interrupt_sent.test_and_set()) {
784+
g_driver->GetDebugger().DispatchInputInterrupt();
785+
g_interrupt_sent.clear();
786+
return;
787+
}
788+
}
789+
loop.RequestTermination();
790+
_exit(SIGINT);
791+
},
792+
signal_status);
793+
assert(sigint_handler && signal_status.Success());
794+
795+
auto sigwinch_handler = signal_loop.RegisterSignal(
796+
SIGWINCH,
797+
[&](MainLoopBase &) {
798+
if (g_driver)
799+
g_driver->UpdateWindowSize();
800+
},
801+
signal_status);
802+
assert(sigwinch_handler && signal_status.Success());
803+
804+
auto sigtstp_handler = signal_loop.RegisterSignal(
805+
SIGTSTP,
806+
[&](MainLoopBase &) {
807+
if (g_driver)
808+
g_driver->GetDebugger().SaveInputTerminalState();
809+
810+
struct sigaction old_action;
811+
struct sigaction new_action;
812+
813+
memset(&new_action, 0, sizeof(new_action));
814+
new_action.sa_handler = SIG_DFL;
815+
new_action.sa_flags = SA_SIGINFO;
816+
sigemptyset(&new_action.sa_mask);
817+
sigaddset(&new_action.sa_mask, SIGTSTP);
818+
819+
int ret = sigaction(SIGTSTP, &new_action, &old_action);
820+
UNUSED_IF_ASSERT_DISABLED(ret);
821+
assert(ret == 0 && "sigaction failed");
822+
823+
raise(SIGTSTP);
824+
825+
ret = sigaction(SIGTSTP, &old_action, nullptr);
826+
UNUSED_IF_ASSERT_DISABLED(ret);
827+
assert(ret == 0 && "sigaction failed");
828+
829+
if (g_driver)
830+
g_driver->GetDebugger().RestoreInputTerminalState();
831+
},
832+
signal_status);
833+
assert(sigtstp_handler && signal_status.Success());
834+
835+
std::thread signal_thread([&] { signal_loop.Run(); });
795836
#endif
796837

797838
int exit_code = 0;
@@ -824,5 +865,11 @@ int main(int argc, char const *argv[]) {
824865
future.wait();
825866
}
826867

868+
#if !defined(_WIN32)
869+
signal_loop.AddPendingCallback(
870+
[](MainLoopBase &loop) { loop.RequestTermination(); });
871+
signal_thread.join();
872+
#endif
873+
827874
return exit_code;
828875
}

0 commit comments

Comments
 (0)