202 lines · c
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_SUPPORT9#include <execinfo.h>10#endif11 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 22static volatile int ui__need_resize;23 24extern struct perf_error_ops perf_tui_eops;25extern bool tui_helpline__set;26 27extern void hist_browser__init_hpp(void);28 29void 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 40static void ui__sigwinch(int sig __maybe_unused)41{42 ui__need_resize = 1;43}44 45static 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 57int 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_SUPPORT101static 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#else116# define ui__signal_backtrace ui__signal117#endif118 119static void ui__signal(int sig)120{121 ui__exit(false);122 psignal(sig, "perf");123 exit(0);124}125 126static 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 143int 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();182out:183 return err;184}185 186void 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