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