xref: /kernel/linux/linux-6.6/tools/perf/ui/tui/setup.c (revision 62306a36)
162306a36Sopenharmony_ci#include <errno.h>
262306a36Sopenharmony_ci#include <signal.h>
362306a36Sopenharmony_ci#include <stdbool.h>
462306a36Sopenharmony_ci#include <stdlib.h>
562306a36Sopenharmony_ci#include <unistd.h>
662306a36Sopenharmony_ci#include <linux/kernel.h>
762306a36Sopenharmony_ci#ifdef HAVE_BACKTRACE_SUPPORT
862306a36Sopenharmony_ci#include <execinfo.h>
962306a36Sopenharmony_ci#endif
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include "../../util/debug.h"
1262306a36Sopenharmony_ci#include "../browser.h"
1362306a36Sopenharmony_ci#include "../helpline.h"
1462306a36Sopenharmony_ci#include "../ui.h"
1562306a36Sopenharmony_ci#include "../util.h"
1662306a36Sopenharmony_ci#include "../libslang.h"
1762306a36Sopenharmony_ci#include "../keysyms.h"
1862306a36Sopenharmony_ci#include "tui.h"
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistatic volatile int ui__need_resize;
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ciextern struct perf_error_ops perf_tui_eops;
2362306a36Sopenharmony_ciextern bool tui_helpline__set;
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ciextern void hist_browser__init_hpp(void);
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_civoid ui__refresh_dimensions(bool force)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	if (force || ui__need_resize) {
3062306a36Sopenharmony_ci		ui__need_resize = 0;
3162306a36Sopenharmony_ci		mutex_lock(&ui__lock);
3262306a36Sopenharmony_ci		SLtt_get_screen_size();
3362306a36Sopenharmony_ci		SLsmg_reinit_smg();
3462306a36Sopenharmony_ci		mutex_unlock(&ui__lock);
3562306a36Sopenharmony_ci	}
3662306a36Sopenharmony_ci}
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistatic void ui__sigwinch(int sig __maybe_unused)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	ui__need_resize = 1;
4162306a36Sopenharmony_ci}
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistatic void ui__setup_sigwinch(void)
4462306a36Sopenharmony_ci{
4562306a36Sopenharmony_ci	static bool done;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	if (done)
4862306a36Sopenharmony_ci		return;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	done = true;
5162306a36Sopenharmony_ci	pthread__unblock_sigwinch();
5262306a36Sopenharmony_ci	signal(SIGWINCH, ui__sigwinch);
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ciint ui__getch(int delay_secs)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	struct timeval timeout, *ptimeout = delay_secs ? &timeout : NULL;
5862306a36Sopenharmony_ci	fd_set read_set;
5962306a36Sopenharmony_ci	int err, key;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	ui__setup_sigwinch();
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	FD_ZERO(&read_set);
6462306a36Sopenharmony_ci	FD_SET(0, &read_set);
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	if (delay_secs) {
6762306a36Sopenharmony_ci		timeout.tv_sec = delay_secs;
6862306a36Sopenharmony_ci		timeout.tv_usec = 0;
6962306a36Sopenharmony_ci	}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci        err = select(1, &read_set, NULL, NULL, ptimeout);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	if (err == 0)
7462306a36Sopenharmony_ci		return K_TIMER;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	if (err == -1) {
7762306a36Sopenharmony_ci		if (errno == EINTR)
7862306a36Sopenharmony_ci			return K_RESIZE;
7962306a36Sopenharmony_ci		return K_ERROR;
8062306a36Sopenharmony_ci	}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	key = SLang_getkey();
8362306a36Sopenharmony_ci	if (key != K_ESC)
8462306a36Sopenharmony_ci		return key;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	FD_ZERO(&read_set);
8762306a36Sopenharmony_ci	FD_SET(0, &read_set);
8862306a36Sopenharmony_ci	timeout.tv_sec = 0;
8962306a36Sopenharmony_ci	timeout.tv_usec = 20;
9062306a36Sopenharmony_ci        err = select(1, &read_set, NULL, NULL, &timeout);
9162306a36Sopenharmony_ci	if (err == 0)
9262306a36Sopenharmony_ci		return K_ESC;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	SLang_ungetkey(key);
9562306a36Sopenharmony_ci	return SLkp_getkey();
9662306a36Sopenharmony_ci}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci#ifdef HAVE_BACKTRACE_SUPPORT
9962306a36Sopenharmony_cistatic void ui__signal_backtrace(int sig)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	void *stackdump[32];
10262306a36Sopenharmony_ci	size_t size;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	ui__exit(false);
10562306a36Sopenharmony_ci	psignal(sig, "perf");
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	printf("-------- backtrace --------\n");
10862306a36Sopenharmony_ci	size = backtrace(stackdump, ARRAY_SIZE(stackdump));
10962306a36Sopenharmony_ci	backtrace_symbols_fd(stackdump, size, STDOUT_FILENO);
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	exit(0);
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci#else
11462306a36Sopenharmony_ci# define ui__signal_backtrace  ui__signal
11562306a36Sopenharmony_ci#endif
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_cistatic void ui__signal(int sig)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	ui__exit(false);
12062306a36Sopenharmony_ci	psignal(sig, "perf");
12162306a36Sopenharmony_ci	exit(0);
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ciint ui__init(void)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	int err;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	SLutf8_enable(-1);
12962306a36Sopenharmony_ci	SLtt_get_terminfo();
13062306a36Sopenharmony_ci	SLtt_get_screen_size();
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	err = SLsmg_init_smg();
13362306a36Sopenharmony_ci	if (err < 0)
13462306a36Sopenharmony_ci		goto out;
13562306a36Sopenharmony_ci	err = SLang_init_tty(-1, 0, 0);
13662306a36Sopenharmony_ci	if (err < 0)
13762306a36Sopenharmony_ci		goto out;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	err = SLkp_init();
14062306a36Sopenharmony_ci	if (err < 0) {
14162306a36Sopenharmony_ci		pr_err("TUI initialization failed.\n");
14262306a36Sopenharmony_ci		goto out;
14362306a36Sopenharmony_ci	}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	SLkp_define_keysym("^(kB)", SL_KEY_UNTAB);
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	signal(SIGSEGV, ui__signal_backtrace);
14862306a36Sopenharmony_ci	signal(SIGFPE, ui__signal_backtrace);
14962306a36Sopenharmony_ci	signal(SIGINT, ui__signal);
15062306a36Sopenharmony_ci	signal(SIGQUIT, ui__signal);
15162306a36Sopenharmony_ci	signal(SIGTERM, ui__signal);
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	perf_error__register(&perf_tui_eops);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	ui_helpline__init();
15662306a36Sopenharmony_ci	ui_browser__init();
15762306a36Sopenharmony_ci	tui_progress__init();
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	hist_browser__init_hpp();
16062306a36Sopenharmony_ciout:
16162306a36Sopenharmony_ci	return err;
16262306a36Sopenharmony_ci}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_civoid ui__exit(bool wait_for_ok)
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci	if (wait_for_ok && tui_helpline__set)
16762306a36Sopenharmony_ci		ui__question_window("Fatal Error",
16862306a36Sopenharmony_ci				    ui_helpline__last_msg,
16962306a36Sopenharmony_ci				    "Press any key...", 0);
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	SLtt_set_cursor_visibility(1);
17262306a36Sopenharmony_ci	if (mutex_trylock(&ui__lock)) {
17362306a36Sopenharmony_ci		SLsmg_refresh();
17462306a36Sopenharmony_ci		SLsmg_reset_smg();
17562306a36Sopenharmony_ci		mutex_unlock(&ui__lock);
17662306a36Sopenharmony_ci	}
17762306a36Sopenharmony_ci	SLang_reset_tty();
17862306a36Sopenharmony_ci	perf_error__unregister(&perf_tui_eops);
17962306a36Sopenharmony_ci}
180