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