162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2017, 2018, 2019, 2021 BMW Car IT GmbH
462306a36Sopenharmony_ci * Author: Viktor Rosendahl (viktor.rosendahl@bmw.de)
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#define _GNU_SOURCE
862306a36Sopenharmony_ci#define _POSIX_C_SOURCE 200809L
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <ctype.h>
1162306a36Sopenharmony_ci#include <stdbool.h>
1262306a36Sopenharmony_ci#include <stdio.h>
1362306a36Sopenharmony_ci#include <stdlib.h>
1462306a36Sopenharmony_ci#include <string.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include <err.h>
1762306a36Sopenharmony_ci#include <errno.h>
1862306a36Sopenharmony_ci#include <fcntl.h>
1962306a36Sopenharmony_ci#include <getopt.h>
2062306a36Sopenharmony_ci#include <sched.h>
2162306a36Sopenharmony_ci#include <linux/unistd.h>
2262306a36Sopenharmony_ci#include <signal.h>
2362306a36Sopenharmony_ci#include <sys/inotify.h>
2462306a36Sopenharmony_ci#include <unistd.h>
2562306a36Sopenharmony_ci#include <pthread.h>
2662306a36Sopenharmony_ci#include <tracefs.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic const char *prg_name;
2962306a36Sopenharmony_cistatic const char *prg_unknown = "unknown program name";
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic int fd_stdout;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_cistatic int sched_policy;
3462306a36Sopenharmony_cistatic bool sched_policy_set;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic int sched_pri;
3762306a36Sopenharmony_cistatic bool sched_pri_set;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistatic bool trace_enable = true;
4062306a36Sopenharmony_cistatic bool setup_ftrace = true;
4162306a36Sopenharmony_cistatic bool use_random_sleep;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#define TRACE_OPTS				\
4462306a36Sopenharmony_ci	C(FUNC_TR, "function-trace"),		\
4562306a36Sopenharmony_ci	C(DISP_GR, "display-graph"),		\
4662306a36Sopenharmony_ci	C(NR,       NULL)
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci#undef C
4962306a36Sopenharmony_ci#define C(a, b) OPTIDX_##a
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cienum traceopt {
5262306a36Sopenharmony_ci	TRACE_OPTS
5362306a36Sopenharmony_ci};
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci#undef C
5662306a36Sopenharmony_ci#define C(a, b)  b
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistatic const char *const optstr[] = {
5962306a36Sopenharmony_ci	TRACE_OPTS
6062306a36Sopenharmony_ci};
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cienum errhandling {
6362306a36Sopenharmony_ci	ERR_EXIT = 0,
6462306a36Sopenharmony_ci	ERR_WARN,
6562306a36Sopenharmony_ci	ERR_CLEANUP,
6662306a36Sopenharmony_ci};
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic bool use_options[OPTIDX_NR];
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic char inotify_buffer[655360];
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci#define likely(x)      __builtin_expect(!!(x), 1)
7362306a36Sopenharmony_ci#define unlikely(x)    __builtin_expect(!!(x), 0)
7462306a36Sopenharmony_ci#define bool2str(x)    (x ? "true":"false")
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci#define DEFAULT_NR_PRINTER_THREADS (3)
7762306a36Sopenharmony_cistatic unsigned int nr_threads = DEFAULT_NR_PRINTER_THREADS;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci#define DEFAULT_TABLE_SIZE (2)
8062306a36Sopenharmony_cistatic unsigned int table_startsize = DEFAULT_TABLE_SIZE;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistatic int verbosity;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci#define verbose_sizechange() (verbosity >= 1)
8562306a36Sopenharmony_ci#define verbose_lostevent()  (verbosity >= 2)
8662306a36Sopenharmony_ci#define verbose_ftrace()     (verbosity >= 1)
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci#define was_changed(ORIG, CUR) (strcmp(ORIG, CUR) != 0)
8962306a36Sopenharmony_ci#define needs_change(CUR, WANTED) (strcmp(CUR, WANTED) != 0)
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistatic const char *debug_tracefile;
9262306a36Sopenharmony_cistatic const char *debug_tracefile_dflt;
9362306a36Sopenharmony_cistatic const char *debug_maxlat;
9462306a36Sopenharmony_cistatic const char *debug_maxlat_dflt;
9562306a36Sopenharmony_cistatic const char * const DEBUG_NOFILE = "[file not found]";
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic const char * const TR_MAXLAT  = "tracing_max_latency";
9862306a36Sopenharmony_cistatic const char * const TR_THRESH  = "tracing_thresh";
9962306a36Sopenharmony_cistatic const char * const TR_CURRENT = "current_tracer";
10062306a36Sopenharmony_cistatic const char * const TR_OPTIONS = "trace_options";
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic const char * const NOP_TRACER = "nop";
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_cistatic const char * const OPT_NO_PREFIX = "no";
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci#define DFLT_THRESHOLD_US "0"
10762306a36Sopenharmony_cistatic const char *threshold = DFLT_THRESHOLD_US;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci#define DEV_URANDOM     "/dev/urandom"
11062306a36Sopenharmony_ci#define RT_DEFAULT_PRI (99)
11162306a36Sopenharmony_ci#define DEFAULT_PRI    (0)
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci#define USEC_PER_MSEC (1000L)
11462306a36Sopenharmony_ci#define NSEC_PER_USEC (1000L)
11562306a36Sopenharmony_ci#define NSEC_PER_MSEC (USEC_PER_MSEC * NSEC_PER_USEC)
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci#define MSEC_PER_SEC (1000L)
11862306a36Sopenharmony_ci#define USEC_PER_SEC (USEC_PER_MSEC * MSEC_PER_SEC)
11962306a36Sopenharmony_ci#define NSEC_PER_SEC (NSEC_PER_MSEC * MSEC_PER_SEC)
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci#define SLEEP_TIME_MS_DEFAULT (1000L)
12262306a36Sopenharmony_ci#define TRY_PRINTMUTEX_MS (1000)
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistatic long sleep_time = (USEC_PER_MSEC * SLEEP_TIME_MS_DEFAULT);
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cistatic const char * const queue_full_warning =
12762306a36Sopenharmony_ci"Could not queue trace for printing. It is likely that events happen faster\n"
12862306a36Sopenharmony_ci"than what they can be printed. Probably partly because of random sleeping\n";
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic const char * const no_tracer_msg =
13162306a36Sopenharmony_ci"Could not find any tracers! Running this program as root may help!\n";
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic const char * const no_latency_tr_msg =
13462306a36Sopenharmony_ci"No latency tracers are supported by your kernel!\n";
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistruct policy {
13762306a36Sopenharmony_ci	const char *name;
13862306a36Sopenharmony_ci	int policy;
13962306a36Sopenharmony_ci	int default_pri;
14062306a36Sopenharmony_ci};
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic const struct policy policies[] = {
14362306a36Sopenharmony_ci	{ "other", SCHED_OTHER, DEFAULT_PRI    },
14462306a36Sopenharmony_ci	{ "batch", SCHED_BATCH, DEFAULT_PRI    },
14562306a36Sopenharmony_ci	{ "idle",  SCHED_IDLE,  DEFAULT_PRI    },
14662306a36Sopenharmony_ci	{ "rr",    SCHED_RR,    RT_DEFAULT_PRI },
14762306a36Sopenharmony_ci	{ "fifo",  SCHED_FIFO,  RT_DEFAULT_PRI },
14862306a36Sopenharmony_ci	{ NULL,    0,           DEFAULT_PRI    }
14962306a36Sopenharmony_ci};
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci/*
15262306a36Sopenharmony_ci * The default tracer will be the first on this list that is supported by the
15362306a36Sopenharmony_ci * currently running Linux kernel.
15462306a36Sopenharmony_ci */
15562306a36Sopenharmony_cistatic const char * const relevant_tracers[] = {
15662306a36Sopenharmony_ci	"preemptirqsoff",
15762306a36Sopenharmony_ci	"preemptoff",
15862306a36Sopenharmony_ci	"irqsoff",
15962306a36Sopenharmony_ci	"wakeup",
16062306a36Sopenharmony_ci	"wakeup_rt",
16162306a36Sopenharmony_ci	"wakeup_dl",
16262306a36Sopenharmony_ci	NULL
16362306a36Sopenharmony_ci};
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci/* This is the list of tracers for which random sleep makes sense */
16662306a36Sopenharmony_cistatic const char * const random_tracers[] = {
16762306a36Sopenharmony_ci	"preemptirqsoff",
16862306a36Sopenharmony_ci	"preemptoff",
16962306a36Sopenharmony_ci	"irqsoff",
17062306a36Sopenharmony_ci	NULL
17162306a36Sopenharmony_ci};
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_cistatic const char *current_tracer;
17462306a36Sopenharmony_cistatic bool force_tracer;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistruct ftrace_state {
17762306a36Sopenharmony_ci	char *tracer;
17862306a36Sopenharmony_ci	char *thresh;
17962306a36Sopenharmony_ci	bool opt[OPTIDX_NR];
18062306a36Sopenharmony_ci	bool opt_valid[OPTIDX_NR];
18162306a36Sopenharmony_ci	pthread_mutex_t mutex;
18262306a36Sopenharmony_ci};
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cistruct entry {
18562306a36Sopenharmony_ci	int ticket;
18662306a36Sopenharmony_ci	int ticket_completed_ref;
18762306a36Sopenharmony_ci};
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cistruct print_state {
19062306a36Sopenharmony_ci	int ticket_counter;
19162306a36Sopenharmony_ci	int ticket_completed;
19262306a36Sopenharmony_ci	pthread_mutex_t mutex;
19362306a36Sopenharmony_ci	pthread_cond_t cond;
19462306a36Sopenharmony_ci	int cnt;
19562306a36Sopenharmony_ci	pthread_mutex_t cnt_mutex;
19662306a36Sopenharmony_ci};
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_cistruct short_msg {
19962306a36Sopenharmony_ci	char buf[160];
20062306a36Sopenharmony_ci	int len;
20162306a36Sopenharmony_ci};
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_cistatic struct print_state printstate;
20462306a36Sopenharmony_cistatic struct ftrace_state save_state;
20562306a36Sopenharmony_civolatile sig_atomic_t signal_flag;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci#define PROB_TABLE_MAX_SIZE (1000)
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ciint probabilities[PROB_TABLE_MAX_SIZE];
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_cistruct sleep_table {
21262306a36Sopenharmony_ci	int *table;
21362306a36Sopenharmony_ci	int size;
21462306a36Sopenharmony_ci	pthread_mutex_t mutex;
21562306a36Sopenharmony_ci};
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cistatic struct sleep_table sleeptable;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci#define QUEUE_SIZE (10)
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_cistruct queue {
22262306a36Sopenharmony_ci	struct entry entries[QUEUE_SIZE];
22362306a36Sopenharmony_ci	int next_prod_idx;
22462306a36Sopenharmony_ci	int next_cons_idx;
22562306a36Sopenharmony_ci	pthread_mutex_t mutex;
22662306a36Sopenharmony_ci	pthread_cond_t cond;
22762306a36Sopenharmony_ci};
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci#define MAX_THREADS (40)
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_cistruct queue printqueue;
23262306a36Sopenharmony_cipthread_t printthread[MAX_THREADS];
23362306a36Sopenharmony_cipthread_mutex_t print_mtx;
23462306a36Sopenharmony_ci#define PRINT_BUFFER_SIZE (16 * 1024 * 1024)
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_cistatic void cleanup_exit(int status);
23762306a36Sopenharmony_cistatic int set_trace_opt(const char *opt, bool value);
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic __always_inline void *malloc_or_die(size_t size)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	void *ptr = malloc(size);
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	if (unlikely(ptr == NULL)) {
24462306a36Sopenharmony_ci		warn("malloc() failed");
24562306a36Sopenharmony_ci		cleanup_exit(EXIT_FAILURE);
24662306a36Sopenharmony_ci	}
24762306a36Sopenharmony_ci	return ptr;
24862306a36Sopenharmony_ci}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_cistatic __always_inline void *malloc_or_die_nocleanup(size_t size)
25162306a36Sopenharmony_ci{
25262306a36Sopenharmony_ci	void *ptr = malloc(size);
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	if (unlikely(ptr == NULL))
25562306a36Sopenharmony_ci		err(0, "malloc() failed");
25662306a36Sopenharmony_ci	return ptr;
25762306a36Sopenharmony_ci}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_cistatic __always_inline void write_or_die(int fd, const char *buf, size_t count)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci	ssize_t r;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	do {
26462306a36Sopenharmony_ci		r = write(fd, buf, count);
26562306a36Sopenharmony_ci		if (unlikely(r < 0)) {
26662306a36Sopenharmony_ci			if (errno == EINTR)
26762306a36Sopenharmony_ci				continue;
26862306a36Sopenharmony_ci			warn("write() failed");
26962306a36Sopenharmony_ci			cleanup_exit(EXIT_FAILURE);
27062306a36Sopenharmony_ci		}
27162306a36Sopenharmony_ci		count -= r;
27262306a36Sopenharmony_ci		buf += r;
27362306a36Sopenharmony_ci	} while (count > 0);
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cistatic __always_inline void clock_gettime_or_die(clockid_t clk_id,
27762306a36Sopenharmony_ci						 struct timespec *tp)
27862306a36Sopenharmony_ci{
27962306a36Sopenharmony_ci	int r = clock_gettime(clk_id, tp);
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	if (unlikely(r != 0))
28262306a36Sopenharmony_ci		err(EXIT_FAILURE, "clock_gettime() failed");
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_cistatic __always_inline void sigemptyset_or_die(sigset_t *s)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	if (unlikely(sigemptyset(s) != 0)) {
28862306a36Sopenharmony_ci		warn("sigemptyset() failed");
28962306a36Sopenharmony_ci		cleanup_exit(EXIT_FAILURE);
29062306a36Sopenharmony_ci	}
29162306a36Sopenharmony_ci}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_cistatic __always_inline void sigaddset_or_die(sigset_t *s, int signum)
29462306a36Sopenharmony_ci{
29562306a36Sopenharmony_ci	if (unlikely(sigaddset(s, signum) != 0)) {
29662306a36Sopenharmony_ci		warn("sigemptyset() failed");
29762306a36Sopenharmony_ci		cleanup_exit(EXIT_FAILURE);
29862306a36Sopenharmony_ci	}
29962306a36Sopenharmony_ci}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_cistatic __always_inline void sigaction_or_die(int signum,
30262306a36Sopenharmony_ci					     const struct sigaction *act,
30362306a36Sopenharmony_ci					     struct sigaction *oldact)
30462306a36Sopenharmony_ci{
30562306a36Sopenharmony_ci	if (unlikely(sigaction(signum, act, oldact) != 0)) {
30662306a36Sopenharmony_ci		warn("sigaction() failed");
30762306a36Sopenharmony_ci		cleanup_exit(EXIT_FAILURE);
30862306a36Sopenharmony_ci	}
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_cistatic void open_stdout(void)
31262306a36Sopenharmony_ci{
31362306a36Sopenharmony_ci	if (setvbuf(stdout, NULL, _IONBF, 0) != 0)
31462306a36Sopenharmony_ci		err(EXIT_FAILURE, "setvbuf() failed");
31562306a36Sopenharmony_ci	fd_stdout = fileno(stdout);
31662306a36Sopenharmony_ci	if (fd_stdout < 0)
31762306a36Sopenharmony_ci		err(EXIT_FAILURE, "fileno() failed");
31862306a36Sopenharmony_ci}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci/*
32162306a36Sopenharmony_ci * It's not worth it to call cleanup_exit() from mutex functions because
32262306a36Sopenharmony_ci * cleanup_exit() uses mutexes.
32362306a36Sopenharmony_ci */
32462306a36Sopenharmony_cistatic __always_inline void mutex_lock(pthread_mutex_t *mtx)
32562306a36Sopenharmony_ci{
32662306a36Sopenharmony_ci	errno = pthread_mutex_lock(mtx);
32762306a36Sopenharmony_ci	if (unlikely(errno))
32862306a36Sopenharmony_ci		err(EXIT_FAILURE, "pthread_mutex_lock() failed");
32962306a36Sopenharmony_ci}
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_cistatic __always_inline void mutex_unlock(pthread_mutex_t *mtx)
33362306a36Sopenharmony_ci{
33462306a36Sopenharmony_ci	errno = pthread_mutex_unlock(mtx);
33562306a36Sopenharmony_ci	if (unlikely(errno))
33662306a36Sopenharmony_ci		err(EXIT_FAILURE, "pthread_mutex_unlock() failed");
33762306a36Sopenharmony_ci}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_cistatic __always_inline void cond_signal(pthread_cond_t *cond)
34062306a36Sopenharmony_ci{
34162306a36Sopenharmony_ci	errno = pthread_cond_signal(cond);
34262306a36Sopenharmony_ci	if (unlikely(errno))
34362306a36Sopenharmony_ci		err(EXIT_FAILURE, "pthread_cond_signal() failed");
34462306a36Sopenharmony_ci}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_cistatic __always_inline void cond_wait(pthread_cond_t *restrict cond,
34762306a36Sopenharmony_ci				      pthread_mutex_t *restrict mutex)
34862306a36Sopenharmony_ci{
34962306a36Sopenharmony_ci	errno = pthread_cond_wait(cond, mutex);
35062306a36Sopenharmony_ci	if (unlikely(errno))
35162306a36Sopenharmony_ci		err(EXIT_FAILURE, "pthread_cond_wait() failed");
35262306a36Sopenharmony_ci}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_cistatic __always_inline void cond_broadcast(pthread_cond_t *cond)
35562306a36Sopenharmony_ci{
35662306a36Sopenharmony_ci	errno = pthread_cond_broadcast(cond);
35762306a36Sopenharmony_ci	if (unlikely(errno))
35862306a36Sopenharmony_ci		err(EXIT_FAILURE, "pthread_cond_broadcast() failed");
35962306a36Sopenharmony_ci}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_cistatic __always_inline void
36262306a36Sopenharmony_cimutex_init(pthread_mutex_t *mutex,
36362306a36Sopenharmony_ci	   const pthread_mutexattr_t *attr)
36462306a36Sopenharmony_ci{
36562306a36Sopenharmony_ci	errno = pthread_mutex_init(mutex, attr);
36662306a36Sopenharmony_ci	if (errno)
36762306a36Sopenharmony_ci		err(EXIT_FAILURE, "pthread_mutex_init() failed");
36862306a36Sopenharmony_ci}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_cistatic __always_inline void mutexattr_init(pthread_mutexattr_t *attr)
37162306a36Sopenharmony_ci{
37262306a36Sopenharmony_ci	errno = pthread_mutexattr_init(attr);
37362306a36Sopenharmony_ci	if (errno)
37462306a36Sopenharmony_ci		err(EXIT_FAILURE, "pthread_mutexattr_init() failed");
37562306a36Sopenharmony_ci}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_cistatic __always_inline void mutexattr_destroy(pthread_mutexattr_t *attr)
37862306a36Sopenharmony_ci{
37962306a36Sopenharmony_ci	errno = pthread_mutexattr_destroy(attr);
38062306a36Sopenharmony_ci	if (errno)
38162306a36Sopenharmony_ci		err(EXIT_FAILURE, "pthread_mutexattr_destroy() failed");
38262306a36Sopenharmony_ci}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_cistatic __always_inline void mutexattr_settype(pthread_mutexattr_t *attr,
38562306a36Sopenharmony_ci					      int type)
38662306a36Sopenharmony_ci{
38762306a36Sopenharmony_ci	errno = pthread_mutexattr_settype(attr, type);
38862306a36Sopenharmony_ci	if (errno)
38962306a36Sopenharmony_ci		err(EXIT_FAILURE, "pthread_mutexattr_settype() failed");
39062306a36Sopenharmony_ci}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_cistatic __always_inline void condattr_init(pthread_condattr_t *attr)
39362306a36Sopenharmony_ci{
39462306a36Sopenharmony_ci	errno = pthread_condattr_init(attr);
39562306a36Sopenharmony_ci	if (errno)
39662306a36Sopenharmony_ci		err(EXIT_FAILURE, "pthread_condattr_init() failed");
39762306a36Sopenharmony_ci}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_cistatic __always_inline void condattr_destroy(pthread_condattr_t *attr)
40062306a36Sopenharmony_ci{
40162306a36Sopenharmony_ci	errno = pthread_condattr_destroy(attr);
40262306a36Sopenharmony_ci	if (errno)
40362306a36Sopenharmony_ci		err(EXIT_FAILURE, "pthread_condattr_destroy() failed");
40462306a36Sopenharmony_ci}
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_cistatic __always_inline void condattr_setclock(pthread_condattr_t *attr,
40762306a36Sopenharmony_ci					      clockid_t clock_id)
40862306a36Sopenharmony_ci{
40962306a36Sopenharmony_ci	errno = pthread_condattr_setclock(attr, clock_id);
41062306a36Sopenharmony_ci	if (unlikely(errno))
41162306a36Sopenharmony_ci		err(EXIT_FAILURE, "pthread_condattr_setclock() failed");
41262306a36Sopenharmony_ci}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_cistatic __always_inline void cond_init(pthread_cond_t *cond,
41562306a36Sopenharmony_ci				      const pthread_condattr_t *attr)
41662306a36Sopenharmony_ci{
41762306a36Sopenharmony_ci	errno = pthread_cond_init(cond, attr);
41862306a36Sopenharmony_ci	if (errno)
41962306a36Sopenharmony_ci		err(EXIT_FAILURE, "pthread_cond_init() failed");
42062306a36Sopenharmony_ci}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_cistatic __always_inline int
42362306a36Sopenharmony_cicond_timedwait(pthread_cond_t *restrict cond,
42462306a36Sopenharmony_ci	       pthread_mutex_t *restrict mutex,
42562306a36Sopenharmony_ci	       const struct timespec *restrict abstime)
42662306a36Sopenharmony_ci{
42762306a36Sopenharmony_ci	errno = pthread_cond_timedwait(cond, mutex, abstime);
42862306a36Sopenharmony_ci	if (errno && errno != ETIMEDOUT)
42962306a36Sopenharmony_ci		err(EXIT_FAILURE, "pthread_cond_timedwait() failed");
43062306a36Sopenharmony_ci	return errno;
43162306a36Sopenharmony_ci}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_cistatic void init_printstate(void)
43462306a36Sopenharmony_ci{
43562306a36Sopenharmony_ci	pthread_condattr_t cattr;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	printstate.ticket_counter = 0;
43862306a36Sopenharmony_ci	printstate.ticket_completed = 0;
43962306a36Sopenharmony_ci	printstate.cnt = 0;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	mutex_init(&printstate.mutex, NULL);
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	condattr_init(&cattr);
44462306a36Sopenharmony_ci	condattr_setclock(&cattr, CLOCK_MONOTONIC);
44562306a36Sopenharmony_ci	cond_init(&printstate.cond, &cattr);
44662306a36Sopenharmony_ci	condattr_destroy(&cattr);
44762306a36Sopenharmony_ci}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_cistatic void init_print_mtx(void)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	pthread_mutexattr_t mattr;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	mutexattr_init(&mattr);
45462306a36Sopenharmony_ci	mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE);
45562306a36Sopenharmony_ci	mutex_init(&print_mtx, &mattr);
45662306a36Sopenharmony_ci	mutexattr_destroy(&mattr);
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci}
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_cistatic void signal_blocking(int how)
46162306a36Sopenharmony_ci{
46262306a36Sopenharmony_ci	sigset_t s;
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	sigemptyset_or_die(&s);
46562306a36Sopenharmony_ci	sigaddset_or_die(&s, SIGHUP);
46662306a36Sopenharmony_ci	sigaddset_or_die(&s, SIGTERM);
46762306a36Sopenharmony_ci	sigaddset_or_die(&s, SIGINT);
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	errno = pthread_sigmask(how, &s, NULL);
47062306a36Sopenharmony_ci	if (unlikely(errno)) {
47162306a36Sopenharmony_ci		warn("pthread_sigmask() failed");
47262306a36Sopenharmony_ci		cleanup_exit(EXIT_FAILURE);
47362306a36Sopenharmony_ci	}
47462306a36Sopenharmony_ci}
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_cistatic void signal_handler(int num)
47762306a36Sopenharmony_ci{
47862306a36Sopenharmony_ci	signal_flag = num;
47962306a36Sopenharmony_ci}
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_cistatic void setup_sig_handler(void)
48262306a36Sopenharmony_ci{
48362306a36Sopenharmony_ci	struct sigaction sa;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	memset(&sa, 0, sizeof(sa));
48662306a36Sopenharmony_ci	sa.sa_handler = signal_handler;
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	sigaction_or_die(SIGHUP, &sa, NULL);
48962306a36Sopenharmony_ci	sigaction_or_die(SIGTERM, &sa, NULL);
49062306a36Sopenharmony_ci	sigaction_or_die(SIGINT, &sa, NULL);
49162306a36Sopenharmony_ci}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_cistatic void process_signal(int signal)
49462306a36Sopenharmony_ci{
49562306a36Sopenharmony_ci	char *name;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	name = strsignal(signal);
49862306a36Sopenharmony_ci	if (name == NULL)
49962306a36Sopenharmony_ci		printf("Received signal %d\n", signal);
50062306a36Sopenharmony_ci	else
50162306a36Sopenharmony_ci		printf("Received signal %d (%s)\n", signal, name);
50262306a36Sopenharmony_ci	cleanup_exit(EXIT_SUCCESS);
50362306a36Sopenharmony_ci}
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_cistatic __always_inline void check_signals(void)
50662306a36Sopenharmony_ci{
50762306a36Sopenharmony_ci	int signal = signal_flag;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	if (unlikely(signal))
51062306a36Sopenharmony_ci		process_signal(signal);
51162306a36Sopenharmony_ci}
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_cistatic __always_inline void get_time_in_future(struct timespec *future,
51462306a36Sopenharmony_ci					       long time_us)
51562306a36Sopenharmony_ci{
51662306a36Sopenharmony_ci	long nsec;
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	clock_gettime_or_die(CLOCK_MONOTONIC, future);
51962306a36Sopenharmony_ci	future->tv_sec += time_us / USEC_PER_SEC;
52062306a36Sopenharmony_ci	nsec = future->tv_nsec + (time_us * NSEC_PER_USEC) % NSEC_PER_SEC;
52162306a36Sopenharmony_ci	if (nsec >= NSEC_PER_SEC) {
52262306a36Sopenharmony_ci		future->tv_nsec = nsec % NSEC_PER_SEC;
52362306a36Sopenharmony_ci		future->tv_sec += 1;
52462306a36Sopenharmony_ci	}
52562306a36Sopenharmony_ci}
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_cistatic __always_inline bool time_has_passed(const struct timespec *time)
52862306a36Sopenharmony_ci{
52962306a36Sopenharmony_ci	struct timespec now;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	clock_gettime_or_die(CLOCK_MONOTONIC, &now);
53262306a36Sopenharmony_ci	if (now.tv_sec > time->tv_sec)
53362306a36Sopenharmony_ci		return true;
53462306a36Sopenharmony_ci	if (now.tv_sec < time->tv_sec)
53562306a36Sopenharmony_ci		return false;
53662306a36Sopenharmony_ci	return (now.tv_nsec >= time->tv_nsec);
53762306a36Sopenharmony_ci}
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_cistatic bool mutex_trylock_limit(pthread_mutex_t *mutex, int time_ms)
54062306a36Sopenharmony_ci{
54162306a36Sopenharmony_ci	long time_us = time_ms * USEC_PER_MSEC;
54262306a36Sopenharmony_ci	struct timespec limit;
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	get_time_in_future(&limit, time_us);
54562306a36Sopenharmony_ci	do {
54662306a36Sopenharmony_ci		errno =  pthread_mutex_trylock(mutex);
54762306a36Sopenharmony_ci		if (errno && errno != EBUSY)
54862306a36Sopenharmony_ci			err(EXIT_FAILURE, "pthread_mutex_trylock() failed");
54962306a36Sopenharmony_ci	} while (errno && !time_has_passed(&limit));
55062306a36Sopenharmony_ci	return errno == 0;
55162306a36Sopenharmony_ci}
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_cistatic void restore_trace_opts(const struct ftrace_state *state,
55462306a36Sopenharmony_ci				const bool *cur)
55562306a36Sopenharmony_ci{
55662306a36Sopenharmony_ci	int i;
55762306a36Sopenharmony_ci	int r;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	for (i = 0; i < OPTIDX_NR; i++)
56062306a36Sopenharmony_ci		if (state->opt_valid[i] && state->opt[i] != cur[i]) {
56162306a36Sopenharmony_ci			r = set_trace_opt(optstr[i], state->opt[i]);
56262306a36Sopenharmony_ci			if (r < 0)
56362306a36Sopenharmony_ci				warnx("Failed to restore the %s option to %s",
56462306a36Sopenharmony_ci				      optstr[i], bool2str(state->opt[i]));
56562306a36Sopenharmony_ci			else if (verbose_ftrace())
56662306a36Sopenharmony_ci				printf("Restored the %s option in %s to %s\n",
56762306a36Sopenharmony_ci				       optstr[i], TR_OPTIONS,
56862306a36Sopenharmony_ci				       bool2str(state->opt[i]));
56962306a36Sopenharmony_ci		}
57062306a36Sopenharmony_ci}
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_cistatic char *read_file(const char *file, enum errhandling h)
57362306a36Sopenharmony_ci{
57462306a36Sopenharmony_ci	int psize;
57562306a36Sopenharmony_ci	char *r;
57662306a36Sopenharmony_ci	static const char *emsg = "Failed to read the %s file";
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	r = tracefs_instance_file_read(NULL, file, &psize);
57962306a36Sopenharmony_ci	if (!r) {
58062306a36Sopenharmony_ci		if (h) {
58162306a36Sopenharmony_ci			warn(emsg, file);
58262306a36Sopenharmony_ci			if (h == ERR_CLEANUP)
58362306a36Sopenharmony_ci				cleanup_exit(EXIT_FAILURE);
58462306a36Sopenharmony_ci		} else
58562306a36Sopenharmony_ci			errx(EXIT_FAILURE, emsg, file);
58662306a36Sopenharmony_ci	}
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	if (r && r[psize - 1] == '\n')
58962306a36Sopenharmony_ci		r[psize - 1] = '\0';
59062306a36Sopenharmony_ci	return r;
59162306a36Sopenharmony_ci}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_cistatic void restore_file(const char *file, char **saved, const char *cur)
59462306a36Sopenharmony_ci{
59562306a36Sopenharmony_ci	if (*saved && was_changed(*saved, cur)) {
59662306a36Sopenharmony_ci		if (tracefs_instance_file_write(NULL, file, *saved) < 0)
59762306a36Sopenharmony_ci			warnx("Failed to restore %s to %s!", file, *saved);
59862306a36Sopenharmony_ci		else if (verbose_ftrace())
59962306a36Sopenharmony_ci			printf("Restored %s to %s\n", file, *saved);
60062306a36Sopenharmony_ci		free(*saved);
60162306a36Sopenharmony_ci		*saved = NULL;
60262306a36Sopenharmony_ci	}
60362306a36Sopenharmony_ci}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_cistatic void restore_ftrace(void)
60662306a36Sopenharmony_ci{
60762306a36Sopenharmony_ci	mutex_lock(&save_state.mutex);
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	restore_file(TR_CURRENT, &save_state.tracer, current_tracer);
61062306a36Sopenharmony_ci	restore_file(TR_THRESH, &save_state.thresh, threshold);
61162306a36Sopenharmony_ci	restore_trace_opts(&save_state, use_options);
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	mutex_unlock(&save_state.mutex);
61462306a36Sopenharmony_ci}
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_cistatic void cleanup_exit(int status)
61762306a36Sopenharmony_ci{
61862306a36Sopenharmony_ci	char *maxlat;
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	if (!setup_ftrace)
62162306a36Sopenharmony_ci		exit(status);
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	/*
62462306a36Sopenharmony_ci	 * We try the print_mtx for 1 sec in order to avoid garbled
62562306a36Sopenharmony_ci	 * output if possible, but if it cannot be obtained we proceed anyway.
62662306a36Sopenharmony_ci	 */
62762306a36Sopenharmony_ci	mutex_trylock_limit(&print_mtx, TRY_PRINTMUTEX_MS);
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	maxlat = read_file(TR_MAXLAT, ERR_WARN);
63062306a36Sopenharmony_ci	if (maxlat) {
63162306a36Sopenharmony_ci		printf("The maximum detected latency was: %sus\n", maxlat);
63262306a36Sopenharmony_ci		free(maxlat);
63362306a36Sopenharmony_ci	}
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	restore_ftrace();
63662306a36Sopenharmony_ci	/*
63762306a36Sopenharmony_ci	 * We do not need to unlock the print_mtx here because we will exit at
63862306a36Sopenharmony_ci	 * the end of this function. Unlocking print_mtx causes problems if a
63962306a36Sopenharmony_ci	 * print thread happens to be waiting for the mutex because we have
64062306a36Sopenharmony_ci	 * just changed the ftrace settings to the original and thus the
64162306a36Sopenharmony_ci	 * print thread would output incorrect data from ftrace.
64262306a36Sopenharmony_ci	 */
64362306a36Sopenharmony_ci	exit(status);
64462306a36Sopenharmony_ci}
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_cistatic void init_save_state(void)
64762306a36Sopenharmony_ci{
64862306a36Sopenharmony_ci	pthread_mutexattr_t mattr;
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	mutexattr_init(&mattr);
65162306a36Sopenharmony_ci	mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE);
65262306a36Sopenharmony_ci	mutex_init(&save_state.mutex, &mattr);
65362306a36Sopenharmony_ci	mutexattr_destroy(&mattr);
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	save_state.tracer = NULL;
65662306a36Sopenharmony_ci	save_state.thresh = NULL;
65762306a36Sopenharmony_ci	save_state.opt_valid[OPTIDX_FUNC_TR] = false;
65862306a36Sopenharmony_ci	save_state.opt_valid[OPTIDX_DISP_GR] = false;
65962306a36Sopenharmony_ci}
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_cistatic int printstate_next_ticket(struct entry *req)
66262306a36Sopenharmony_ci{
66362306a36Sopenharmony_ci	int r;
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	r = ++(printstate.ticket_counter);
66662306a36Sopenharmony_ci	req->ticket = r;
66762306a36Sopenharmony_ci	req->ticket_completed_ref = printstate.ticket_completed;
66862306a36Sopenharmony_ci	cond_broadcast(&printstate.cond);
66962306a36Sopenharmony_ci	return r;
67062306a36Sopenharmony_ci}
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_cistatic __always_inline
67362306a36Sopenharmony_civoid printstate_mark_req_completed(const struct entry *req)
67462306a36Sopenharmony_ci{
67562306a36Sopenharmony_ci	if (req->ticket > printstate.ticket_completed)
67662306a36Sopenharmony_ci		printstate.ticket_completed = req->ticket;
67762306a36Sopenharmony_ci}
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_cistatic __always_inline
68062306a36Sopenharmony_cibool printstate_has_new_req_arrived(const struct entry *req)
68162306a36Sopenharmony_ci{
68262306a36Sopenharmony_ci	return (printstate.ticket_counter != req->ticket);
68362306a36Sopenharmony_ci}
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_cistatic __always_inline int printstate_cnt_inc(void)
68662306a36Sopenharmony_ci{
68762306a36Sopenharmony_ci	int value;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	mutex_lock(&printstate.cnt_mutex);
69062306a36Sopenharmony_ci	value = ++printstate.cnt;
69162306a36Sopenharmony_ci	mutex_unlock(&printstate.cnt_mutex);
69262306a36Sopenharmony_ci	return value;
69362306a36Sopenharmony_ci}
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_cistatic __always_inline int printstate_cnt_dec(void)
69662306a36Sopenharmony_ci{
69762306a36Sopenharmony_ci	int value;
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	mutex_lock(&printstate.cnt_mutex);
70062306a36Sopenharmony_ci	value = --printstate.cnt;
70162306a36Sopenharmony_ci	mutex_unlock(&printstate.cnt_mutex);
70262306a36Sopenharmony_ci	return value;
70362306a36Sopenharmony_ci}
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_cistatic __always_inline int printstate_cnt_read(void)
70662306a36Sopenharmony_ci{
70762306a36Sopenharmony_ci	int value;
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	mutex_lock(&printstate.cnt_mutex);
71062306a36Sopenharmony_ci	value = printstate.cnt;
71162306a36Sopenharmony_ci	mutex_unlock(&printstate.cnt_mutex);
71262306a36Sopenharmony_ci	return value;
71362306a36Sopenharmony_ci}
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_cistatic __always_inline
71662306a36Sopenharmony_cibool prev_req_won_race(const struct entry *req)
71762306a36Sopenharmony_ci{
71862306a36Sopenharmony_ci	return (printstate.ticket_completed != req->ticket_completed_ref);
71962306a36Sopenharmony_ci}
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_cistatic void sleeptable_resize(int size, bool printout, struct short_msg *msg)
72262306a36Sopenharmony_ci{
72362306a36Sopenharmony_ci	int bytes;
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	if (printout) {
72662306a36Sopenharmony_ci		msg->len = 0;
72762306a36Sopenharmony_ci		if (unlikely(size > PROB_TABLE_MAX_SIZE))
72862306a36Sopenharmony_ci			bytes = snprintf(msg->buf, sizeof(msg->buf),
72962306a36Sopenharmony_ci"Cannot increase probability table to %d (maximum size reached)\n", size);
73062306a36Sopenharmony_ci		else
73162306a36Sopenharmony_ci			bytes = snprintf(msg->buf, sizeof(msg->buf),
73262306a36Sopenharmony_ci"Increasing probability table to %d\n", size);
73362306a36Sopenharmony_ci		if (bytes < 0)
73462306a36Sopenharmony_ci			warn("snprintf() failed");
73562306a36Sopenharmony_ci		else
73662306a36Sopenharmony_ci			msg->len = bytes;
73762306a36Sopenharmony_ci	}
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	if (unlikely(size < 0)) {
74062306a36Sopenharmony_ci		/* Should never happen */
74162306a36Sopenharmony_ci		warnx("Bad program state at %s:%d", __FILE__, __LINE__);
74262306a36Sopenharmony_ci		cleanup_exit(EXIT_FAILURE);
74362306a36Sopenharmony_ci		return;
74462306a36Sopenharmony_ci	}
74562306a36Sopenharmony_ci	sleeptable.size = size;
74662306a36Sopenharmony_ci	sleeptable.table = &probabilities[PROB_TABLE_MAX_SIZE - size];
74762306a36Sopenharmony_ci}
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_cistatic void init_probabilities(void)
75062306a36Sopenharmony_ci{
75162306a36Sopenharmony_ci	int i;
75262306a36Sopenharmony_ci	int j = 1000;
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	for (i = 0; i < PROB_TABLE_MAX_SIZE; i++) {
75562306a36Sopenharmony_ci		probabilities[i] = 1000 / j;
75662306a36Sopenharmony_ci		j--;
75762306a36Sopenharmony_ci	}
75862306a36Sopenharmony_ci	mutex_init(&sleeptable.mutex, NULL);
75962306a36Sopenharmony_ci}
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_cistatic int table_get_probability(const struct entry *req,
76262306a36Sopenharmony_ci				 struct short_msg *msg)
76362306a36Sopenharmony_ci{
76462306a36Sopenharmony_ci	int diff = req->ticket - req->ticket_completed_ref;
76562306a36Sopenharmony_ci	int rval = 0;
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	msg->len = 0;
76862306a36Sopenharmony_ci	diff--;
76962306a36Sopenharmony_ci	/* Should never happen...*/
77062306a36Sopenharmony_ci	if (unlikely(diff < 0)) {
77162306a36Sopenharmony_ci		warnx("Programmer assumption error at %s:%d\n", __FILE__,
77262306a36Sopenharmony_ci		      __LINE__);
77362306a36Sopenharmony_ci		cleanup_exit(EXIT_FAILURE);
77462306a36Sopenharmony_ci	}
77562306a36Sopenharmony_ci	mutex_lock(&sleeptable.mutex);
77662306a36Sopenharmony_ci	if (diff >= (sleeptable.size - 1)) {
77762306a36Sopenharmony_ci		rval = sleeptable.table[sleeptable.size - 1];
77862306a36Sopenharmony_ci		sleeptable_resize(sleeptable.size + 1, verbose_sizechange(),
77962306a36Sopenharmony_ci				  msg);
78062306a36Sopenharmony_ci	} else {
78162306a36Sopenharmony_ci		rval = sleeptable.table[diff];
78262306a36Sopenharmony_ci	}
78362306a36Sopenharmony_ci	mutex_unlock(&sleeptable.mutex);
78462306a36Sopenharmony_ci	return rval;
78562306a36Sopenharmony_ci}
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_cistatic void init_queue(struct queue *q)
78862306a36Sopenharmony_ci{
78962306a36Sopenharmony_ci	q->next_prod_idx = 0;
79062306a36Sopenharmony_ci	q->next_cons_idx = 0;
79162306a36Sopenharmony_ci	mutex_init(&q->mutex, NULL);
79262306a36Sopenharmony_ci	errno = pthread_cond_init(&q->cond, NULL);
79362306a36Sopenharmony_ci	if (errno)
79462306a36Sopenharmony_ci		err(EXIT_FAILURE, "pthread_cond_init() failed");
79562306a36Sopenharmony_ci}
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_cistatic __always_inline int queue_len(const struct queue *q)
79862306a36Sopenharmony_ci{
79962306a36Sopenharmony_ci	if (q->next_prod_idx >= q->next_cons_idx)
80062306a36Sopenharmony_ci		return q->next_prod_idx - q->next_cons_idx;
80162306a36Sopenharmony_ci	else
80262306a36Sopenharmony_ci		return QUEUE_SIZE - q->next_cons_idx + q->next_prod_idx;
80362306a36Sopenharmony_ci}
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_cistatic __always_inline int queue_nr_free(const struct queue *q)
80662306a36Sopenharmony_ci{
80762306a36Sopenharmony_ci	int nr_free = QUEUE_SIZE - queue_len(q);
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	/*
81062306a36Sopenharmony_ci	 * If there is only one slot left we will anyway lie and claim that the
81162306a36Sopenharmony_ci	 * queue is full because adding an element will make it appear empty
81262306a36Sopenharmony_ci	 */
81362306a36Sopenharmony_ci	if (nr_free == 1)
81462306a36Sopenharmony_ci		nr_free = 0;
81562306a36Sopenharmony_ci	return nr_free;
81662306a36Sopenharmony_ci}
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_cistatic __always_inline void queue_idx_inc(int *idx)
81962306a36Sopenharmony_ci{
82062306a36Sopenharmony_ci	*idx = (*idx + 1) % QUEUE_SIZE;
82162306a36Sopenharmony_ci}
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_cistatic __always_inline void queue_push_to_back(struct queue *q,
82462306a36Sopenharmony_ci					      const struct entry *e)
82562306a36Sopenharmony_ci{
82662306a36Sopenharmony_ci	q->entries[q->next_prod_idx] = *e;
82762306a36Sopenharmony_ci	queue_idx_inc(&q->next_prod_idx);
82862306a36Sopenharmony_ci}
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_cistatic __always_inline struct entry queue_pop_from_front(struct queue *q)
83162306a36Sopenharmony_ci{
83262306a36Sopenharmony_ci	struct entry e = q->entries[q->next_cons_idx];
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	queue_idx_inc(&q->next_cons_idx);
83562306a36Sopenharmony_ci	return e;
83662306a36Sopenharmony_ci}
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_cistatic __always_inline void queue_cond_signal(struct queue *q)
83962306a36Sopenharmony_ci{
84062306a36Sopenharmony_ci	cond_signal(&q->cond);
84162306a36Sopenharmony_ci}
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_cistatic __always_inline void queue_cond_wait(struct queue *q)
84462306a36Sopenharmony_ci{
84562306a36Sopenharmony_ci	cond_wait(&q->cond, &q->mutex);
84662306a36Sopenharmony_ci}
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_cistatic __always_inline int queue_try_to_add_entry(struct queue *q,
84962306a36Sopenharmony_ci						  const struct entry *e)
85062306a36Sopenharmony_ci{
85162306a36Sopenharmony_ci	int r = 0;
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	mutex_lock(&q->mutex);
85462306a36Sopenharmony_ci	if (queue_nr_free(q) > 0) {
85562306a36Sopenharmony_ci		queue_push_to_back(q, e);
85662306a36Sopenharmony_ci		cond_signal(&q->cond);
85762306a36Sopenharmony_ci	} else
85862306a36Sopenharmony_ci		r = -1;
85962306a36Sopenharmony_ci	mutex_unlock(&q->mutex);
86062306a36Sopenharmony_ci	return r;
86162306a36Sopenharmony_ci}
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_cistatic struct entry queue_wait_for_entry(struct queue *q)
86462306a36Sopenharmony_ci{
86562306a36Sopenharmony_ci	struct entry e;
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci	mutex_lock(&q->mutex);
86862306a36Sopenharmony_ci	while (true) {
86962306a36Sopenharmony_ci		if (queue_len(&printqueue) > 0) {
87062306a36Sopenharmony_ci			e = queue_pop_from_front(q);
87162306a36Sopenharmony_ci			break;
87262306a36Sopenharmony_ci		}
87362306a36Sopenharmony_ci		queue_cond_wait(q);
87462306a36Sopenharmony_ci	}
87562306a36Sopenharmony_ci	mutex_unlock(&q->mutex);
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	return e;
87862306a36Sopenharmony_ci}
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_cistatic const struct policy *policy_from_name(const char *name)
88162306a36Sopenharmony_ci{
88262306a36Sopenharmony_ci	const struct policy *p = &policies[0];
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci	while (p->name != NULL) {
88562306a36Sopenharmony_ci		if (!strcmp(name, p->name))
88662306a36Sopenharmony_ci			return p;
88762306a36Sopenharmony_ci		p++;
88862306a36Sopenharmony_ci	}
88962306a36Sopenharmony_ci	return NULL;
89062306a36Sopenharmony_ci}
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_cistatic const char *policy_name(int policy)
89362306a36Sopenharmony_ci{
89462306a36Sopenharmony_ci	const struct policy *p = &policies[0];
89562306a36Sopenharmony_ci	static const char *rval = "unknown";
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	while (p->name != NULL) {
89862306a36Sopenharmony_ci		if (p->policy == policy)
89962306a36Sopenharmony_ci			return p->name;
90062306a36Sopenharmony_ci		p++;
90162306a36Sopenharmony_ci	}
90262306a36Sopenharmony_ci	return rval;
90362306a36Sopenharmony_ci}
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_cistatic bool is_relevant_tracer(const char *name)
90662306a36Sopenharmony_ci{
90762306a36Sopenharmony_ci	unsigned int i;
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	for (i = 0; relevant_tracers[i]; i++)
91062306a36Sopenharmony_ci		if (!strcmp(name, relevant_tracers[i]))
91162306a36Sopenharmony_ci			return true;
91262306a36Sopenharmony_ci	return false;
91362306a36Sopenharmony_ci}
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_cistatic bool random_makes_sense(const char *name)
91662306a36Sopenharmony_ci{
91762306a36Sopenharmony_ci	unsigned int i;
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	for (i = 0; random_tracers[i]; i++)
92062306a36Sopenharmony_ci		if (!strcmp(name, random_tracers[i]))
92162306a36Sopenharmony_ci			return true;
92262306a36Sopenharmony_ci	return false;
92362306a36Sopenharmony_ci}
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_cistatic void show_available(void)
92662306a36Sopenharmony_ci{
92762306a36Sopenharmony_ci	char **tracers;
92862306a36Sopenharmony_ci	int found = 0;
92962306a36Sopenharmony_ci	int i;
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	tracers = tracefs_tracers(NULL);
93262306a36Sopenharmony_ci	for (i = 0; tracers && tracers[i]; i++) {
93362306a36Sopenharmony_ci		if (is_relevant_tracer(tracers[i]))
93462306a36Sopenharmony_ci			found++;
93562306a36Sopenharmony_ci	}
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	if (!tracers) {
93862306a36Sopenharmony_ci		warnx(no_tracer_msg);
93962306a36Sopenharmony_ci		return;
94062306a36Sopenharmony_ci	}
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	if (!found) {
94362306a36Sopenharmony_ci		warnx(no_latency_tr_msg);
94462306a36Sopenharmony_ci		tracefs_list_free(tracers);
94562306a36Sopenharmony_ci		return;
94662306a36Sopenharmony_ci	}
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	printf("The following latency tracers are available on your system:\n");
94962306a36Sopenharmony_ci	for (i = 0; tracers[i]; i++) {
95062306a36Sopenharmony_ci		if (is_relevant_tracer(tracers[i]))
95162306a36Sopenharmony_ci			printf("%s\n", tracers[i]);
95262306a36Sopenharmony_ci	}
95362306a36Sopenharmony_ci	tracefs_list_free(tracers);
95462306a36Sopenharmony_ci}
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_cistatic bool tracer_valid(const char *name, bool *notracer)
95762306a36Sopenharmony_ci{
95862306a36Sopenharmony_ci	char **tracers;
95962306a36Sopenharmony_ci	int i;
96062306a36Sopenharmony_ci	bool rval = false;
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	*notracer = false;
96362306a36Sopenharmony_ci	tracers = tracefs_tracers(NULL);
96462306a36Sopenharmony_ci	if (!tracers) {
96562306a36Sopenharmony_ci		*notracer = true;
96662306a36Sopenharmony_ci		return false;
96762306a36Sopenharmony_ci	}
96862306a36Sopenharmony_ci	for (i = 0; tracers[i]; i++)
96962306a36Sopenharmony_ci		if (!strcmp(tracers[i], name)) {
97062306a36Sopenharmony_ci			rval = true;
97162306a36Sopenharmony_ci			break;
97262306a36Sopenharmony_ci		}
97362306a36Sopenharmony_ci	tracefs_list_free(tracers);
97462306a36Sopenharmony_ci	return rval;
97562306a36Sopenharmony_ci}
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_cistatic const char *find_default_tracer(void)
97862306a36Sopenharmony_ci{
97962306a36Sopenharmony_ci	int i;
98062306a36Sopenharmony_ci	bool notracer;
98162306a36Sopenharmony_ci	bool valid;
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	for (i = 0; relevant_tracers[i]; i++) {
98462306a36Sopenharmony_ci		valid = tracer_valid(relevant_tracers[i], &notracer);
98562306a36Sopenharmony_ci		if (notracer)
98662306a36Sopenharmony_ci			errx(EXIT_FAILURE, no_tracer_msg);
98762306a36Sopenharmony_ci		if (valid)
98862306a36Sopenharmony_ci			return relevant_tracers[i];
98962306a36Sopenharmony_ci	}
99062306a36Sopenharmony_ci	return NULL;
99162306a36Sopenharmony_ci}
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_cistatic bool toss_coin(struct drand48_data *buffer, unsigned int prob)
99462306a36Sopenharmony_ci{
99562306a36Sopenharmony_ci	long r;
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	if (unlikely(lrand48_r(buffer, &r))) {
99862306a36Sopenharmony_ci		warnx("lrand48_r() failed");
99962306a36Sopenharmony_ci		cleanup_exit(EXIT_FAILURE);
100062306a36Sopenharmony_ci	}
100162306a36Sopenharmony_ci	r = r % 1000L;
100262306a36Sopenharmony_ci	if (r < prob)
100362306a36Sopenharmony_ci		return true;
100462306a36Sopenharmony_ci	else
100562306a36Sopenharmony_ci		return false;
100662306a36Sopenharmony_ci}
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_cistatic long go_to_sleep(const struct entry *req)
101062306a36Sopenharmony_ci{
101162306a36Sopenharmony_ci	struct timespec future;
101262306a36Sopenharmony_ci	long delay = sleep_time;
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	get_time_in_future(&future, delay);
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci	mutex_lock(&printstate.mutex);
101762306a36Sopenharmony_ci	while (!printstate_has_new_req_arrived(req)) {
101862306a36Sopenharmony_ci		cond_timedwait(&printstate.cond, &printstate.mutex, &future);
101962306a36Sopenharmony_ci		if (time_has_passed(&future))
102062306a36Sopenharmony_ci			break;
102162306a36Sopenharmony_ci	}
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci	if (printstate_has_new_req_arrived(req))
102462306a36Sopenharmony_ci		delay = -1;
102562306a36Sopenharmony_ci	mutex_unlock(&printstate.mutex);
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	return delay;
102862306a36Sopenharmony_ci}
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_cistatic void set_priority(void)
103262306a36Sopenharmony_ci{
103362306a36Sopenharmony_ci	int r;
103462306a36Sopenharmony_ci	pid_t pid;
103562306a36Sopenharmony_ci	struct sched_param param;
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci	memset(&param, 0, sizeof(param));
103862306a36Sopenharmony_ci	param.sched_priority = sched_pri;
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci	pid = getpid();
104162306a36Sopenharmony_ci	r = sched_setscheduler(pid, sched_policy, &param);
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	if (r != 0)
104462306a36Sopenharmony_ci		err(EXIT_FAILURE, "sched_setscheduler() failed");
104562306a36Sopenharmony_ci}
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_cipid_t latency_collector_gettid(void)
104862306a36Sopenharmony_ci{
104962306a36Sopenharmony_ci	return (pid_t) syscall(__NR_gettid);
105062306a36Sopenharmony_ci}
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_cistatic void print_priority(void)
105362306a36Sopenharmony_ci{
105462306a36Sopenharmony_ci	pid_t tid;
105562306a36Sopenharmony_ci	int policy;
105662306a36Sopenharmony_ci	int r;
105762306a36Sopenharmony_ci	struct sched_param param;
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	tid = latency_collector_gettid();
106062306a36Sopenharmony_ci	r = pthread_getschedparam(pthread_self(), &policy, &param);
106162306a36Sopenharmony_ci	if (r != 0) {
106262306a36Sopenharmony_ci		warn("pthread_getschedparam() failed");
106362306a36Sopenharmony_ci		cleanup_exit(EXIT_FAILURE);
106462306a36Sopenharmony_ci	}
106562306a36Sopenharmony_ci	mutex_lock(&print_mtx);
106662306a36Sopenharmony_ci	printf("Thread %d runs with scheduling policy %s and priority %d\n",
106762306a36Sopenharmony_ci	       tid, policy_name(policy), param.sched_priority);
106862306a36Sopenharmony_ci	mutex_unlock(&print_mtx);
106962306a36Sopenharmony_ci}
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_cistatic __always_inline
107262306a36Sopenharmony_civoid __print_skipmessage(const struct short_msg *resize_msg,
107362306a36Sopenharmony_ci			 const struct timespec *timestamp, char *buffer,
107462306a36Sopenharmony_ci			 size_t bufspace, const struct entry *req, bool excuse,
107562306a36Sopenharmony_ci			 const char *str)
107662306a36Sopenharmony_ci{
107762306a36Sopenharmony_ci	ssize_t bytes = 0;
107862306a36Sopenharmony_ci	char *p = &buffer[0];
107962306a36Sopenharmony_ci	long us, sec;
108062306a36Sopenharmony_ci	int r;
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci	sec = timestamp->tv_sec;
108362306a36Sopenharmony_ci	us = timestamp->tv_nsec / 1000;
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	if (resize_msg != NULL && resize_msg->len > 0) {
108662306a36Sopenharmony_ci		strncpy(p, resize_msg->buf, resize_msg->len);
108762306a36Sopenharmony_ci		bytes += resize_msg->len;
108862306a36Sopenharmony_ci		p += resize_msg->len;
108962306a36Sopenharmony_ci		bufspace -= resize_msg->len;
109062306a36Sopenharmony_ci	}
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	if (excuse)
109362306a36Sopenharmony_ci		r = snprintf(p, bufspace,
109462306a36Sopenharmony_ci"%ld.%06ld Latency %d printout skipped due to %s\n",
109562306a36Sopenharmony_ci			     sec, us, req->ticket, str);
109662306a36Sopenharmony_ci	else
109762306a36Sopenharmony_ci		r = snprintf(p, bufspace, "%ld.%06ld Latency %d detected\n",
109862306a36Sopenharmony_ci			    sec, us, req->ticket);
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	if (r < 0)
110162306a36Sopenharmony_ci		warn("snprintf() failed");
110262306a36Sopenharmony_ci	else
110362306a36Sopenharmony_ci		bytes += r;
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	/* These prints could happen concurrently */
110662306a36Sopenharmony_ci	mutex_lock(&print_mtx);
110762306a36Sopenharmony_ci	write_or_die(fd_stdout, buffer, bytes);
110862306a36Sopenharmony_ci	mutex_unlock(&print_mtx);
110962306a36Sopenharmony_ci}
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_cistatic void print_skipmessage(const struct short_msg *resize_msg,
111262306a36Sopenharmony_ci			      const struct timespec *timestamp, char *buffer,
111362306a36Sopenharmony_ci			      size_t bufspace, const struct entry *req,
111462306a36Sopenharmony_ci			      bool excuse)
111562306a36Sopenharmony_ci{
111662306a36Sopenharmony_ci	__print_skipmessage(resize_msg, timestamp, buffer, bufspace, req,
111762306a36Sopenharmony_ci			    excuse, "random delay");
111862306a36Sopenharmony_ci}
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_cistatic void print_lostmessage(const struct timespec *timestamp, char *buffer,
112162306a36Sopenharmony_ci			      size_t bufspace, const struct entry *req,
112262306a36Sopenharmony_ci			      const char *reason)
112362306a36Sopenharmony_ci{
112462306a36Sopenharmony_ci	__print_skipmessage(NULL, timestamp, buffer, bufspace, req, true,
112562306a36Sopenharmony_ci			    reason);
112662306a36Sopenharmony_ci}
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_cistatic void print_tracefile(const struct short_msg *resize_msg,
112962306a36Sopenharmony_ci			    const struct timespec *timestamp, char *buffer,
113062306a36Sopenharmony_ci			    size_t bufspace, long slept,
113162306a36Sopenharmony_ci			    const struct entry *req)
113262306a36Sopenharmony_ci{
113362306a36Sopenharmony_ci	static const int reserve = 256;
113462306a36Sopenharmony_ci	char *p = &buffer[0];
113562306a36Sopenharmony_ci	ssize_t bytes = 0;
113662306a36Sopenharmony_ci	ssize_t bytes_tot = 0;
113762306a36Sopenharmony_ci	long us, sec;
113862306a36Sopenharmony_ci	long slept_ms;
113962306a36Sopenharmony_ci	int trace_fd;
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci	/* Save some space for the final string and final null char */
114262306a36Sopenharmony_ci	bufspace = bufspace - reserve - 1;
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci	if (resize_msg != NULL && resize_msg->len > 0) {
114562306a36Sopenharmony_ci		bytes = resize_msg->len;
114662306a36Sopenharmony_ci		strncpy(p, resize_msg->buf, bytes);
114762306a36Sopenharmony_ci		bytes_tot += bytes;
114862306a36Sopenharmony_ci		p += bytes;
114962306a36Sopenharmony_ci		bufspace -= bytes;
115062306a36Sopenharmony_ci	}
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci	trace_fd = open(debug_tracefile, O_RDONLY);
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci	if (trace_fd < 0) {
115562306a36Sopenharmony_ci		warn("open() failed on %s", debug_tracefile);
115662306a36Sopenharmony_ci		return;
115762306a36Sopenharmony_ci	}
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci	sec = timestamp->tv_sec;
116062306a36Sopenharmony_ci	us = timestamp->tv_nsec / 1000;
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci	if (slept != 0) {
116362306a36Sopenharmony_ci		slept_ms = slept / 1000;
116462306a36Sopenharmony_ci		bytes = snprintf(p, bufspace,
116562306a36Sopenharmony_ci"%ld.%06ld Latency %d randomly sleep for %ld ms before print\n",
116662306a36Sopenharmony_ci				 sec, us, req->ticket, slept_ms);
116762306a36Sopenharmony_ci	} else {
116862306a36Sopenharmony_ci		bytes = snprintf(p, bufspace,
116962306a36Sopenharmony_ci				 "%ld.%06ld Latency %d immediate print\n", sec,
117062306a36Sopenharmony_ci				 us, req->ticket);
117162306a36Sopenharmony_ci	}
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	if (bytes < 0) {
117462306a36Sopenharmony_ci		warn("snprintf() failed");
117562306a36Sopenharmony_ci		return;
117662306a36Sopenharmony_ci	}
117762306a36Sopenharmony_ci	p += bytes;
117862306a36Sopenharmony_ci	bufspace -= bytes;
117962306a36Sopenharmony_ci	bytes_tot += bytes;
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci	bytes = snprintf(p, bufspace,
118262306a36Sopenharmony_ci">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> BEGIN <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"
118362306a36Sopenharmony_ci		);
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci	if (bytes < 0) {
118662306a36Sopenharmony_ci		warn("snprintf() failed");
118762306a36Sopenharmony_ci		return;
118862306a36Sopenharmony_ci	}
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	p += bytes;
119162306a36Sopenharmony_ci	bufspace -= bytes;
119262306a36Sopenharmony_ci	bytes_tot += bytes;
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci	do {
119562306a36Sopenharmony_ci		bytes = read(trace_fd, p, bufspace);
119662306a36Sopenharmony_ci		if (bytes < 0) {
119762306a36Sopenharmony_ci			if (errno == EINTR)
119862306a36Sopenharmony_ci				continue;
119962306a36Sopenharmony_ci			warn("read() failed on %s", debug_tracefile);
120062306a36Sopenharmony_ci			if (unlikely(close(trace_fd) != 0))
120162306a36Sopenharmony_ci				warn("close() failed on %s", debug_tracefile);
120262306a36Sopenharmony_ci			return;
120362306a36Sopenharmony_ci		}
120462306a36Sopenharmony_ci		if (bytes == 0)
120562306a36Sopenharmony_ci			break;
120662306a36Sopenharmony_ci		p += bytes;
120762306a36Sopenharmony_ci		bufspace -= bytes;
120862306a36Sopenharmony_ci		bytes_tot += bytes;
120962306a36Sopenharmony_ci	} while (true);
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci	if (unlikely(close(trace_fd) != 0))
121262306a36Sopenharmony_ci		warn("close() failed on %s", debug_tracefile);
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci	printstate_cnt_dec();
121562306a36Sopenharmony_ci	/* Add the reserve space back to the budget for the final string */
121662306a36Sopenharmony_ci	bufspace += reserve;
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci	bytes = snprintf(p, bufspace,
121962306a36Sopenharmony_ci			 ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> END <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n\n");
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci	if (bytes < 0) {
122262306a36Sopenharmony_ci		warn("snprintf() failed");
122362306a36Sopenharmony_ci		return;
122462306a36Sopenharmony_ci	}
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci	bytes_tot += bytes;
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	/* These prints could happen concurrently */
122962306a36Sopenharmony_ci	mutex_lock(&print_mtx);
123062306a36Sopenharmony_ci	write_or_die(fd_stdout, buffer, bytes_tot);
123162306a36Sopenharmony_ci	mutex_unlock(&print_mtx);
123262306a36Sopenharmony_ci}
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_cistatic char *get_no_opt(const char *opt)
123562306a36Sopenharmony_ci{
123662306a36Sopenharmony_ci	char *no_opt;
123762306a36Sopenharmony_ci	int s;
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci	s = strlen(opt) + strlen(OPT_NO_PREFIX) + 1;
124062306a36Sopenharmony_ci	/* We may be called from cleanup_exit() via set_trace_opt() */
124162306a36Sopenharmony_ci	no_opt = malloc_or_die_nocleanup(s);
124262306a36Sopenharmony_ci	strcpy(no_opt, OPT_NO_PREFIX);
124362306a36Sopenharmony_ci	strcat(no_opt, opt);
124462306a36Sopenharmony_ci	return no_opt;
124562306a36Sopenharmony_ci}
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_cistatic char *find_next_optstr(const char *allopt, const char **next)
124862306a36Sopenharmony_ci{
124962306a36Sopenharmony_ci	const char *begin;
125062306a36Sopenharmony_ci	const char *end;
125162306a36Sopenharmony_ci	char *r;
125262306a36Sopenharmony_ci	int s = 0;
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci	if (allopt == NULL)
125562306a36Sopenharmony_ci		return NULL;
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci	for (begin = allopt; *begin != '\0'; begin++) {
125862306a36Sopenharmony_ci		if (isgraph(*begin))
125962306a36Sopenharmony_ci			break;
126062306a36Sopenharmony_ci	}
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci	if (*begin == '\0')
126362306a36Sopenharmony_ci		return NULL;
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci	for (end = begin; *end != '\0' && isgraph(*end); end++)
126662306a36Sopenharmony_ci		s++;
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci	r = malloc_or_die_nocleanup(s + 1);
126962306a36Sopenharmony_ci	strncpy(r, begin, s);
127062306a36Sopenharmony_ci	r[s] = '\0';
127162306a36Sopenharmony_ci	*next = begin + s;
127262306a36Sopenharmony_ci	return r;
127362306a36Sopenharmony_ci}
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_cistatic bool get_trace_opt(const char *allopt, const char *opt, bool *found)
127662306a36Sopenharmony_ci{
127762306a36Sopenharmony_ci	*found = false;
127862306a36Sopenharmony_ci	char *no_opt;
127962306a36Sopenharmony_ci	char *str;
128062306a36Sopenharmony_ci	const char *next = allopt;
128162306a36Sopenharmony_ci	bool rval = false;
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci	no_opt = get_no_opt(opt);
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci	do {
128662306a36Sopenharmony_ci		str = find_next_optstr(next, &next);
128762306a36Sopenharmony_ci		if (str == NULL)
128862306a36Sopenharmony_ci			break;
128962306a36Sopenharmony_ci		if (!strcmp(str, opt)) {
129062306a36Sopenharmony_ci			*found = true;
129162306a36Sopenharmony_ci			rval = true;
129262306a36Sopenharmony_ci			free(str);
129362306a36Sopenharmony_ci			break;
129462306a36Sopenharmony_ci		}
129562306a36Sopenharmony_ci		if (!strcmp(str, no_opt)) {
129662306a36Sopenharmony_ci			*found = true;
129762306a36Sopenharmony_ci			rval = false;
129862306a36Sopenharmony_ci			free(str);
129962306a36Sopenharmony_ci			break;
130062306a36Sopenharmony_ci		}
130162306a36Sopenharmony_ci		free(str);
130262306a36Sopenharmony_ci	} while (true);
130362306a36Sopenharmony_ci	free(no_opt);
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	return rval;
130662306a36Sopenharmony_ci}
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_cistatic int set_trace_opt(const char *opt, bool value)
130962306a36Sopenharmony_ci{
131062306a36Sopenharmony_ci	char *str;
131162306a36Sopenharmony_ci	int r;
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci	if (value)
131462306a36Sopenharmony_ci		str = strdup(opt);
131562306a36Sopenharmony_ci	else
131662306a36Sopenharmony_ci		str = get_no_opt(opt);
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci	r = tracefs_instance_file_write(NULL, TR_OPTIONS, str);
131962306a36Sopenharmony_ci	free(str);
132062306a36Sopenharmony_ci	return r;
132162306a36Sopenharmony_ci}
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_civoid save_trace_opts(struct ftrace_state *state)
132462306a36Sopenharmony_ci{
132562306a36Sopenharmony_ci	char *allopt;
132662306a36Sopenharmony_ci	int psize;
132762306a36Sopenharmony_ci	int i;
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	allopt = tracefs_instance_file_read(NULL, TR_OPTIONS, &psize);
133062306a36Sopenharmony_ci	if (!allopt)
133162306a36Sopenharmony_ci		errx(EXIT_FAILURE, "Failed to read the %s file\n", TR_OPTIONS);
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci	for (i = 0; i < OPTIDX_NR; i++)
133462306a36Sopenharmony_ci		state->opt[i] = get_trace_opt(allopt, optstr[i],
133562306a36Sopenharmony_ci					      &state->opt_valid[i]);
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci	free(allopt);
133862306a36Sopenharmony_ci}
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_cistatic void write_file(const char *file, const char *cur, const char *new,
134162306a36Sopenharmony_ci		       enum errhandling h)
134262306a36Sopenharmony_ci{
134362306a36Sopenharmony_ci	int r;
134462306a36Sopenharmony_ci	static const char *emsg = "Failed to write to the %s file!";
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci	/* Do nothing if we now that the current and new value are equal */
134762306a36Sopenharmony_ci	if (cur && !needs_change(cur, new))
134862306a36Sopenharmony_ci		return;
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci	r = tracefs_instance_file_write(NULL, file, new);
135162306a36Sopenharmony_ci	if (r < 0) {
135262306a36Sopenharmony_ci		if (h) {
135362306a36Sopenharmony_ci			warnx(emsg, file);
135462306a36Sopenharmony_ci			if (h == ERR_CLEANUP)
135562306a36Sopenharmony_ci				cleanup_exit(EXIT_FAILURE);
135662306a36Sopenharmony_ci		} else
135762306a36Sopenharmony_ci			errx(EXIT_FAILURE, emsg, file);
135862306a36Sopenharmony_ci	}
135962306a36Sopenharmony_ci	if (verbose_ftrace()) {
136062306a36Sopenharmony_ci		mutex_lock(&print_mtx);
136162306a36Sopenharmony_ci		printf("%s was set to %s\n", file, new);
136262306a36Sopenharmony_ci		mutex_unlock(&print_mtx);
136362306a36Sopenharmony_ci	}
136462306a36Sopenharmony_ci}
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_cistatic void reset_max_latency(void)
136762306a36Sopenharmony_ci{
136862306a36Sopenharmony_ci	write_file(TR_MAXLAT, NULL, "0", ERR_CLEANUP);
136962306a36Sopenharmony_ci}
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_cistatic void save_and_disable_tracer(void)
137262306a36Sopenharmony_ci{
137362306a36Sopenharmony_ci	char *orig_th;
137462306a36Sopenharmony_ci	char *tracer;
137562306a36Sopenharmony_ci	bool need_nop = false;
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci	mutex_lock(&save_state.mutex);
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	save_trace_opts(&save_state);
138062306a36Sopenharmony_ci	tracer = read_file(TR_CURRENT, ERR_EXIT);
138162306a36Sopenharmony_ci	orig_th = read_file(TR_THRESH, ERR_EXIT);
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci	if (needs_change(tracer, NOP_TRACER)) {
138462306a36Sopenharmony_ci		mutex_lock(&print_mtx);
138562306a36Sopenharmony_ci		if (force_tracer) {
138662306a36Sopenharmony_ci			printf(
138762306a36Sopenharmony_ci				"The %s tracer is already in use but proceeding anyway!\n",
138862306a36Sopenharmony_ci				tracer);
138962306a36Sopenharmony_ci		} else {
139062306a36Sopenharmony_ci			printf(
139162306a36Sopenharmony_ci				"The %s tracer is already in use, cowardly bailing out!\n"
139262306a36Sopenharmony_ci				"This could indicate that another program or instance is tracing.\n"
139362306a36Sopenharmony_ci				"Use the -F [--force] option to disregard the current tracer.\n", tracer);
139462306a36Sopenharmony_ci			exit(0);
139562306a36Sopenharmony_ci		}
139662306a36Sopenharmony_ci		mutex_unlock(&print_mtx);
139762306a36Sopenharmony_ci		need_nop = true;
139862306a36Sopenharmony_ci	}
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci	save_state.tracer =  tracer;
140162306a36Sopenharmony_ci	save_state.thresh = orig_th;
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci	if (need_nop)
140462306a36Sopenharmony_ci		write_file(TR_CURRENT, NULL, NOP_TRACER, ERR_EXIT);
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci	mutex_unlock(&save_state.mutex);
140762306a36Sopenharmony_ci}
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_civoid set_trace_opts(struct ftrace_state *state, bool *new)
141062306a36Sopenharmony_ci{
141162306a36Sopenharmony_ci	int i;
141262306a36Sopenharmony_ci	int r;
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci	/*
141562306a36Sopenharmony_ci	 * We only set options if we earlier detected that the option exists in
141662306a36Sopenharmony_ci	 * the trace_options file and that the wanted setting is different from
141762306a36Sopenharmony_ci	 * the one we saw in save_and_disable_tracer()
141862306a36Sopenharmony_ci	 */
141962306a36Sopenharmony_ci	for (i = 0; i < OPTIDX_NR; i++)
142062306a36Sopenharmony_ci		if (state->opt_valid[i] &&
142162306a36Sopenharmony_ci		    state->opt[i] != new[i]) {
142262306a36Sopenharmony_ci			r = set_trace_opt(optstr[i], new[i]);
142362306a36Sopenharmony_ci			if (r < 0) {
142462306a36Sopenharmony_ci				warnx("Failed to set the %s option to %s",
142562306a36Sopenharmony_ci				      optstr[i], bool2str(new[i]));
142662306a36Sopenharmony_ci				cleanup_exit(EXIT_FAILURE);
142762306a36Sopenharmony_ci			}
142862306a36Sopenharmony_ci			if (verbose_ftrace()) {
142962306a36Sopenharmony_ci				mutex_lock(&print_mtx);
143062306a36Sopenharmony_ci				printf("%s in %s was set to %s\n", optstr[i],
143162306a36Sopenharmony_ci				       TR_OPTIONS, bool2str(new[i]));
143262306a36Sopenharmony_ci				mutex_unlock(&print_mtx);
143362306a36Sopenharmony_ci			}
143462306a36Sopenharmony_ci		}
143562306a36Sopenharmony_ci}
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_cistatic void enable_tracer(void)
143862306a36Sopenharmony_ci{
143962306a36Sopenharmony_ci	mutex_lock(&save_state.mutex);
144062306a36Sopenharmony_ci	set_trace_opts(&save_state, use_options);
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci	write_file(TR_THRESH, save_state.thresh, threshold, ERR_CLEANUP);
144362306a36Sopenharmony_ci	write_file(TR_CURRENT, NOP_TRACER, current_tracer, ERR_CLEANUP);
144462306a36Sopenharmony_ci
144562306a36Sopenharmony_ci	mutex_unlock(&save_state.mutex);
144662306a36Sopenharmony_ci}
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_cistatic void tracing_loop(void)
144962306a36Sopenharmony_ci{
145062306a36Sopenharmony_ci	int ifd = inotify_init();
145162306a36Sopenharmony_ci	int wd;
145262306a36Sopenharmony_ci	const ssize_t bufsize = sizeof(inotify_buffer);
145362306a36Sopenharmony_ci	const ssize_t istructsize = sizeof(struct inotify_event);
145462306a36Sopenharmony_ci	char *buf = &inotify_buffer[0];
145562306a36Sopenharmony_ci	ssize_t nr_read;
145662306a36Sopenharmony_ci	char *p;
145762306a36Sopenharmony_ci	int modified;
145862306a36Sopenharmony_ci	struct inotify_event *event;
145962306a36Sopenharmony_ci	struct entry req;
146062306a36Sopenharmony_ci	char *buffer;
146162306a36Sopenharmony_ci	const size_t bufspace = PRINT_BUFFER_SIZE;
146262306a36Sopenharmony_ci	struct timespec timestamp;
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_ci	print_priority();
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci	buffer = malloc_or_die(bufspace);
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_ci	if (ifd < 0)
146962306a36Sopenharmony_ci		err(EXIT_FAILURE, "inotify_init() failed!");
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci	if (setup_ftrace) {
147362306a36Sopenharmony_ci		/*
147462306a36Sopenharmony_ci		 * We must disable the tracer before resetting the max_latency
147562306a36Sopenharmony_ci		 */
147662306a36Sopenharmony_ci		save_and_disable_tracer();
147762306a36Sopenharmony_ci		/*
147862306a36Sopenharmony_ci		 * We must reset the max_latency before the inotify_add_watch()
147962306a36Sopenharmony_ci		 * call.
148062306a36Sopenharmony_ci		 */
148162306a36Sopenharmony_ci		reset_max_latency();
148262306a36Sopenharmony_ci	}
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_ci	wd = inotify_add_watch(ifd, debug_maxlat, IN_MODIFY);
148562306a36Sopenharmony_ci	if (wd < 0)
148662306a36Sopenharmony_ci		err(EXIT_FAILURE, "inotify_add_watch() failed!");
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci	if (setup_ftrace)
148962306a36Sopenharmony_ci		enable_tracer();
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_ci	signal_blocking(SIG_UNBLOCK);
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ci	while (true) {
149462306a36Sopenharmony_ci		modified = 0;
149562306a36Sopenharmony_ci		check_signals();
149662306a36Sopenharmony_ci		nr_read = read(ifd, buf, bufsize);
149762306a36Sopenharmony_ci		check_signals();
149862306a36Sopenharmony_ci		if (nr_read < 0) {
149962306a36Sopenharmony_ci			if (errno == EINTR)
150062306a36Sopenharmony_ci				continue;
150162306a36Sopenharmony_ci			warn("read() failed on inotify fd!");
150262306a36Sopenharmony_ci			cleanup_exit(EXIT_FAILURE);
150362306a36Sopenharmony_ci		}
150462306a36Sopenharmony_ci		if (nr_read == bufsize)
150562306a36Sopenharmony_ci			warnx("inotify() buffer filled, skipping events");
150662306a36Sopenharmony_ci		if (nr_read < istructsize) {
150762306a36Sopenharmony_ci			warnx("read() returned too few bytes on inotify fd");
150862306a36Sopenharmony_ci			cleanup_exit(EXIT_FAILURE);
150962306a36Sopenharmony_ci		}
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci		for (p = buf; p < buf + nr_read;) {
151262306a36Sopenharmony_ci			event = (struct inotify_event *) p;
151362306a36Sopenharmony_ci			if ((event->mask & IN_MODIFY) != 0)
151462306a36Sopenharmony_ci				modified++;
151562306a36Sopenharmony_ci			p += istructsize + event->len;
151662306a36Sopenharmony_ci		}
151762306a36Sopenharmony_ci		while (modified > 0) {
151862306a36Sopenharmony_ci			check_signals();
151962306a36Sopenharmony_ci			mutex_lock(&printstate.mutex);
152062306a36Sopenharmony_ci			check_signals();
152162306a36Sopenharmony_ci			printstate_next_ticket(&req);
152262306a36Sopenharmony_ci			if (printstate_cnt_read() > 0) {
152362306a36Sopenharmony_ci				printstate_mark_req_completed(&req);
152462306a36Sopenharmony_ci				mutex_unlock(&printstate.mutex);
152562306a36Sopenharmony_ci				if (verbose_lostevent()) {
152662306a36Sopenharmony_ci					clock_gettime_or_die(CLOCK_MONOTONIC,
152762306a36Sopenharmony_ci							     &timestamp);
152862306a36Sopenharmony_ci					print_lostmessage(&timestamp, buffer,
152962306a36Sopenharmony_ci							  bufspace, &req,
153062306a36Sopenharmony_ci							  "inotify loop");
153162306a36Sopenharmony_ci				}
153262306a36Sopenharmony_ci				break;
153362306a36Sopenharmony_ci			}
153462306a36Sopenharmony_ci			mutex_unlock(&printstate.mutex);
153562306a36Sopenharmony_ci			if (queue_try_to_add_entry(&printqueue, &req) != 0) {
153662306a36Sopenharmony_ci				/* These prints could happen concurrently */
153762306a36Sopenharmony_ci				check_signals();
153862306a36Sopenharmony_ci				mutex_lock(&print_mtx);
153962306a36Sopenharmony_ci				check_signals();
154062306a36Sopenharmony_ci				write_or_die(fd_stdout, queue_full_warning,
154162306a36Sopenharmony_ci					     strlen(queue_full_warning));
154262306a36Sopenharmony_ci				mutex_unlock(&print_mtx);
154362306a36Sopenharmony_ci			}
154462306a36Sopenharmony_ci			modified--;
154562306a36Sopenharmony_ci		}
154662306a36Sopenharmony_ci	}
154762306a36Sopenharmony_ci}
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_cistatic void *do_printloop(void *arg)
155062306a36Sopenharmony_ci{
155162306a36Sopenharmony_ci	const size_t bufspace = PRINT_BUFFER_SIZE;
155262306a36Sopenharmony_ci	char *buffer;
155362306a36Sopenharmony_ci	long *rseed = (long *) arg;
155462306a36Sopenharmony_ci	struct drand48_data drandbuf;
155562306a36Sopenharmony_ci	long slept = 0;
155662306a36Sopenharmony_ci	struct entry req;
155762306a36Sopenharmony_ci	int prob = 0;
155862306a36Sopenharmony_ci	struct timespec timestamp;
155962306a36Sopenharmony_ci	struct short_msg resize_msg;
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ci	print_priority();
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_ci	if (srand48_r(*rseed, &drandbuf) != 0) {
156462306a36Sopenharmony_ci		warn("srand48_r() failed!\n");
156562306a36Sopenharmony_ci		cleanup_exit(EXIT_FAILURE);
156662306a36Sopenharmony_ci	}
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_ci	buffer = malloc_or_die(bufspace);
156962306a36Sopenharmony_ci
157062306a36Sopenharmony_ci	while (true) {
157162306a36Sopenharmony_ci		req = queue_wait_for_entry(&printqueue);
157262306a36Sopenharmony_ci		clock_gettime_or_die(CLOCK_MONOTONIC, &timestamp);
157362306a36Sopenharmony_ci		mutex_lock(&printstate.mutex);
157462306a36Sopenharmony_ci		if (prev_req_won_race(&req)) {
157562306a36Sopenharmony_ci			printstate_mark_req_completed(&req);
157662306a36Sopenharmony_ci			mutex_unlock(&printstate.mutex);
157762306a36Sopenharmony_ci			if (verbose_lostevent())
157862306a36Sopenharmony_ci				print_lostmessage(&timestamp, buffer, bufspace,
157962306a36Sopenharmony_ci						  &req, "print loop");
158062306a36Sopenharmony_ci			continue;
158162306a36Sopenharmony_ci		}
158262306a36Sopenharmony_ci		mutex_unlock(&printstate.mutex);
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ci		/*
158562306a36Sopenharmony_ci		 * Toss a coin to decide if we want to sleep before printing
158662306a36Sopenharmony_ci		 * out the backtrace. The reason for this is that opening
158762306a36Sopenharmony_ci		 * /sys/kernel/tracing/trace will cause a blackout of
158862306a36Sopenharmony_ci		 * hundreds of ms, where no latencies will be noted by the
158962306a36Sopenharmony_ci		 * latency tracer. Thus by randomly sleeping we try to avoid
159062306a36Sopenharmony_ci		 * missing traces systematically due to this. With this option
159162306a36Sopenharmony_ci		 * we will sometimes get the first latency, some other times
159262306a36Sopenharmony_ci		 * some of the later ones, in case of closely spaced traces.
159362306a36Sopenharmony_ci		 */
159462306a36Sopenharmony_ci		if (trace_enable && use_random_sleep) {
159562306a36Sopenharmony_ci			slept = 0;
159662306a36Sopenharmony_ci			prob = table_get_probability(&req, &resize_msg);
159762306a36Sopenharmony_ci			if (!toss_coin(&drandbuf, prob))
159862306a36Sopenharmony_ci				slept = go_to_sleep(&req);
159962306a36Sopenharmony_ci			if (slept >= 0) {
160062306a36Sopenharmony_ci				/* A print is ongoing */
160162306a36Sopenharmony_ci				printstate_cnt_inc();
160262306a36Sopenharmony_ci				/*
160362306a36Sopenharmony_ci				 * We will do the printout below so we have to
160462306a36Sopenharmony_ci				 * mark it as completed while we still have the
160562306a36Sopenharmony_ci				 * mutex.
160662306a36Sopenharmony_ci				 */
160762306a36Sopenharmony_ci				mutex_lock(&printstate.mutex);
160862306a36Sopenharmony_ci				printstate_mark_req_completed(&req);
160962306a36Sopenharmony_ci				mutex_unlock(&printstate.mutex);
161062306a36Sopenharmony_ci			}
161162306a36Sopenharmony_ci		}
161262306a36Sopenharmony_ci		if (trace_enable) {
161362306a36Sopenharmony_ci			/*
161462306a36Sopenharmony_ci			 * slept < 0  means that we detected another
161562306a36Sopenharmony_ci			 * notification in go_to_sleep() above
161662306a36Sopenharmony_ci			 */
161762306a36Sopenharmony_ci			if (slept >= 0)
161862306a36Sopenharmony_ci				/*
161962306a36Sopenharmony_ci				 * N.B. printstate_cnt_dec(); will be called
162062306a36Sopenharmony_ci				 * inside print_tracefile()
162162306a36Sopenharmony_ci				 */
162262306a36Sopenharmony_ci				print_tracefile(&resize_msg, &timestamp, buffer,
162362306a36Sopenharmony_ci						bufspace, slept, &req);
162462306a36Sopenharmony_ci			else
162562306a36Sopenharmony_ci				print_skipmessage(&resize_msg, &timestamp,
162662306a36Sopenharmony_ci						  buffer, bufspace, &req, true);
162762306a36Sopenharmony_ci		} else {
162862306a36Sopenharmony_ci			print_skipmessage(&resize_msg, &timestamp, buffer,
162962306a36Sopenharmony_ci					  bufspace, &req, false);
163062306a36Sopenharmony_ci		}
163162306a36Sopenharmony_ci	}
163262306a36Sopenharmony_ci	return NULL;
163362306a36Sopenharmony_ci}
163462306a36Sopenharmony_ci
163562306a36Sopenharmony_cistatic void start_printthread(void)
163662306a36Sopenharmony_ci{
163762306a36Sopenharmony_ci	unsigned int i;
163862306a36Sopenharmony_ci	long *seed;
163962306a36Sopenharmony_ci	int ufd;
164062306a36Sopenharmony_ci
164162306a36Sopenharmony_ci	ufd = open(DEV_URANDOM, O_RDONLY);
164262306a36Sopenharmony_ci	if (nr_threads > MAX_THREADS) {
164362306a36Sopenharmony_ci		warnx(
164462306a36Sopenharmony_ci"Number of requested print threads was %d, max number is %d\n",
164562306a36Sopenharmony_ci		      nr_threads, MAX_THREADS);
164662306a36Sopenharmony_ci		nr_threads = MAX_THREADS;
164762306a36Sopenharmony_ci	}
164862306a36Sopenharmony_ci	for (i = 0; i < nr_threads; i++) {
164962306a36Sopenharmony_ci		seed = malloc_or_die(sizeof(*seed));
165062306a36Sopenharmony_ci		if (ufd <  0 ||
165162306a36Sopenharmony_ci		    read(ufd, seed, sizeof(*seed)) != sizeof(*seed)) {
165262306a36Sopenharmony_ci			printf(
165362306a36Sopenharmony_ci"Warning! Using trivial random number seed, since %s not available\n",
165462306a36Sopenharmony_ci			DEV_URANDOM);
165562306a36Sopenharmony_ci			fflush(stdout);
165662306a36Sopenharmony_ci			*seed = i;
165762306a36Sopenharmony_ci		}
165862306a36Sopenharmony_ci		errno = pthread_create(&printthread[i], NULL, do_printloop,
165962306a36Sopenharmony_ci				       seed);
166062306a36Sopenharmony_ci		if (errno)
166162306a36Sopenharmony_ci			err(EXIT_FAILURE, "pthread_create()");
166262306a36Sopenharmony_ci	}
166362306a36Sopenharmony_ci	if (ufd > 0 && close(ufd) != 0)
166462306a36Sopenharmony_ci		warn("close() failed");
166562306a36Sopenharmony_ci}
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_cistatic void show_usage(void)
166862306a36Sopenharmony_ci{
166962306a36Sopenharmony_ci	printf(
167062306a36Sopenharmony_ci"Usage: %s [OPTION]...\n\n"
167162306a36Sopenharmony_ci"Collect closely occurring latencies from %s\n"
167262306a36Sopenharmony_ci"with any of the following tracers: preemptirqsoff, preemptoff, irqsoff, "
167362306a36Sopenharmony_ci"wakeup,\nwakeup_dl, or wakeup_rt.\n\n"
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ci"The occurrence of a latency is detected by monitoring the file\n"
167662306a36Sopenharmony_ci"%s with inotify.\n\n"
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci"The following options are supported:\n\n"
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_ci"-l, --list\t\tList the latency tracers that are supported by the\n"
168162306a36Sopenharmony_ci"\t\t\tcurrently running Linux kernel. If you don't see the\n"
168262306a36Sopenharmony_ci"\t\t\ttracer that you want, you will probably need to\n"
168362306a36Sopenharmony_ci"\t\t\tchange your kernel config and build a new kernel.\n\n"
168462306a36Sopenharmony_ci
168562306a36Sopenharmony_ci"-t, --tracer TR\t\tUse the tracer TR. The default is to use the first\n"
168662306a36Sopenharmony_ci"\t\t\ttracer that is supported by the kernel in the following\n"
168762306a36Sopenharmony_ci"\t\t\torder of precedence:\n\n"
168862306a36Sopenharmony_ci"\t\t\tpreemptirqsoff\n"
168962306a36Sopenharmony_ci"\t\t\tpreemptoff\n"
169062306a36Sopenharmony_ci"\t\t\tirqsoff\n"
169162306a36Sopenharmony_ci"\t\t\twakeup\n"
169262306a36Sopenharmony_ci"\t\t\twakeup_rt\n"
169362306a36Sopenharmony_ci"\t\t\twakeup_dl\n"
169462306a36Sopenharmony_ci"\n"
169562306a36Sopenharmony_ci"\t\t\tIf TR is not on the list above, then a warning will be\n"
169662306a36Sopenharmony_ci"\t\t\tprinted.\n\n"
169762306a36Sopenharmony_ci
169862306a36Sopenharmony_ci"-F, --force\t\tProceed even if another ftrace tracer is active. Without\n"
169962306a36Sopenharmony_ci"\t\t\tthis option, the program will refuse to start tracing if\n"
170062306a36Sopenharmony_ci"\t\t\tany other tracer than the nop tracer is active.\n\n"
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_ci"-s, --threshold TH\tConfigure ftrace to use a threshold of TH microseconds\n"
170362306a36Sopenharmony_ci"\t\t\tfor the tracer. The default is 0, which means that\n"
170462306a36Sopenharmony_ci"\t\t\ttracing_max_latency will be used. tracing_max_latency is\n"
170562306a36Sopenharmony_ci"\t\t\tset to 0 when the program is started and contains the\n"
170662306a36Sopenharmony_ci"\t\t\tmaximum of the latencies that have been encountered.\n\n"
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_ci"-f, --function\t\tEnable the function-trace option in trace_options. With\n"
170962306a36Sopenharmony_ci"\t\t\tthis option, ftrace will trace the functions that are\n"
171062306a36Sopenharmony_ci"\t\t\texecuted during a latency, without it we only get the\n"
171162306a36Sopenharmony_ci"\t\t\tbeginning, end, and backtrace.\n\n"
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_ci"-g, --graph\t\tEnable the display-graph option in trace_option. This\n"
171462306a36Sopenharmony_ci"\t\t\toption causes ftrace to show the graph of how functions\n"
171562306a36Sopenharmony_ci"\t\t\tare calling other functions.\n\n"
171662306a36Sopenharmony_ci
171762306a36Sopenharmony_ci"-c, --policy POL\tRun the program with scheduling policy POL. POL can be\n"
171862306a36Sopenharmony_ci"\t\t\tother, batch, idle, rr or fifo. The default is rr. When\n"
171962306a36Sopenharmony_ci"\t\t\tusing rr or fifo, remember that these policies may cause\n"
172062306a36Sopenharmony_ci"\t\t\tother tasks to experience latencies.\n\n"
172162306a36Sopenharmony_ci
172262306a36Sopenharmony_ci"-p, --priority PRI\tRun the program with priority PRI. The acceptable range\n"
172362306a36Sopenharmony_ci"\t\t\tof PRI depends on the scheduling policy.\n\n"
172462306a36Sopenharmony_ci
172562306a36Sopenharmony_ci"-n, --notrace\t\tIf latency is detected, do not print out the content of\n"
172662306a36Sopenharmony_ci"\t\t\tthe trace file to standard output\n\n"
172762306a36Sopenharmony_ci
172862306a36Sopenharmony_ci"-t, --threads NRTHR\tRun NRTHR threads for printing. Default is %d.\n\n"
172962306a36Sopenharmony_ci
173062306a36Sopenharmony_ci"-r, --random\t\tArbitrarily sleep a certain amount of time, default\n"
173162306a36Sopenharmony_ci"\t\t\t%ld ms, before reading the trace file. The\n"
173262306a36Sopenharmony_ci"\t\t\tprobabilities for sleep are chosen so that the\n"
173362306a36Sopenharmony_ci"\t\t\tprobability of obtaining any of a cluster of closely\n"
173462306a36Sopenharmony_ci"\t\t\toccurring latencies are equal, i.e. we will randomly\n"
173562306a36Sopenharmony_ci"\t\t\tchoose which one we collect from the trace file.\n\n"
173662306a36Sopenharmony_ci"\t\t\tThis option is probably only useful with the irqsoff,\n"
173762306a36Sopenharmony_ci"\t\t\tpreemptoff, and preemptirqsoff tracers.\n\n"
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_ci"-a, --nrlat NRLAT\tFor the purpose of arbitrary delay, assume that there\n"
174062306a36Sopenharmony_ci"\t\t\tare no more than NRLAT clustered latencies. If NRLAT\n"
174162306a36Sopenharmony_ci"\t\t\tlatencies are detected during a run, this value will\n"
174262306a36Sopenharmony_ci"\t\t\tautomatically be increased to NRLAT + 1 and then to\n"
174362306a36Sopenharmony_ci"\t\t\tNRLAT + 2 and so on. The default is %d. This option\n"
174462306a36Sopenharmony_ci"\t\t\timplies -r. We need to know this number in order to\n"
174562306a36Sopenharmony_ci"\t\t\tbe able to calculate the probabilities of sleeping.\n"
174662306a36Sopenharmony_ci"\t\t\tSpecifically, the probabilities of not sleeping, i.e. to\n"
174762306a36Sopenharmony_ci"\t\t\tdo an immediate printout will be:\n\n"
174862306a36Sopenharmony_ci"\t\t\t1/NRLAT  1/(NRLAT - 1) ... 1/3  1/2  1\n\n"
174962306a36Sopenharmony_ci"\t\t\tThe probability of sleeping will be:\n\n"
175062306a36Sopenharmony_ci"\t\t\t1 - P, where P is from the series above\n\n"
175162306a36Sopenharmony_ci"\t\t\tThis descending probability will cause us to choose\n"
175262306a36Sopenharmony_ci"\t\t\tan occurrence at random. Observe that the final\n"
175362306a36Sopenharmony_ci"\t\t\tprobability is 0, it is when we reach this probability\n"
175462306a36Sopenharmony_ci"\t\t\tthat we increase NRLAT automatically. As an example,\n"
175562306a36Sopenharmony_ci"\t\t\twith the default value of 2, the probabilities will be:\n\n"
175662306a36Sopenharmony_ci"\t\t\t1/2  0\n\n"
175762306a36Sopenharmony_ci"\t\t\tThis means, when a latency is detected we will sleep\n"
175862306a36Sopenharmony_ci"\t\t\twith 50%% probability. If we ever detect another latency\n"
175962306a36Sopenharmony_ci"\t\t\tduring the sleep period, then the probability of sleep\n"
176062306a36Sopenharmony_ci"\t\t\twill be 0%% and the table will be expanded to:\n\n"
176162306a36Sopenharmony_ci"\t\t\t1/3  1/2  0\n\n"
176262306a36Sopenharmony_ci
176362306a36Sopenharmony_ci"-v, --verbose\t\tIncrease the verbosity. If this option is given once,\n"
176462306a36Sopenharmony_ci"\t\t\tthen print a message every time that the NRLAT value\n"
176562306a36Sopenharmony_ci"\t\t\tis automatically increased. It also causes a message to\n"
176662306a36Sopenharmony_ci"\t\t\tbe printed when the ftrace settings are changed. If this\n"
176762306a36Sopenharmony_ci"\t\t\toption is given at least twice, then also print a\n"
176862306a36Sopenharmony_ci"\t\t\twarning for lost events.\n\n"
176962306a36Sopenharmony_ci
177062306a36Sopenharmony_ci"-u, --time TIME\t\tArbitrarily sleep for a specified time TIME ms before\n"
177162306a36Sopenharmony_ci"\t\t\tprinting out the trace from the trace file. The default\n"
177262306a36Sopenharmony_ci"\t\t\tis %ld ms. This option implies -r.\n\n"
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_ci"-x, --no-ftrace\t\tDo not configure ftrace. This assume that the user\n"
177562306a36Sopenharmony_ci"\t\t\tconfigures the ftrace files in sysfs such as\n"
177662306a36Sopenharmony_ci"\t\t\t/sys/kernel/tracing/current_tracer or equivalent.\n\n"
177762306a36Sopenharmony_ci
177862306a36Sopenharmony_ci"-i, --tracefile FILE\tUse FILE as trace file. The default is\n"
177962306a36Sopenharmony_ci"\t\t\t%s.\n"
178062306a36Sopenharmony_ci"\t\t\tThis options implies -x\n\n"
178162306a36Sopenharmony_ci
178262306a36Sopenharmony_ci"-m, --max-lat FILE\tUse FILE as tracing_max_latency file. The default is\n"
178362306a36Sopenharmony_ci"\t\t\t%s.\n"
178462306a36Sopenharmony_ci"\t\t\tThis options implies -x\n\n"
178562306a36Sopenharmony_ci,
178662306a36Sopenharmony_ciprg_name, debug_tracefile_dflt, debug_maxlat_dflt, DEFAULT_NR_PRINTER_THREADS,
178762306a36Sopenharmony_ciSLEEP_TIME_MS_DEFAULT, DEFAULT_TABLE_SIZE, SLEEP_TIME_MS_DEFAULT,
178862306a36Sopenharmony_cidebug_tracefile_dflt, debug_maxlat_dflt);
178962306a36Sopenharmony_ci}
179062306a36Sopenharmony_ci
179162306a36Sopenharmony_cistatic void find_tracefiles(void)
179262306a36Sopenharmony_ci{
179362306a36Sopenharmony_ci	debug_tracefile_dflt = tracefs_get_tracing_file("trace");
179462306a36Sopenharmony_ci	if (debug_tracefile_dflt == NULL) {
179562306a36Sopenharmony_ci		/* This is needed in show_usage() */
179662306a36Sopenharmony_ci		debug_tracefile_dflt = DEBUG_NOFILE;
179762306a36Sopenharmony_ci	}
179862306a36Sopenharmony_ci
179962306a36Sopenharmony_ci	debug_maxlat_dflt = tracefs_get_tracing_file("tracing_max_latency");
180062306a36Sopenharmony_ci	if (debug_maxlat_dflt == NULL) {
180162306a36Sopenharmony_ci		/* This is needed in show_usage() */
180262306a36Sopenharmony_ci		debug_maxlat_dflt = DEBUG_NOFILE;
180362306a36Sopenharmony_ci	}
180462306a36Sopenharmony_ci
180562306a36Sopenharmony_ci	debug_tracefile = debug_tracefile_dflt;
180662306a36Sopenharmony_ci	debug_maxlat = debug_maxlat_dflt;
180762306a36Sopenharmony_ci}
180862306a36Sopenharmony_ci
180962306a36Sopenharmony_cibool alldigits(const char *s)
181062306a36Sopenharmony_ci{
181162306a36Sopenharmony_ci	for (; *s != '\0'; s++)
181262306a36Sopenharmony_ci		if (!isdigit(*s))
181362306a36Sopenharmony_ci			return false;
181462306a36Sopenharmony_ci	return true;
181562306a36Sopenharmony_ci}
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_civoid check_alldigits(const char *optarg, const char *argname)
181862306a36Sopenharmony_ci{
181962306a36Sopenharmony_ci	if (!alldigits(optarg))
182062306a36Sopenharmony_ci		errx(EXIT_FAILURE,
182162306a36Sopenharmony_ci		     "The %s parameter expects a decimal argument\n", argname);
182262306a36Sopenharmony_ci}
182362306a36Sopenharmony_ci
182462306a36Sopenharmony_cistatic void scan_arguments(int argc, char *argv[])
182562306a36Sopenharmony_ci{
182662306a36Sopenharmony_ci	int c;
182762306a36Sopenharmony_ci	int i;
182862306a36Sopenharmony_ci	int option_idx = 0;
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_ci	static struct option long_options[] = {
183162306a36Sopenharmony_ci		{ "list",       no_argument,            0, 'l' },
183262306a36Sopenharmony_ci		{ "tracer",	required_argument,	0, 't' },
183362306a36Sopenharmony_ci		{ "force",      no_argument,            0, 'F' },
183462306a36Sopenharmony_ci		{ "threshold",  required_argument,      0, 's' },
183562306a36Sopenharmony_ci		{ "function",   no_argument,            0, 'f' },
183662306a36Sopenharmony_ci		{ "graph",      no_argument,            0, 'g' },
183762306a36Sopenharmony_ci		{ "policy",	required_argument,	0, 'c' },
183862306a36Sopenharmony_ci		{ "priority",	required_argument,	0, 'p' },
183962306a36Sopenharmony_ci		{ "help",	no_argument,		0, 'h' },
184062306a36Sopenharmony_ci		{ "notrace",	no_argument,		0, 'n' },
184162306a36Sopenharmony_ci		{ "random",	no_argument,		0, 'r' },
184262306a36Sopenharmony_ci		{ "nrlat",	required_argument,	0, 'a' },
184362306a36Sopenharmony_ci		{ "threads",	required_argument,	0, 'e' },
184462306a36Sopenharmony_ci		{ "time",	required_argument,	0, 'u' },
184562306a36Sopenharmony_ci		{ "verbose",	no_argument,		0, 'v' },
184662306a36Sopenharmony_ci		{ "no-ftrace",  no_argument,            0, 'x' },
184762306a36Sopenharmony_ci		{ "tracefile",	required_argument,	0, 'i' },
184862306a36Sopenharmony_ci		{ "max-lat",	required_argument,	0, 'm' },
184962306a36Sopenharmony_ci		{ 0,		0,			0,  0  }
185062306a36Sopenharmony_ci	};
185162306a36Sopenharmony_ci	const struct policy *p;
185262306a36Sopenharmony_ci	int max, min;
185362306a36Sopenharmony_ci	int value;
185462306a36Sopenharmony_ci	bool notracer, valid;
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_ci	/*
185762306a36Sopenharmony_ci	 * We must do this before parsing the arguments because show_usage()
185862306a36Sopenharmony_ci	 * needs to display these.
185962306a36Sopenharmony_ci	 */
186062306a36Sopenharmony_ci	find_tracefiles();
186162306a36Sopenharmony_ci
186262306a36Sopenharmony_ci	while (true) {
186362306a36Sopenharmony_ci		c = getopt_long(argc, argv, "lt:Fs:fgc:p:hnra:e:u:vxi:m:",
186462306a36Sopenharmony_ci				long_options, &option_idx);
186562306a36Sopenharmony_ci		if (c == -1)
186662306a36Sopenharmony_ci			break;
186762306a36Sopenharmony_ci
186862306a36Sopenharmony_ci		switch (c) {
186962306a36Sopenharmony_ci		case 'l':
187062306a36Sopenharmony_ci			show_available();
187162306a36Sopenharmony_ci			exit(0);
187262306a36Sopenharmony_ci			break;
187362306a36Sopenharmony_ci		case 't':
187462306a36Sopenharmony_ci			current_tracer = strdup(optarg);
187562306a36Sopenharmony_ci			if (!is_relevant_tracer(current_tracer)) {
187662306a36Sopenharmony_ci				warnx("%s is not a known latency tracer!\n",
187762306a36Sopenharmony_ci				      current_tracer);
187862306a36Sopenharmony_ci			}
187962306a36Sopenharmony_ci			valid = tracer_valid(current_tracer, &notracer);
188062306a36Sopenharmony_ci			if (notracer)
188162306a36Sopenharmony_ci				errx(EXIT_FAILURE, no_tracer_msg);
188262306a36Sopenharmony_ci			if (!valid)
188362306a36Sopenharmony_ci				errx(EXIT_FAILURE,
188462306a36Sopenharmony_ci"The tracer %s is not supported by your kernel!\n", current_tracer);
188562306a36Sopenharmony_ci			break;
188662306a36Sopenharmony_ci		case 'F':
188762306a36Sopenharmony_ci			force_tracer = true;
188862306a36Sopenharmony_ci			break;
188962306a36Sopenharmony_ci		case 's':
189062306a36Sopenharmony_ci			check_alldigits(optarg, "-s [--threshold]");
189162306a36Sopenharmony_ci			threshold = strdup(optarg);
189262306a36Sopenharmony_ci			break;
189362306a36Sopenharmony_ci		case 'f':
189462306a36Sopenharmony_ci			use_options[OPTIDX_FUNC_TR] = true;
189562306a36Sopenharmony_ci			break;
189662306a36Sopenharmony_ci		case 'g':
189762306a36Sopenharmony_ci			use_options[OPTIDX_DISP_GR] = true;
189862306a36Sopenharmony_ci			break;
189962306a36Sopenharmony_ci		case 'c':
190062306a36Sopenharmony_ci			p = policy_from_name(optarg);
190162306a36Sopenharmony_ci			if (p != NULL) {
190262306a36Sopenharmony_ci				sched_policy = p->policy;
190362306a36Sopenharmony_ci				sched_policy_set = true;
190462306a36Sopenharmony_ci				if (!sched_pri_set) {
190562306a36Sopenharmony_ci					sched_pri = p->default_pri;
190662306a36Sopenharmony_ci					sched_pri_set = true;
190762306a36Sopenharmony_ci				}
190862306a36Sopenharmony_ci			} else {
190962306a36Sopenharmony_ci				warnx("Unknown scheduling %s\n", optarg);
191062306a36Sopenharmony_ci				show_usage();
191162306a36Sopenharmony_ci				exit(0);
191262306a36Sopenharmony_ci			}
191362306a36Sopenharmony_ci			break;
191462306a36Sopenharmony_ci		case 'p':
191562306a36Sopenharmony_ci			check_alldigits(optarg, "-p [--priority]");
191662306a36Sopenharmony_ci			sched_pri = atoi(optarg);
191762306a36Sopenharmony_ci			sched_pri_set = true;
191862306a36Sopenharmony_ci			break;
191962306a36Sopenharmony_ci		case 'h':
192062306a36Sopenharmony_ci			show_usage();
192162306a36Sopenharmony_ci			exit(0);
192262306a36Sopenharmony_ci			break;
192362306a36Sopenharmony_ci		case 'n':
192462306a36Sopenharmony_ci			trace_enable = false;
192562306a36Sopenharmony_ci			use_random_sleep = false;
192662306a36Sopenharmony_ci			break;
192762306a36Sopenharmony_ci		case 'e':
192862306a36Sopenharmony_ci			check_alldigits(optarg, "-e [--threads]");
192962306a36Sopenharmony_ci			value = atoi(optarg);
193062306a36Sopenharmony_ci			if (value > 0)
193162306a36Sopenharmony_ci				nr_threads = value;
193262306a36Sopenharmony_ci			else {
193362306a36Sopenharmony_ci				warnx("NRTHR must be > 0\n");
193462306a36Sopenharmony_ci				show_usage();
193562306a36Sopenharmony_ci				exit(0);
193662306a36Sopenharmony_ci			}
193762306a36Sopenharmony_ci			break;
193862306a36Sopenharmony_ci		case 'u':
193962306a36Sopenharmony_ci			check_alldigits(optarg, "-u [--time]");
194062306a36Sopenharmony_ci			value = atoi(optarg);
194162306a36Sopenharmony_ci			if (value < 0) {
194262306a36Sopenharmony_ci				warnx("TIME must be >= 0\n");
194362306a36Sopenharmony_ci				show_usage();
194462306a36Sopenharmony_ci				exit(0);
194562306a36Sopenharmony_ci			}
194662306a36Sopenharmony_ci			trace_enable = true;
194762306a36Sopenharmony_ci			use_random_sleep = true;
194862306a36Sopenharmony_ci			sleep_time = value * USEC_PER_MSEC;
194962306a36Sopenharmony_ci			break;
195062306a36Sopenharmony_ci		case 'v':
195162306a36Sopenharmony_ci			verbosity++;
195262306a36Sopenharmony_ci			break;
195362306a36Sopenharmony_ci		case 'r':
195462306a36Sopenharmony_ci			trace_enable = true;
195562306a36Sopenharmony_ci			use_random_sleep = true;
195662306a36Sopenharmony_ci			break;
195762306a36Sopenharmony_ci		case 'a':
195862306a36Sopenharmony_ci			check_alldigits(optarg, "-a [--nrlat]");
195962306a36Sopenharmony_ci			value = atoi(optarg);
196062306a36Sopenharmony_ci			if (value <= 0) {
196162306a36Sopenharmony_ci				warnx("NRLAT must be > 0\n");
196262306a36Sopenharmony_ci				show_usage();
196362306a36Sopenharmony_ci				exit(0);
196462306a36Sopenharmony_ci			}
196562306a36Sopenharmony_ci			trace_enable = true;
196662306a36Sopenharmony_ci			use_random_sleep = true;
196762306a36Sopenharmony_ci			table_startsize = value;
196862306a36Sopenharmony_ci			break;
196962306a36Sopenharmony_ci		case 'x':
197062306a36Sopenharmony_ci			setup_ftrace = false;
197162306a36Sopenharmony_ci			break;
197262306a36Sopenharmony_ci		case 'i':
197362306a36Sopenharmony_ci			setup_ftrace = false;
197462306a36Sopenharmony_ci			debug_tracefile = strdup(optarg);
197562306a36Sopenharmony_ci			break;
197662306a36Sopenharmony_ci		case 'm':
197762306a36Sopenharmony_ci			setup_ftrace = false;
197862306a36Sopenharmony_ci			debug_maxlat = strdup(optarg);
197962306a36Sopenharmony_ci			break;
198062306a36Sopenharmony_ci		default:
198162306a36Sopenharmony_ci			show_usage();
198262306a36Sopenharmony_ci			exit(0);
198362306a36Sopenharmony_ci			break;
198462306a36Sopenharmony_ci		}
198562306a36Sopenharmony_ci	}
198662306a36Sopenharmony_ci
198762306a36Sopenharmony_ci	if (setup_ftrace) {
198862306a36Sopenharmony_ci		if (!current_tracer) {
198962306a36Sopenharmony_ci			current_tracer = find_default_tracer();
199062306a36Sopenharmony_ci			if (!current_tracer)
199162306a36Sopenharmony_ci				errx(EXIT_FAILURE,
199262306a36Sopenharmony_ci"No default tracer found and tracer not specified\n");
199362306a36Sopenharmony_ci		}
199462306a36Sopenharmony_ci
199562306a36Sopenharmony_ci		if (use_random_sleep && !random_makes_sense(current_tracer)) {
199662306a36Sopenharmony_ci			warnx("WARNING: The tracer is %s and random sleep has",
199762306a36Sopenharmony_ci			      current_tracer);
199862306a36Sopenharmony_ci			fprintf(stderr,
199962306a36Sopenharmony_ci"been enabled. Random sleep is intended for the following tracers:\n");
200062306a36Sopenharmony_ci			for (i = 0; random_tracers[i]; i++)
200162306a36Sopenharmony_ci				fprintf(stderr, "%s\n", random_tracers[i]);
200262306a36Sopenharmony_ci			fprintf(stderr, "\n");
200362306a36Sopenharmony_ci		}
200462306a36Sopenharmony_ci	}
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_ci	if (debug_tracefile == DEBUG_NOFILE ||
200762306a36Sopenharmony_ci	    debug_maxlat == DEBUG_NOFILE)
200862306a36Sopenharmony_ci		errx(EXIT_FAILURE,
200962306a36Sopenharmony_ci"Could not find tracing directory e.g. /sys/kernel/tracing\n");
201062306a36Sopenharmony_ci
201162306a36Sopenharmony_ci	if (!sched_policy_set) {
201262306a36Sopenharmony_ci		sched_policy = SCHED_RR;
201362306a36Sopenharmony_ci		sched_policy_set = true;
201462306a36Sopenharmony_ci		if (!sched_pri_set) {
201562306a36Sopenharmony_ci			sched_pri = RT_DEFAULT_PRI;
201662306a36Sopenharmony_ci			sched_pri_set = true;
201762306a36Sopenharmony_ci		}
201862306a36Sopenharmony_ci	}
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_ci	max = sched_get_priority_max(sched_policy);
202162306a36Sopenharmony_ci	min = sched_get_priority_min(sched_policy);
202262306a36Sopenharmony_ci
202362306a36Sopenharmony_ci	if (sched_pri < min) {
202462306a36Sopenharmony_ci		printf(
202562306a36Sopenharmony_ci"ATTENTION: Increasing priority to minimum, which is %d\n", min);
202662306a36Sopenharmony_ci		sched_pri = min;
202762306a36Sopenharmony_ci	}
202862306a36Sopenharmony_ci	if (sched_pri > max) {
202962306a36Sopenharmony_ci		printf(
203062306a36Sopenharmony_ci"ATTENTION: Reducing priority to maximum, which is %d\n", max);
203162306a36Sopenharmony_ci		sched_pri = max;
203262306a36Sopenharmony_ci	}
203362306a36Sopenharmony_ci}
203462306a36Sopenharmony_ci
203562306a36Sopenharmony_cistatic void show_params(void)
203662306a36Sopenharmony_ci{
203762306a36Sopenharmony_ci	printf(
203862306a36Sopenharmony_ci"\n"
203962306a36Sopenharmony_ci"Running with scheduling policy %s and priority %d. Using %d print threads.\n",
204062306a36Sopenharmony_ci		policy_name(sched_policy), sched_pri, nr_threads);
204162306a36Sopenharmony_ci	if (trace_enable) {
204262306a36Sopenharmony_ci		if (use_random_sleep) {
204362306a36Sopenharmony_ci			printf(
204462306a36Sopenharmony_ci"%s will be printed with random delay\n"
204562306a36Sopenharmony_ci"Start size of the probability table:\t\t\t%d\n"
204662306a36Sopenharmony_ci"Print a message when the prob. table changes size:\t%s\n"
204762306a36Sopenharmony_ci"Print a warning when an event has been lost:\t\t%s\n"
204862306a36Sopenharmony_ci"Sleep time is:\t\t\t\t\t\t%ld ms\n",
204962306a36Sopenharmony_cidebug_tracefile,
205062306a36Sopenharmony_citable_startsize,
205162306a36Sopenharmony_cibool2str(verbose_sizechange()),
205262306a36Sopenharmony_cibool2str(verbose_lostevent()),
205362306a36Sopenharmony_cisleep_time / USEC_PER_MSEC);
205462306a36Sopenharmony_ci		} else {
205562306a36Sopenharmony_ci			printf("%s will be printed immediately\n",
205662306a36Sopenharmony_ci			       debug_tracefile);
205762306a36Sopenharmony_ci		}
205862306a36Sopenharmony_ci	} else {
205962306a36Sopenharmony_ci		printf("%s will not be printed\n",
206062306a36Sopenharmony_ci		       debug_tracefile);
206162306a36Sopenharmony_ci	}
206262306a36Sopenharmony_ci	if (setup_ftrace) {
206362306a36Sopenharmony_ci		printf("Tracer:\t\t\t\t\t\t\t%s\n"
206462306a36Sopenharmony_ci		       "%s option:\t\t\t\t\t%s\n"
206562306a36Sopenharmony_ci		       "%s option:\t\t\t\t\t%s\n",
206662306a36Sopenharmony_ci		       current_tracer,
206762306a36Sopenharmony_ci		       optstr[OPTIDX_FUNC_TR],
206862306a36Sopenharmony_ci		       bool2str(use_options[OPTIDX_FUNC_TR]),
206962306a36Sopenharmony_ci		       optstr[OPTIDX_DISP_GR],
207062306a36Sopenharmony_ci		       bool2str(use_options[OPTIDX_DISP_GR]));
207162306a36Sopenharmony_ci		if (!strcmp(threshold, "0"))
207262306a36Sopenharmony_ci			printf("Threshold:\t\t\t\t\t\ttracing_max_latency\n");
207362306a36Sopenharmony_ci		else
207462306a36Sopenharmony_ci			printf("Threshold:\t\t\t\t\t\t%s\n", threshold);
207562306a36Sopenharmony_ci	}
207662306a36Sopenharmony_ci	printf("\n");
207762306a36Sopenharmony_ci}
207862306a36Sopenharmony_ci
207962306a36Sopenharmony_ciint main(int argc, char *argv[])
208062306a36Sopenharmony_ci{
208162306a36Sopenharmony_ci	init_save_state();
208262306a36Sopenharmony_ci	signal_blocking(SIG_BLOCK);
208362306a36Sopenharmony_ci	setup_sig_handler();
208462306a36Sopenharmony_ci	open_stdout();
208562306a36Sopenharmony_ci
208662306a36Sopenharmony_ci	if (argc >= 1)
208762306a36Sopenharmony_ci		prg_name = argv[0];
208862306a36Sopenharmony_ci	else
208962306a36Sopenharmony_ci		prg_name = prg_unknown;
209062306a36Sopenharmony_ci
209162306a36Sopenharmony_ci	scan_arguments(argc, argv);
209262306a36Sopenharmony_ci	show_params();
209362306a36Sopenharmony_ci
209462306a36Sopenharmony_ci	init_printstate();
209562306a36Sopenharmony_ci	init_print_mtx();
209662306a36Sopenharmony_ci	if (use_random_sleep) {
209762306a36Sopenharmony_ci		init_probabilities();
209862306a36Sopenharmony_ci		if (verbose_sizechange())
209962306a36Sopenharmony_ci			printf("Initializing probability table to %d\n",
210062306a36Sopenharmony_ci			       table_startsize);
210162306a36Sopenharmony_ci		sleeptable_resize(table_startsize, false, NULL);
210262306a36Sopenharmony_ci	}
210362306a36Sopenharmony_ci	set_priority();
210462306a36Sopenharmony_ci	init_queue(&printqueue);
210562306a36Sopenharmony_ci	start_printthread();
210662306a36Sopenharmony_ci	tracing_loop();
210762306a36Sopenharmony_ci	return 0;
210862306a36Sopenharmony_ci}
2109