|
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