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