0001 #include <errno.h>
0002 #include <signal.h>
0003 #include <stdbool.h>
0004 #include <stdlib.h>
0005 #include <unistd.h>
0006 #include <linux/kernel.h>
0007 #ifdef HAVE_BACKTRACE_SUPPORT
0008 #include <execinfo.h>
0009 #endif
0010
0011 #include "../../util/debug.h"
0012 #include "../../perf.h"
0013 #include "../browser.h"
0014 #include "../helpline.h"
0015 #include "../ui.h"
0016 #include "../util.h"
0017 #include "../libslang.h"
0018 #include "../keysyms.h"
0019 #include "tui.h"
0020
0021 static volatile int ui__need_resize;
0022
0023 extern struct perf_error_ops perf_tui_eops;
0024 extern bool tui_helpline__set;
0025
0026 extern void hist_browser__init_hpp(void);
0027
0028 void ui__refresh_dimensions(bool force)
0029 {
0030 if (force || ui__need_resize) {
0031 ui__need_resize = 0;
0032 pthread_mutex_lock(&ui__lock);
0033 SLtt_get_screen_size();
0034 SLsmg_reinit_smg();
0035 pthread_mutex_unlock(&ui__lock);
0036 }
0037 }
0038
0039 static void ui__sigwinch(int sig __maybe_unused)
0040 {
0041 ui__need_resize = 1;
0042 }
0043
0044 static void ui__setup_sigwinch(void)
0045 {
0046 static bool done;
0047
0048 if (done)
0049 return;
0050
0051 done = true;
0052 pthread__unblock_sigwinch();
0053 signal(SIGWINCH, ui__sigwinch);
0054 }
0055
0056 int ui__getch(int delay_secs)
0057 {
0058 struct timeval timeout, *ptimeout = delay_secs ? &timeout : NULL;
0059 fd_set read_set;
0060 int err, key;
0061
0062 ui__setup_sigwinch();
0063
0064 FD_ZERO(&read_set);
0065 FD_SET(0, &read_set);
0066
0067 if (delay_secs) {
0068 timeout.tv_sec = delay_secs;
0069 timeout.tv_usec = 0;
0070 }
0071
0072 err = select(1, &read_set, NULL, NULL, ptimeout);
0073
0074 if (err == 0)
0075 return K_TIMER;
0076
0077 if (err == -1) {
0078 if (errno == EINTR)
0079 return K_RESIZE;
0080 return K_ERROR;
0081 }
0082
0083 key = SLang_getkey();
0084 if (key != K_ESC)
0085 return key;
0086
0087 FD_ZERO(&read_set);
0088 FD_SET(0, &read_set);
0089 timeout.tv_sec = 0;
0090 timeout.tv_usec = 20;
0091 err = select(1, &read_set, NULL, NULL, &timeout);
0092 if (err == 0)
0093 return K_ESC;
0094
0095 SLang_ungetkey(key);
0096 return SLkp_getkey();
0097 }
0098
0099 #ifdef HAVE_BACKTRACE_SUPPORT
0100 static void ui__signal_backtrace(int sig)
0101 {
0102 void *stackdump[32];
0103 size_t size;
0104
0105 ui__exit(false);
0106 psignal(sig, "perf");
0107
0108 printf("-------- backtrace --------\n");
0109 size = backtrace(stackdump, ARRAY_SIZE(stackdump));
0110 backtrace_symbols_fd(stackdump, size, STDOUT_FILENO);
0111
0112 exit(0);
0113 }
0114 #else
0115 # define ui__signal_backtrace ui__signal
0116 #endif
0117
0118 static void ui__signal(int sig)
0119 {
0120 ui__exit(false);
0121 psignal(sig, "perf");
0122 exit(0);
0123 }
0124
0125 int ui__init(void)
0126 {
0127 int err;
0128
0129 SLutf8_enable(-1);
0130 SLtt_get_terminfo();
0131 SLtt_get_screen_size();
0132
0133 err = SLsmg_init_smg();
0134 if (err < 0)
0135 goto out;
0136 err = SLang_init_tty(-1, 0, 0);
0137 if (err < 0)
0138 goto out;
0139
0140 err = SLkp_init();
0141 if (err < 0) {
0142 pr_err("TUI initialization failed.\n");
0143 goto out;
0144 }
0145
0146 SLkp_define_keysym((char *)"^(kB)", SL_KEY_UNTAB);
0147
0148 signal(SIGSEGV, ui__signal_backtrace);
0149 signal(SIGFPE, ui__signal_backtrace);
0150 signal(SIGINT, ui__signal);
0151 signal(SIGQUIT, ui__signal);
0152 signal(SIGTERM, ui__signal);
0153
0154 perf_error__register(&perf_tui_eops);
0155
0156 ui_helpline__init();
0157 ui_browser__init();
0158 tui_progress__init();
0159
0160 hist_browser__init_hpp();
0161 out:
0162 return err;
0163 }
0164
0165 void ui__exit(bool wait_for_ok)
0166 {
0167 if (wait_for_ok && tui_helpline__set)
0168 ui__question_window("Fatal Error",
0169 ui_helpline__last_msg,
0170 "Press any key...", 0);
0171
0172 SLtt_set_cursor_visibility(1);
0173 if (!pthread_mutex_trylock(&ui__lock)) {
0174 SLsmg_refresh();
0175 SLsmg_reset_smg();
0176 pthread_mutex_unlock(&ui__lock);
0177 }
0178 SLang_reset_tty();
0179 perf_error__unregister(&perf_tui_eops);
0180 }