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"
5052
5153using namespace lldb ;
5254using namespace llvm ;
55+ using lldb_private::MainLoop;
56+ using lldb_private::MainLoopBase;
57+ using lldb_private::Status;
5358
5459namespace {
5560using 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
644645void 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
685662static 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