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