diff options
Diffstat (limited to 'tools/perf/ui/tui/setup.c')
-rw-r--r-- | tools/perf/ui/tui/setup.c | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/tools/perf/ui/tui/setup.c b/tools/perf/ui/tui/setup.c new file mode 100644 index 000000000..a3b8c397c --- /dev/null +++ b/tools/perf/ui/tui/setup.c @@ -0,0 +1,180 @@ +#include <errno.h> +#include <signal.h> +#include <stdbool.h> +#include <stdlib.h> +#include <unistd.h> +#include <linux/kernel.h> +#ifdef HAVE_BACKTRACE_SUPPORT +#include <execinfo.h> +#endif + +#include "../../util/debug.h" +#include "../../perf.h" +#include "../browser.h" +#include "../helpline.h" +#include "../ui.h" +#include "../util.h" +#include "../libslang.h" +#include "../keysyms.h" +#include "tui.h" + +static volatile int ui__need_resize; + +extern struct perf_error_ops perf_tui_eops; +extern bool tui_helpline__set; + +extern void hist_browser__init_hpp(void); + +void ui__refresh_dimensions(bool force) +{ + if (force || ui__need_resize) { + ui__need_resize = 0; + mutex_lock(&ui__lock); + SLtt_get_screen_size(); + SLsmg_reinit_smg(); + mutex_unlock(&ui__lock); + } +} + +static void ui__sigwinch(int sig __maybe_unused) +{ + ui__need_resize = 1; +} + +static void ui__setup_sigwinch(void) +{ + static bool done; + + if (done) + return; + + done = true; + pthread__unblock_sigwinch(); + signal(SIGWINCH, ui__sigwinch); +} + +int ui__getch(int delay_secs) +{ + struct timeval timeout, *ptimeout = delay_secs ? &timeout : NULL; + fd_set read_set; + int err, key; + + ui__setup_sigwinch(); + + FD_ZERO(&read_set); + FD_SET(0, &read_set); + + if (delay_secs) { + timeout.tv_sec = delay_secs; + timeout.tv_usec = 0; + } + + err = select(1, &read_set, NULL, NULL, ptimeout); + + if (err == 0) + return K_TIMER; + + if (err == -1) { + if (errno == EINTR) + return K_RESIZE; + return K_ERROR; + } + + key = SLang_getkey(); + if (key != K_ESC) + return key; + + FD_ZERO(&read_set); + FD_SET(0, &read_set); + timeout.tv_sec = 0; + timeout.tv_usec = 20; + err = select(1, &read_set, NULL, NULL, &timeout); + if (err == 0) + return K_ESC; + + SLang_ungetkey(key); + return SLkp_getkey(); +} + +#ifdef HAVE_BACKTRACE_SUPPORT +static void ui__signal_backtrace(int sig) +{ + void *stackdump[32]; + size_t size; + + ui__exit(false); + psignal(sig, "perf"); + + printf("-------- backtrace --------\n"); + size = backtrace(stackdump, ARRAY_SIZE(stackdump)); + backtrace_symbols_fd(stackdump, size, STDOUT_FILENO); + + exit(0); +} +#else +# define ui__signal_backtrace ui__signal +#endif + +static void ui__signal(int sig) +{ + ui__exit(false); + psignal(sig, "perf"); + exit(0); +} + +int ui__init(void) +{ + int err; + + SLutf8_enable(-1); + SLtt_get_terminfo(); + SLtt_get_screen_size(); + + err = SLsmg_init_smg(); + if (err < 0) + goto out; + err = SLang_init_tty(-1, 0, 0); + if (err < 0) + goto out; + + err = SLkp_init(); + if (err < 0) { + pr_err("TUI initialization failed.\n"); + goto out; + } + + SLkp_define_keysym((char *)"^(kB)", SL_KEY_UNTAB); + + signal(SIGSEGV, ui__signal_backtrace); + signal(SIGFPE, ui__signal_backtrace); + signal(SIGINT, ui__signal); + signal(SIGQUIT, ui__signal); + signal(SIGTERM, ui__signal); + + perf_error__register(&perf_tui_eops); + + ui_helpline__init(); + ui_browser__init(); + tui_progress__init(); + + hist_browser__init_hpp(); +out: + return err; +} + +void ui__exit(bool wait_for_ok) +{ + if (wait_for_ok && tui_helpline__set) + ui__question_window("Fatal Error", + ui_helpline__last_msg, + "Press any key...", 0); + + SLtt_set_cursor_visibility(1); + if (mutex_trylock(&ui__lock)) { + SLsmg_refresh(); + SLsmg_reset_smg(); + mutex_unlock(&ui__lock); + } + SLang_reset_tty(); + perf_error__unregister(&perf_tui_eops); +} |