1 // SPDX-License-Identifier: GPL-2.0 2 #include <errno.h> 3 #include <signal.h> 4 #include <stdbool.h> 5 #include <linux/kernel.h> 6 #ifdef HAVE_BACKTRACE_SUPPORT 7 #include <execinfo.h> 8 #endif 9 10 #include "../../util/cache.h" 11 #include "../../util/debug.h" 12 #include "../../util/util.h" 13 #include "../browser.h" 14 #include "../helpline.h" 15 #include "../ui.h" 16 #include "../util.h" 17 #include "../libslang.h" 18 #include "../keysyms.h" 19 #include "tui.h" 20 21 static volatile int ui__need_resize; 22 23 extern struct perf_error_ops perf_tui_eops; 24 extern bool tui_helpline__set; 25 26 extern void hist_browser__init_hpp(void); 27 28 void ui__refresh_dimensions(bool force) 29 { 30 if (force || ui__need_resize) { 31 ui__need_resize = 0; 32 pthread_mutex_lock(&ui__lock); 33 SLtt_get_screen_size(); 34 SLsmg_reinit_smg(); 35 pthread_mutex_unlock(&ui__lock); 36 } 37 } 38 39 static void ui__sigwinch(int sig __maybe_unused) 40 { 41 ui__need_resize = 1; 42 } 43 44 static void ui__setup_sigwinch(void) 45 { 46 static bool done; 47 48 if (done) 49 return; 50 51 done = true; 52 pthread__unblock_sigwinch(); 53 signal(SIGWINCH, ui__sigwinch); 54 } 55 56 int ui__getch(int delay_secs) 57 { 58 struct timeval timeout, *ptimeout = delay_secs ? &timeout : NULL; 59 fd_set read_set; 60 int err, key; 61 62 ui__setup_sigwinch(); 63 64 FD_ZERO(&read_set); 65 FD_SET(0, &read_set); 66 67 if (delay_secs) { 68 timeout.tv_sec = delay_secs; 69 timeout.tv_usec = 0; 70 } 71 72 err = select(1, &read_set, NULL, NULL, ptimeout); 73 74 if (err == 0) 75 return K_TIMER; 76 77 if (err == -1) { 78 if (errno == EINTR) 79 return K_RESIZE; 80 return K_ERROR; 81 } 82 83 key = SLang_getkey(); 84 if (key != K_ESC) 85 return key; 86 87 FD_ZERO(&read_set); 88 FD_SET(0, &read_set); 89 timeout.tv_sec = 0; 90 timeout.tv_usec = 20; 91 err = select(1, &read_set, NULL, NULL, &timeout); 92 if (err == 0) 93 return K_ESC; 94 95 SLang_ungetkey(key); 96 return SLkp_getkey(); 97 } 98 99 #ifdef HAVE_BACKTRACE_SUPPORT 100 static void ui__signal_backtrace(int sig) 101 { 102 void *stackdump[32]; 103 size_t size; 104 105 ui__exit(false); 106 psignal(sig, "perf"); 107 108 printf("-------- backtrace --------\n"); 109 size = backtrace(stackdump, ARRAY_SIZE(stackdump)); 110 backtrace_symbols_fd(stackdump, size, STDOUT_FILENO); 111 112 exit(0); 113 } 114 #else 115 # define ui__signal_backtrace ui__signal 116 #endif 117 118 static void ui__signal(int sig) 119 { 120 ui__exit(false); 121 psignal(sig, "perf"); 122 exit(0); 123 } 124 125 int ui__init(void) 126 { 127 int err; 128 129 SLutf8_enable(-1); 130 SLtt_get_terminfo(); 131 SLtt_get_screen_size(); 132 133 err = SLsmg_init_smg(); 134 if (err < 0) 135 goto out; 136 err = SLang_init_tty(-1, 0, 0); 137 if (err < 0) 138 goto out; 139 140 err = SLkp_init(); 141 if (err < 0) { 142 pr_err("TUI initialization failed.\n"); 143 goto out; 144 } 145 146 SLkp_define_keysym((char *)"^(kB)", SL_KEY_UNTAB); 147 148 signal(SIGSEGV, ui__signal_backtrace); 149 signal(SIGFPE, ui__signal_backtrace); 150 signal(SIGINT, ui__signal); 151 signal(SIGQUIT, ui__signal); 152 signal(SIGTERM, ui__signal); 153 154 perf_error__register(&perf_tui_eops); 155 156 ui_helpline__init(); 157 ui_browser__init(); 158 tui_progress__init(); 159 160 hist_browser__init_hpp(); 161 out: 162 return err; 163 } 164 165 void ui__exit(bool wait_for_ok) 166 { 167 if (wait_for_ok && tui_helpline__set) 168 ui__question_window("Fatal Error", 169 ui_helpline__last_msg, 170 "Press any key...", 0); 171 172 SLtt_set_cursor_visibility(1); 173 SLsmg_refresh(); 174 SLsmg_reset_smg(); 175 SLang_reset_tty(); 176 177 perf_error__unregister(&perf_tui_eops); 178 } 179