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