----- Original Message -----
Implement `timer` command option (namely, `-e`) that allows
filtering
out all the non-expired timers.
This is useful to verify what CPU is blocked due to looping with
interrupts disabled or due to lack of resources to run the vCPU on a
hypervisor side.
Hi Oleksandr,
This makes the output somewhat sparse, ugly, and hard to read, no?
I'm wondering if it would be more readable if you just recognize the
expired entries, and maybe display something like "[EXPIRED]" at the
end of the expired entry's line? It wouldn't even require the "-e",
but just have it do it all the time.
What do you think?
Dave
Signed-off-by: Oleksandr Natalenko <oleksandr(a)redhat.com>
---
help.c | 1 +
kernel.c | 213 ++++++++++++++++++++++++++++++++-----------------------
2 files changed, 125 insertions(+), 89 deletions(-)
diff --git a/help.c b/help.c
index c0c750f..fa856d1 100644
--- a/help.c
+++ b/help.c
@@ -2886,6 +2886,7 @@ char *help_timer[] = {
" chronological order. In the case of the old-style hrtimers, the",
" expiration time is a single value; in the new-style hrtimers, the",
" expiration time is a range.",
+" -e Display expired timers only.",
" -C cpu Restrict the output to one or more CPUs, where multiple cpu[s]
can",
" be specified, for example, as \"1,3,5\", \"1-3\", or
\"1,3,5-7,10\".",
"\nEXAMPLES",
diff --git a/kernel.c b/kernel.c
index 22909d2..afc66da 100644
--- a/kernel.c
+++ b/kernel.c
@@ -38,24 +38,24 @@ static void display_bh_1(void);
static void display_bh_2(void);
static void display_bh_3(void);
static void display_bh_4(void);
-static void dump_hrtimer_data(const ulong *cpus);
-static void dump_hrtimer_clock_base(const void *, const int);
-static void dump_hrtimer_base(const void *, const int);
-static void dump_active_timers(const void *, ulonglong);
+static void dump_hrtimer_data(const ulong *, int);
+static void dump_hrtimer_clock_base(const void *, const int, int);
+static void dump_hrtimer_base(const void *, const int, int);
+static void dump_active_timers(const void *, ulonglong, int);
static int get_expires_len(const int, const ulong *, const int);
-static void print_timer(const void *);
+static void print_timer(const void *, ulonglong, int);
static ulonglong ktime_to_ns(const void *);
-static void dump_timer_data(const ulong *cpus);
-static void dump_timer_data_tvec_bases_v1(const ulong *cpus);
-static void dump_timer_data_tvec_bases_v2(const ulong *cpus);
-static void dump_timer_data_tvec_bases_v3(const ulong *cpus);
-static void dump_timer_data_timer_bases(const ulong *cpus);
+static void dump_timer_data(const ulong *, int);
+static void dump_timer_data_tvec_bases_v1(const ulong *, int);
+static void dump_timer_data_tvec_bases_v2(const ulong *, int);
+static void dump_timer_data_tvec_bases_v3(const ulong *, int);
+static void dump_timer_data_timer_bases(const ulong *, int);
struct tv_range;
static void init_tv_ranges(struct tv_range *, int, int, int);
-static int do_timer_list(ulong,int, ulong *, void *,ulong *,struct tv_range
*);
-static int do_timer_list_v3(ulong, int, ulong *, void *,ulong *);
+static int do_timer_list(ulong,int, ulong *, void *,ulong *,struct tv_range
*, ulong, int);
+static int do_timer_list_v3(ulong, int, ulong *, void *,ulong *, ulong,
int);
struct timer_bases_data;
-static int do_timer_list_v4(struct timer_bases_data *);
+static int do_timer_list_v4(struct timer_bases_data *, ulong, int);
static int compare_timer_data(const void *, const void *);
static void panic_this_kernel(void);
static void dump_waitq(ulong, char *);
@@ -7402,18 +7402,24 @@ cmd_timer(void)
{
int c;
int rflag;
+ int eflag;
char *cpuspec;
ulong *cpus = NULL;
rflag = 0;
+ eflag = 0;
- while ((c = getopt(argcnt, args, "rC:")) != EOF) {
+ while ((c = getopt(argcnt, args, "reC:")) != EOF) {
switch(c)
{
case 'r':
rflag = 1;
break;
+ case 'e':
+ eflag = 1;
+ break;
+
case 'C':
cpuspec = optarg;
cpus = get_cpumask_buf();
@@ -7430,16 +7436,16 @@ cmd_timer(void)
cmd_usage(pc->curcmd, SYNOPSIS);
if (rflag)
- dump_hrtimer_data(cpus);
+ dump_hrtimer_data(cpus, eflag);
else
- dump_timer_data(cpus);
+ dump_timer_data(cpus, eflag);
if (cpus)
FREEBUF(cpus);
}
static void
-dump_hrtimer_data(const ulong *cpus)
+dump_hrtimer_data(const ulong *cpus, int eflag)
{
int i, j, k = 0;
int hrtimer_max_clock_bases, max_hrtimer_bases;
@@ -7487,7 +7493,7 @@ dump_hrtimer_data(const ulong *cpus)
fprintf(fp, "\n");
dump_hrtimer_clock_base(
(void *)(hrtimer_bases->value) +
- kt->__per_cpu_offset[i], j);
+ kt->__per_cpu_offset[i], j, eflag);
}
} else {
fprintf(fp, "\n");
@@ -7496,7 +7502,7 @@ dump_hrtimer_data(const ulong *cpus)
fprintf(fp, "\n");
dump_hrtimer_base(
(void *)(hrtimer_bases->value) +
- kt->__per_cpu_offset[i], j);
+ kt->__per_cpu_offset[i], j, eflag);
}
}
}
@@ -7506,7 +7512,7 @@ static int expires_len = -1;
static int softexpires_len = -1;
static void
-dump_hrtimer_clock_base(const void *hrtimer_bases, const int num)
+dump_hrtimer_clock_base(const void *hrtimer_bases, const int num, int eflag)
{
void *base;
ulonglong current_time, now;
@@ -7530,11 +7536,11 @@ dump_hrtimer_clock_base(const void *hrtimer_bases,
const int num)
offset = ktime_to_ns(base + OFFSET(hrtimer_clock_base_offset));
now = current_time * (1000000000LL / machdep->hz) + offset;
- dump_active_timers(base, now);
+ dump_active_timers(base, now, eflag);
}
static void
-dump_hrtimer_base(const void *hrtimer_bases, const int num)
+dump_hrtimer_base(const void *hrtimer_bases, const int num, int eflag)
{
void *base;
ulonglong current_time, now;
@@ -7552,11 +7558,11 @@ dump_hrtimer_base(const void *hrtimer_bases, const
int num)
get_uptime(NULL, ¤t_time);
now = current_time * (1000000000LL / machdep->hz);
- dump_active_timers(base, now);
+ dump_active_timers(base, now, eflag);
}
static void
-dump_active_timers(const void *base, ulonglong now)
+dump_active_timers(const void *base, ulonglong now, int eflag)
{
int next, i, t;
struct rb_node *curr;
@@ -7664,7 +7670,7 @@ next_one:
else
timer = (void *)(timer_list[t] - OFFSET(hrtimer_node));
- print_timer(timer);
+ print_timer(timer, now, eflag);
}
}
@@ -7715,7 +7721,7 @@ get_expires_len(const int timer_cnt, const ulong
*timer_list, const int getsoft)
* print hrtimer and its related information
*/
static void
-print_timer(const void *timer)
+print_timer(const void *timer, ulonglong now, int eflag)
{
ulonglong softexpires, expires;
@@ -7724,6 +7730,15 @@ print_timer(const void *timer)
char buf2[BUFSIZE];
char buf3[BUFSIZE];
+ if (VALID_MEMBER(hrtimer_expires))
+ expires = ktime_to_ns(timer + OFFSET(hrtimer_expires));
+ else
+ expires = ktime_to_ns(timer + OFFSET(hrtimer_node) +
+ OFFSET(timerqueue_node_expires));
+
+ if (eflag && expires >= now)
+ return;
+
/* align information */
fprintf(fp, " ");
@@ -7732,11 +7747,6 @@ print_timer(const void *timer)
return;
}
- if (VALID_MEMBER(hrtimer_expires))
- expires = ktime_to_ns(timer + OFFSET(hrtimer_expires));
- else
- expires = ktime_to_ns(timer + OFFSET(hrtimer_node) +
- OFFSET(timerqueue_node_expires));
if (VALID_MEMBER(hrtimer_softexpires)) {
softexpires = ktime_to_ns(timer + OFFSET(hrtimer_softexpires));
@@ -7818,7 +7828,7 @@ struct tv_range {
#define TVN (6)
static void
-dump_timer_data(const ulong *cpus)
+dump_timer_data(const ulong *cpus, int eflag)
{
int i;
ulong timer_active;
@@ -7839,16 +7849,16 @@ dump_timer_data(const ulong *cpus)
struct tv_range tv[TVN];
if (kt->flags2 & TIMER_BASES) {
- dump_timer_data_timer_bases(cpus);
+ dump_timer_data_timer_bases(cpus, eflag);
return;
} else if (kt->flags2 & TVEC_BASES_V3) {
- dump_timer_data_tvec_bases_v3(cpus);
+ dump_timer_data_tvec_bases_v3(cpus, eflag);
return;
} else if (kt->flags & TVEC_BASES_V2) {
- dump_timer_data_tvec_bases_v2(cpus);
+ dump_timer_data_tvec_bases_v2(cpus, eflag);
return;
} else if (kt->flags & TVEC_BASES_V1) {
- dump_timer_data_tvec_bases_v1(cpus);
+ dump_timer_data_tvec_bases_v1(cpus, eflag);
return;
}
@@ -7888,23 +7898,24 @@ dump_timer_data(const ulong *cpus)
init_tv_ranges(tv, vec_root_size, vec_size, 0);
+ get_symbol_data("jiffies", sizeof(ulong), &jiffies);
+ get_symbol_data("timer_jiffies", sizeof(ulong), &timer_jiffies);
+
count += do_timer_list(symbol_value("tv1") +
OFFSET(timer_vec_root_vec),
- vec_root_size, vec, NULL, NULL, tv);
+ vec_root_size, vec, NULL, NULL, tv, jiffies, eflag);
count += do_timer_list(symbol_value("tv2") + OFFSET(timer_vec_vec),
- vec_size, vec, NULL, NULL, tv);
+ vec_size, vec, NULL, NULL, tv, jiffies, eflag);
count += do_timer_list(symbol_value("tv3") + OFFSET(timer_vec_vec),
- vec_size, vec, NULL, NULL, tv);
+ vec_size, vec, NULL, NULL, tv, jiffies, eflag);
count += do_timer_list(symbol_value("tv4") + OFFSET(timer_vec_vec),
- vec_size, vec, NULL, NULL, tv);
+ vec_size, vec, NULL, NULL, tv, jiffies, eflag);
count += do_timer_list(symbol_value("tv4") + OFFSET(timer_vec_vec),
- vec_size, vec, NULL, NULL, tv);
+ vec_size, vec, NULL, NULL, tv, jiffies, eflag);
td = (struct timer_data *)
GETBUF((count*2) * sizeof(struct timer_data));
tdx = 0;
- get_symbol_data("jiffies", sizeof(ulong), &jiffies);
- get_symbol_data("timer_jiffies", sizeof(ulong), &timer_jiffies);
if (old_timers_exist)
get_symbol_data("timer_active", sizeof(ulong), &timer_active);
@@ -7916,6 +7927,8 @@ dump_timer_data(const ulong *cpus)
if (!(mask & timer_active))
continue;
+ if (eflag && tp->expires >= jiffies)
+ continue;
td[tdx].address = i;
td[tdx].expires = tp->expires;
@@ -7926,15 +7939,15 @@ dump_timer_data(const ulong *cpus)
}
do_timer_list(symbol_value("tv1") + OFFSET(timer_vec_root_vec),
- vec_root_size, vec, (void *)td, &highest, tv);
+ vec_root_size, vec, (void *)td, &highest, tv, jiffies, eflag);
do_timer_list(symbol_value("tv2") + OFFSET(timer_vec_vec),
- vec_size, vec, (void *)td, &highest, tv);
+ vec_size, vec, (void *)td, &highest, tv, jiffies, eflag);
do_timer_list(symbol_value("tv3") + OFFSET(timer_vec_vec),
- vec_size, vec, (void *)td, &highest, tv);
+ vec_size, vec, (void *)td, &highest, tv, jiffies, eflag);
do_timer_list(symbol_value("tv4") + OFFSET(timer_vec_vec),
- vec_size, vec, (void *)td, &highest, tv);
+ vec_size, vec, (void *)td, &highest, tv, jiffies, eflag);
tdx = do_timer_list(symbol_value("tv5") + OFFSET(timer_vec_vec),
- vec_size, vec, (void *)td, &highest, tv);
+ vec_size, vec, (void *)td, &highest, tv, jiffies, eflag);
qsort(td, tdx, sizeof(struct timer_data), compare_timer_data);
@@ -7951,6 +7964,9 @@ dump_timer_data(const ulong *cpus)
mkstring(buf, flen, CENTER|LJUST, "EXPIRES"));
for (i = 0; i < tdx; i++) {
+ if (eflag && td[i].expires >= jiffies)
+ continue;
+
fprintf(fp, "%s",
mkstring(buf, flen, RJUST|LONG_DEC, MKSTR(td[i].expires)));
@@ -7990,7 +8006,7 @@ dump_timer_data(const ulong *cpus)
*/
static void
-dump_timer_data_tvec_bases_v1(const ulong *cpus)
+dump_timer_data_tvec_bases_v1(const ulong *cpus, int eflag)
{
int i, cpu, tdx, flen;
struct timer_data *td;
@@ -8026,34 +8042,35 @@ next_cpu:
init_tv_ranges(tv, vec_root_size, vec_size, cpu);
+ get_symbol_data("jiffies", sizeof(ulong), &jiffies);
+
count += do_timer_list(tv[1].base + OFFSET(tvec_root_s_vec),
- vec_root_size, vec, NULL, NULL, tv);
+ vec_root_size, vec, NULL, NULL, tv, jiffies, eflag);
count += do_timer_list(tv[2].base + OFFSET(tvec_s_vec),
- vec_size, vec, NULL, NULL, tv);
+ vec_size, vec, NULL, NULL, tv, jiffies, eflag);
count += do_timer_list(tv[3].base + OFFSET(tvec_s_vec),
- vec_size, vec, NULL, NULL, tv);
+ vec_size, vec, NULL, NULL, tv, jiffies, eflag);
count += do_timer_list(tv[4].base + OFFSET(tvec_s_vec),
- vec_size, vec, NULL, NULL, tv);
+ vec_size, vec, NULL, NULL, tv, jiffies, eflag);
count += do_timer_list(tv[5].base + OFFSET(tvec_s_vec),
- vec_size, vec, NULL, NULL, tv);
+ vec_size, vec, NULL, NULL, tv, jiffies, eflag);
if (count)
td = (struct timer_data *)
GETBUF((count*2) * sizeof(struct timer_data));
tdx = 0;
highest = 0;
- get_symbol_data("jiffies", sizeof(ulong), &jiffies);
do_timer_list(tv[1].base + OFFSET(tvec_root_s_vec),
- vec_root_size, vec, (void *)td, &highest, tv);
+ vec_root_size, vec, (void *)td, &highest, tv, jiffies,
eflag);
do_timer_list(tv[2].base + OFFSET(tvec_s_vec),
- vec_size, vec, (void *)td, &highest, tv);
+ vec_size, vec, (void *)td, &highest, tv, jiffies, eflag);
do_timer_list(tv[3].base + OFFSET(tvec_s_vec),
- vec_size, vec, (void *)td, &highest, tv);
+ vec_size, vec, (void *)td, &highest, tv, jiffies, eflag);
do_timer_list(tv[4].base + OFFSET(tvec_s_vec),
- vec_size, vec, (void *)td, &highest, tv);
+ vec_size, vec, (void *)td, &highest, tv, jiffies, eflag);
tdx = do_timer_list(tv[5].base + OFFSET(tvec_s_vec),
- vec_size, vec, (void *)td, &highest, tv);
+ vec_size, vec, (void *)td, &highest, tv, jiffies, eflag);
qsort(td, tdx, sizeof(struct timer_data), compare_timer_data);
@@ -8110,7 +8127,7 @@ next_cpu:
*/
static void
-dump_timer_data_tvec_bases_v2(const ulong *cpus)
+dump_timer_data_tvec_bases_v2(const ulong *cpus, int eflag)
{
int i, cpu, tdx, flen;
struct timer_data *td;
@@ -8168,34 +8185,35 @@ next_cpu:
init_tv_ranges(tv, vec_root_size, vec_size, cpu);
+ get_symbol_data("jiffies", sizeof(ulong), &jiffies);
+
count += do_timer_list(tv[1].base + OFFSET(tvec_root_s_vec),
- vec_root_size, vec, NULL, NULL, tv);
+ vec_root_size, vec, NULL, NULL, tv, jiffies, eflag);
count += do_timer_list(tv[2].base + OFFSET(tvec_s_vec),
- vec_size, vec, NULL, NULL, tv);
+ vec_size, vec, NULL, NULL, tv, jiffies, eflag);
count += do_timer_list(tv[3].base + OFFSET(tvec_s_vec),
- vec_size, vec, NULL, NULL, tv);
+ vec_size, vec, NULL, NULL, tv, jiffies, eflag);
count += do_timer_list(tv[4].base + OFFSET(tvec_s_vec),
- vec_size, vec, NULL, NULL, tv);
+ vec_size, vec, NULL, NULL, tv, jiffies, eflag);
count += do_timer_list(tv[5].base + OFFSET(tvec_s_vec),
- vec_size, vec, NULL, NULL, tv);
+ vec_size, vec, NULL, NULL, tv, jiffies, eflag);
if (count)
td = (struct timer_data *)
GETBUF((count*2) * sizeof(struct timer_data));
tdx = 0;
highest = 0;
- get_symbol_data("jiffies", sizeof(ulong), &jiffies);
do_timer_list(tv[1].base + OFFSET(tvec_root_s_vec),
- vec_root_size, vec, (void *)td, &highest, tv);
+ vec_root_size, vec, (void *)td, &highest, tv, jiffies,
eflag);
do_timer_list(tv[2].base + OFFSET(tvec_s_vec),
- vec_size, vec, (void *)td, &highest, tv);
+ vec_size, vec, (void *)td, &highest, tv, jiffies, eflag);
do_timer_list(tv[3].base + OFFSET(tvec_s_vec),
- vec_size, vec, (void *)td, &highest, tv);
+ vec_size, vec, (void *)td, &highest, tv, jiffies, eflag);
do_timer_list(tv[4].base + OFFSET(tvec_s_vec),
- vec_size, vec, (void *)td, &highest, tv);
+ vec_size, vec, (void *)td, &highest, tv, jiffies, eflag);
tdx = do_timer_list(tv[5].base + OFFSET(tvec_s_vec),
- vec_size, vec, (void *)td, &highest, tv);
+ vec_size, vec, (void *)td, &highest, tv, jiffies, eflag);
qsort(td, tdx, sizeof(struct timer_data), compare_timer_data);
@@ -8261,7 +8279,7 @@ next_cpu:
* Linux 4.2 timers use new tvec_root, tvec and timer_list structures
*/
static void
-dump_timer_data_tvec_bases_v3(const ulong *cpus)
+dump_timer_data_tvec_bases_v3(const ulong *cpus, int eflag)
{
int i, cpu, tdx, flen;
struct timer_data *td;
@@ -8313,34 +8331,35 @@ next_cpu:
BZERO(tv, sizeof(struct tv_range) * TVN);
init_tv_ranges(tv, vec_root_size, vec_size, cpu);
+ get_symbol_data("jiffies", sizeof(ulong), &jiffies);
+
count += do_timer_list_v3(tv[1].base + OFFSET(tvec_root_s_vec),
- vec_root_size, vec, NULL, NULL);
+ vec_root_size, vec, NULL, NULL, jiffies, eflag);
count += do_timer_list_v3(tv[2].base + OFFSET(tvec_s_vec),
- vec_size, vec, NULL, NULL);
+ vec_size, vec, NULL, NULL, jiffies, eflag);
count += do_timer_list_v3(tv[3].base + OFFSET(tvec_s_vec),
- vec_size, vec, NULL, NULL);
+ vec_size, vec, NULL, NULL, jiffies, eflag);
count += do_timer_list_v3(tv[4].base + OFFSET(tvec_s_vec),
- vec_size, vec, NULL, NULL);
+ vec_size, vec, NULL, NULL, jiffies, eflag);
count += do_timer_list_v3(tv[5].base + OFFSET(tvec_s_vec),
- vec_size, vec, NULL, NULL);
+ vec_size, vec, NULL, NULL, jiffies, eflag);
if (count)
td = (struct timer_data *)
GETBUF((count*2) * sizeof(struct timer_data));
tdx = 0;
highest = 0;
- get_symbol_data("jiffies", sizeof(ulong), &jiffies);
do_timer_list_v3(tv[1].base + OFFSET(tvec_root_s_vec),
- vec_root_size, vec, (void *)td, &highest);
+ vec_root_size, vec, (void *)td, &highest, jiffies, eflag);
do_timer_list_v3(tv[2].base + OFFSET(tvec_s_vec),
- vec_size, vec, (void *)td, &highest);
+ vec_size, vec, (void *)td, &highest, jiffies, eflag);
do_timer_list_v3(tv[3].base + OFFSET(tvec_s_vec),
- vec_size, vec, (void *)td, &highest);
+ vec_size, vec, (void *)td, &highest, jiffies, eflag);
do_timer_list_v3(tv[4].base + OFFSET(tvec_s_vec),
- vec_size, vec, (void *)td, &highest);
+ vec_size, vec, (void *)td, &highest, jiffies, eflag);
tdx = do_timer_list_v3(tv[5].base + OFFSET(tvec_s_vec),
- vec_size, vec, (void *)td, &highest);
+ vec_size, vec, (void *)td, &highest, jiffies, eflag);
qsort(td, tdx, sizeof(struct timer_data), compare_timer_data);
@@ -8506,7 +8525,9 @@ do_timer_list(ulong vec_kvaddr,
ulong *vec,
void *option,
ulong *highest,
- struct tv_range *tv)
+ struct tv_range *tv,
+ ulong jiffies,
+ int eflag)
{
int i, t;
int count, tdx;
@@ -8577,6 +8598,9 @@ do_timer_list(ulong vec_kvaddr,
expires = ULONG(timer_list_buf +
OFFSET(timer_list_expires));
+ if (eflag && expires >= jiffies)
+ continue;
+
function = ULONG(timer_list_buf +
OFFSET(timer_list_function));
@@ -8641,6 +8665,9 @@ new_timer_list_format:
expires = ULONG(timer_list_buf +
OFFSET(timer_list_expires));
+ if (eflag && expires >= jiffies)
+ continue;
+
function = ULONG(timer_list_buf +
OFFSET(timer_list_function));
@@ -8666,7 +8693,9 @@ do_timer_list_v3(ulong vec_kvaddr,
int size,
ulong *vec,
void *option,
- ulong *highest)
+ ulong *highest,
+ ulong jiffies,
+ int eflag)
{
int i, t;
int count, tdx;
@@ -8725,6 +8754,9 @@ do_timer_list_v3(ulong vec_kvaddr,
expires = ULONG(timer_list_buf +
OFFSET(timer_list_expires));
+ if (eflag && expires >= jiffies)
+ continue;
+
function = ULONG(timer_list_buf +
OFFSET(timer_list_function));
@@ -8755,7 +8787,7 @@ struct timer_bases_data {
};
static int
-do_timer_list_v4(struct timer_bases_data *data)
+do_timer_list_v4(struct timer_bases_data *data, ulong jiffies, int eflag)
{
int i, t, timer_cnt, found;
struct list_data list_data, *ld;
@@ -8810,6 +8842,9 @@ do_timer_list_v4(struct timer_bases_data *data)
continue;
expires = ULONG(timer_list_buf + OFFSET(timer_list_expires));
+ if (eflag && expires >= jiffies)
+ continue;
+
function = ULONG(timer_list_buf + OFFSET(timer_list_function));
data->timers[data->cnt].address = timer_list[t];
@@ -8839,7 +8874,7 @@ do_timer_list_v4(struct timer_bases_data *data)
* Linux 4.8 timers use new timer_bases[][]
*/
static void
-dump_timer_data_timer_bases(const ulong *cpus)
+dump_timer_data_timer_bases(const ulong *cpus, int eflag)
{
int i, cpu, flen, base, nr_bases, found, display, j = 0;
struct syment *sp;
@@ -8901,7 +8936,7 @@ next_base:
data.cnt = 0;
data.timer_base = timer_base;
- found = do_timer_list_v4(&data);
+ found = do_timer_list_v4(&data, jiffies, eflag);
qsort(data.timers, found, sizeof(struct timer_data), compare_timer_data);
--
2.22.0