|
19 | 19 | #include "lldb/API/SBStringList.h" |
20 | 20 | #include "lldb/API/SBStructuredData.h" |
21 | 21 | #include "lldb/Host/Config.h" |
22 | | - |
| 22 | +#include "lldb/Host/MainLoop.h" |
| 23 | +#include "lldb/Host/MainLoopBase.h" |
23 | 24 | #include "llvm/ADT/StringRef.h" |
24 | 25 | #include "llvm/Support/Format.h" |
25 | 26 | #include "llvm/Support/InitLLVM.h" |
|
50 | 51 |
|
51 | 52 | using namespace lldb; |
52 | 53 | using namespace llvm; |
| 54 | +using lldb_private::MainLoop; |
| 55 | +using lldb_private::MainLoopBase; |
53 | 56 |
|
54 | 57 | namespace { |
55 | 58 | using namespace llvm::opt; |
@@ -89,6 +92,7 @@ static struct termios g_old_stdin_termios; |
89 | 92 | static bool disable_color(const raw_ostream &OS) { return false; } |
90 | 93 |
|
91 | 94 | static Driver *g_driver = nullptr; |
| 95 | +static MainLoop g_signal_loop; |
92 | 96 |
|
93 | 97 | // In the Driver::MainLoop, we change the terminal settings. This function is |
94 | 98 | // added as an atexit handler to make sure we clean them up. |
@@ -637,48 +641,50 @@ void Driver::UpdateWindowSize() { |
637 | 641 | } |
638 | 642 |
|
639 | 643 | 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 | + }); |
642 | 648 | } |
643 | 649 |
|
644 | 650 | void sigint_handler(int signo) { |
645 | 651 | #ifdef _WIN32 // Restore handler as it is not persistent on Windows |
646 | 652 | signal(SIGINT, sigint_handler); |
647 | 653 | #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 | + } |
654 | 662 | } |
655 | | - } |
656 | 663 |
|
657 | | - _exit(signo); |
| 664 | + loop.RequestTermination(); |
| 665 | + _exit(signo); |
| 666 | + }); |
658 | 667 | } |
659 | 668 |
|
660 | 669 | #ifndef _WIN32 |
661 | 670 | 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([signo](MainLoopBase &loop) { |
| 672 | + if (g_driver != nullptr) |
| 673 | + g_driver->GetDebugger().SaveInputTerminalState(); |
| 674 | + |
| 675 | + // Remove our handler. |
| 676 | + signal(signo, SIG_DFL); |
| 677 | + |
| 678 | + // Now re-raise the signal. We will immediately suspend... |
| 679 | + raise(signo); |
| 680 | + // ... and resume after a SIGCONT. |
| 681 | + |
| 682 | + // Now undo the modifications. |
| 683 | + signal(signo, sigtstp_handler); |
| 684 | + |
| 685 | + if (g_driver != nullptr) |
| 686 | + g_driver->GetDebugger().RestoreInputTerminalState(); |
| 687 | + }); |
682 | 688 | } |
683 | 689 | #endif |
684 | 690 |
|
@@ -794,6 +800,10 @@ int main(int argc, char const *argv[]) { |
794 | 800 | signal(SIGTSTP, sigtstp_handler); |
795 | 801 | #endif |
796 | 802 |
|
| 803 | + // Run the signal handling MainLoop on a separate thread. |
| 804 | + std::thread signal_thread([] { g_signal_loop.Run(); }); |
| 805 | + signal_thread.detach(); |
| 806 | + |
797 | 807 | int exit_code = 0; |
798 | 808 | // Create a scope for driver so that the driver object will destroy itself |
799 | 809 | // before SBDebugger::Terminate() is called. |
@@ -824,5 +834,11 @@ int main(int argc, char const *argv[]) { |
824 | 834 | future.wait(); |
825 | 835 | } |
826 | 836 |
|
| 837 | + // Stop the signal handler thread. Do this after calling SBDebugger::Terminate |
| 838 | + // so that impatient users can send a SIGSTOP if they don't want to wait for |
| 839 | + // the background threads to exit cleanly. |
| 840 | + g_signal_loop.AddPendingCallback( |
| 841 | + [](MainLoopBase &loop) { loop.RequestTermination(); }); |
| 842 | + |
827 | 843 | return exit_code; |
828 | 844 | } |
0 commit comments