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