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