At 2013-3-9 2:26, Dave Anderson wrote:
Shouldn't the NOW value for the ktime_get timers be adjusted appropriate to the EXPIRES values?
Done. I made a mistaken here, thanks for pointing it out! -- -- Regards Qiao Nuohan
>From c3531c5de04d63af89bf186d0a798070cc701dc6 Mon Sep 17 00:00:00 2001 From: qiaonuohan <qiaonuohan@xxxxxxxxxxxxxx> Date: Mon, 11 Mar 2013 09:41:22 +0800 Subject: [PATCH 2/2] hrtimer: add -r option to command timer command timer -r is used to display all hrtimers and their related information. --- defs.h | 21 ++++ help.c | 55 ++++++++- kernel.c | 385 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- symbols.c | 42 +++++++ 4 files changed, 495 insertions(+), 8 deletions(-) diff --git a/defs.h b/defs.h index 2993f2b..8f03672 100755 --- a/defs.h +++ b/defs.h @@ -1848,6 +1848,25 @@ struct offset_table { /* stash of commonly-used offsets */ long vmap_area_list; long vmap_area_flags; long vmap_area_vm; + long hrtimer_cpu_base_clock_base; + long hrtimer_clock_base_offset; + long hrtimer_clock_base_active; + long hrtimer_clock_base_first; + long hrtimer_clock_base_get_time; + long hrtimer_base_first; + long hrtimer_base_pending; + long hrtimer_base_get_time; + long hrtimer_node; + long hrtimer_list; + long hrtimer_softexpires; + long hrtimer_expires; + long hrtimer_function; + long timerqueue_head_next; + long timerqueue_node_expires; + long timerqueue_node_node; + long ktime_t_tv64; + long ktime_t_sec; + long ktime_t_nsec; }; struct size_table { /* stash of commonly-used sizes */ @@ -1985,6 +2004,8 @@ struct size_table { /* stash of commonly-used sizes */ long rt_rq; long task_group; long vmap_area; + long hrtimer_clock_base; + long hrtimer_base; }; struct array_table { diff --git a/help.c b/help.c index c542743..0245a70 100755 --- a/help.c +++ b/help.c @@ -2154,13 +2154,17 @@ NULL char *help_timer[] = { "timer", -"timer queue data", -" ", -" This command displays the timer queue entries, both old- and new-style,", -" in chronological order. In the case of the old-style timers, the", -" timer_table array index is shown; in the case of the new-style timers, ", -" the timer_list address is shown. On later kernels, the timer data is", -" per-cpu.", +"timer data", +"[-r]" +" ", +" This command provides information of timer. With no arguments, the command", +" displays the timer queue entries, both old- and new-style, in chronological", +" order. In the case of the old-style timers, the timer_table array index is", +" shown; in the case of the new-style timers, the timer_list address is", +" shown. On later kernels, the timer data is per-cpu.", +" ", +" -r shows all hrtimers and their related information. On earlier kernels, ", +" expire is an integer, and on later kernels, expire is a range.", "\nEXAMPLES", " %s> timer", " JIFFIES", @@ -2218,6 +2222,45 @@ char *help_timer[] = { " 18277900 ceebaec0 c01232bb <process_timeout>", " 18283769 cf739f64 c01232bb <process_timeout>", " 18331902 cee8af64 c01232bb <process_timeout>", +" ", +" Display hrtimers on a 2-cpu system:\n", +" %s> timer -r", +" cpu: 0 HRTIMER_CPU_BASE: ffff880002210f40", +" clock: 0 HRTIMER_CLOCK_BASE: ffff880002210f48", +" NOW: 1362965779619912707 GET_TIME: ktime_get_real", +" EXPIRES HRTIMER FUNCTION", +" 1362965812364616156-1362965812364666156 ffff88004dbb9d18 ffffffff81094d50 <hrtimer_wakeup>", +" ", +" clock: 1 HRTIMER_CLOCK_BASE: ffff880002210f88", +" NOW: 121430000000 GET_TIME: ktime_get", +" EXPIRES HRTIMER FUNCTION", +" 121431000000-121431000000 ffff880002211040 ffffffff810a0b70 <tick_sched_timer>", +" 132042999849-132042999849 ffff880002211260 ffffffff810d8ab0 <watchdog_timer_fn>", +" 140605044039-140635044037 ffff880037479a68 ffffffff81094d50 <hrtimer_wakeup>", +" 163679698388-163679748388 ffff88004ceabea8 ffffffff81094d50 <hrtimer_wakeup>", +" 6116411968847-6116411968847 ffff880037448c68 ffffffff8106f8b0 <it_real_fn>", +" 86447900789723-86448000789723 ffff880037b99918 ffffffff81094d50 <hrtimer_wakeup>", +" ", +" cpu: 1 HRTIMER_CPU_BASE: ffff880002310f40", +" clock: 0 HRTIMER_CLOCK_BASE: ffff880002310f48", +" NOW: 1362965779619912707 GET_TIME: ktime_get_real", +" EXPIRES HRTIMER FUNCTION", +" 1362965780925227428-1362965780925277428 ffff88004d63fd18 ffffffff81094d50 <hrtimer_wakeup>", +" 1362965814149803000-1362965814149853000 ffff88004d677d18 ffffffff81094d50 <hrtimer_wakeup>", +" ", +" clock: 1 HRTIMER_CLOCK_BASE: ffff880002310f88", +" NOW: 121431000000 GET_TIME: ktime_get", +" EXPIRES HRTIMER FUNCTION", +" 122701000000-122701000000 ffff880002311040 ffffffff810a0b70 <tick_sched_timer>", +" 129810089358-129810139358 ffff88004daefea8 ffffffff81094d50 <hrtimer_wakeup>", +" 132043999849-132043999849 ffff880002311260 ffffffff810d8ab0 <watchdog_timer_fn>", +" 143810417235-143840386233 ffff880037423a68 ffffffff81094d50 <hrtimer_wakeup>", +" 176696625533-176696675533 ffff88004ce19ea8 ffffffff81094d50 <hrtimer_wakeup>", +" 389403993573-389403993573 ffff88004a661468 ffffffff8106f8b0 <it_real_fn>", +" 449411980993-449411980993 ffff880037b75c68 ffffffff8106f8b0 <it_real_fn>", +" 3657285508602-3657285558602 ffff88004a8b3ea8 ffffffff81094d50 <hrtimer_wakeup>", +" 14458641190813-14458641240813 ffff880049da9ea8 ffffffff81094d50 <hrtimer_wakeup>", +" 86458651427627-86458651477627 ffff880049db7ea8 ffffffff81094d50 <hrtimer_wakeup>", NULL }; diff --git a/kernel.c b/kernel.c index c420518..82e78f1 100755 --- a/kernel.c +++ b/kernel.c @@ -34,6 +34,13 @@ 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(void); +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 *); +static int get_expires_len(const int, const ulong *); +static void print_timer(const void *); +static ulonglong ktime_to_ns(const void *); static void dump_timer_data(void); static void dump_timer_data_tvec_bases_v1(void); static void dump_timer_data_tvec_bases_v2(void); @@ -638,6 +645,50 @@ kernel_init() BUG_bytes_init(); kt->flags &= ~PRE_KERNEL_INIT; + + /* + * for hrtimer + */ + MEMBER_OFFSET_INIT(hrtimer_cpu_base_clock_base, "hrtimer_cpu_base", + "clock_base"); + MEMBER_OFFSET_INIT(hrtimer_clock_base_offset, "hrtimer_clock_base", + "offset"); + MEMBER_OFFSET_INIT(hrtimer_clock_base_active, "hrtimer_clock_base", + "active"); + MEMBER_OFFSET_INIT(hrtimer_clock_base_first, "hrtimer_clock_base", + "first"); + MEMBER_OFFSET_INIT(hrtimer_clock_base_get_time, "hrtimer_clock_base", + "get_time"); + MEMBER_OFFSET_INIT(hrtimer_base_first, "hrtimer_base", "first"); + MEMBER_OFFSET_INIT(hrtimer_base_pending, "hrtimer_base", "pending"); + MEMBER_OFFSET_INIT(hrtimer_base_get_time, "hrtimer_base", "get_time"); + MEMBER_OFFSET_INIT(hrtimer_node, "hrtimer", "node"); + MEMBER_OFFSET_INIT(hrtimer_list, "hrtimer", "list"); + MEMBER_OFFSET_INIT(hrtimer_expires, "hrtimer", "expires"); + if (INVALID_MEMBER(hrtimer_expires)) + MEMBER_OFFSET_INIT(hrtimer_expires, "hrtimer", "_expires"); + if (INVALID_MEMBER(hrtimer_expires)) { + MEMBER_OFFSET_INIT(timerqueue_head_next, "timerqueue_head", "next"); + MEMBER_OFFSET_INIT(timerqueue_node_expires, "timerqueue_node", + "expires"); + MEMBER_OFFSET_INIT(timerqueue_node_node, "timerqueue_node_node", + "node"); + } + + MEMBER_OFFSET_INIT(hrtimer_softexpires, "hrtimer", "_softexpires"); + MEMBER_OFFSET_INIT(hrtimer_function, "hrtimer", "function"); + MEMBER_OFFSET_INIT(ktime_t_tv64, "ktime", "tv64"); + if (INVALID_MEMBER(ktime_t_tv64)) + MEMBER_OFFSET_INIT(ktime_t_tv64, "ktime_t", "tv64"); + MEMBER_OFFSET_INIT(ktime_t_sec, "ktime", "sec"); + if (INVALID_MEMBER(ktime_t_sec)) + MEMBER_OFFSET_INIT(ktime_t_sec, "ktime_t", "sec"); + MEMBER_OFFSET_INIT(ktime_t_nsec, "ktime", "nsec"); + if (INVALID_MEMBER(ktime_t_nsec)) + MEMBER_OFFSET_INIT(ktime_t_nsec, "ktime_t", "nsec"); + + STRUCT_SIZE_INIT(hrtimer_clock_base, "hrtimer_clock_base"); + STRUCT_SIZE_INIT(hrtimer_base, "hrtimer_base"); } /* @@ -6333,10 +6384,17 @@ void cmd_timer(void) { int c; + int rflag; - while ((c = getopt(argcnt, args, "")) != EOF) { + rflag = 0; + + while ((c = getopt(argcnt, args, "r")) != EOF) { switch(c) { + case 'r': + rflag = 1; + break; + default: argerrs++; break; @@ -6346,7 +6404,330 @@ cmd_timer(void) if (argerrs) cmd_usage(pc->curcmd, SYNOPSIS); - dump_timer_data(); + if (rflag) + dump_hrtimer_data(); + else + dump_timer_data(); +} + +static void +dump_hrtimer_data(void) +{ + int i, j; + int hrtimer_max_clock_bases, max_hrtimer_bases; + struct syment * hrtimer_bases; + + hrtimer_max_clock_bases = 0; + max_hrtimer_bases = 0; + + /* + * deside whether hrtimer is available and + * set hrtimer_max_clock_bases or max_hrtimer_bases. + * if both are not available, hrtimer is not available. + */ + if (VALID_SIZE(hrtimer_clock_base)) { + hrtimer_max_clock_bases = 2; + if (symbol_exists("ktime_get_boottime")) + hrtimer_max_clock_bases = 3; + } else if (VALID_SIZE(hrtimer_base)) { + max_hrtimer_bases = 2; + } else + command_not_supported(); + + hrtimer_bases = per_cpu_symbol_search("hrtimer_bases"); + for (i = 0; i < kt->cpus; i++) { + if (i) + fprintf(fp, "\n"); + fprintf(fp, "cpu: %d ", i); + if (VALID_SIZE(hrtimer_clock_base)) { + fprintf(fp, "HRTIMER_CPU_BASE: %lx\n", + (ulong)(hrtimer_bases->value + + kt->__per_cpu_offset[i])); + + for (j = 0; j < hrtimer_max_clock_bases; j++) { + if (j) + fprintf(fp, "\n"); + dump_hrtimer_clock_base( + (void *)(hrtimer_bases->value) + + kt->__per_cpu_offset[i], j); + } + } else { + fprintf(fp, "\n"); + for (j = 0; j < max_hrtimer_bases; j++) { + if (j) + fprintf(fp, "\n"); + dump_hrtimer_base( + (void *)(hrtimer_bases->value) + + kt->__per_cpu_offset[i], j); + } + } + } +} + +static int expires_len = VADDR_PRLEN; + +static void +dump_hrtimer_clock_base(const void *hrtimer_bases, const int num) +{ + void *base; + ulonglong current_time; + ulonglong offset; + ulong get_time; + char buf[BUFSIZE]; + + base = (void *)hrtimer_bases + OFFSET(hrtimer_cpu_base_clock_base) + + SIZE(hrtimer_clock_base) * num; + fprintf(fp, " clock: %d HRTIMER_CLOCK_BASE: %lx\n", num, (ulong)base); + + /* get current time(uptime) */ + get_uptime(NULL, ¤t_time); + + offset = 0; + if (VALID_MEMBER(hrtimer_clock_base_offset)) + offset = ktime_to_ns(base + OFFSET(hrtimer_clock_base_offset)); + + fprintf(fp, " NOW: %lld", current_time * 1000000000LL / machdep->hz + offset); + + readmem((ulong)(base + OFFSET(hrtimer_clock_base_get_time)), KVADDR, + &get_time, sizeof(get_time), "hrtimer_clock_base get_time", + FAULT_ON_ERROR); + + fprintf(fp ," GET_TIME: %s\n", value_to_symstr(get_time, buf, 0)); + + dump_active_timers(base); +} + +static void +dump_hrtimer_base(const void *hrtimer_bases, const int num) +{ + void *base; + ulonglong current_time; + ulong get_time; + char buf[BUFSIZE]; + + base = (void *)hrtimer_bases + SIZE(hrtimer_base) * num; + fprintf(fp, " clock: %d HRTIMER_BASE: %lx\n", num, (ulong)base); + + /* get current time(uptime) */ + get_uptime(NULL, ¤t_time); + fprintf(fp, " NOW: %lld", current_time * 1000000000LL / machdep->hz); + + readmem((ulong)(base + OFFSET(hrtimer_base_get_time)), KVADDR, + &get_time, sizeof(get_time), "hrtimer_base get_time", + FAULT_ON_ERROR); + + fprintf(fp ," GET_TIME: %s\n", value_to_symstr(get_time, buf, 0)); + + dump_active_timers(base); +} + +static void +dump_active_timers(const void *base) +{ + int next, i, t; + struct rb_node *curr; + int timer_cnt; + ulong *timer_list; + void *timer; + char buf1[BUFSIZE]; + char buf2[BUFSIZE]; + char buf3[BUFSIZE]; + + + next = 0; + + /* search hrtimers */ + hq_open(); + timer_cnt = 0; +next_one: + i = 0; + + /* get the first node */ + if (VALID_MEMBER(hrtimer_base_pending)) + readmem((ulong)(base + OFFSET(hrtimer_base_pending) - + OFFSET(hrtimer_list) + OFFSET(hrtimer_node)), + KVADDR, &curr, sizeof(curr), "hrtimer_base pending", + FAULT_ON_ERROR); + else if (VALID_MEMBER(hrtimer_base_first)) + readmem((ulong)(base + OFFSET(hrtimer_base_first)), + KVADDR, &curr, sizeof(curr), "hrtimer_base first", + FAULT_ON_ERROR); + else if (VALID_MEMBER(hrtimer_clock_base_first)) + readmem((ulong)(base + OFFSET(hrtimer_clock_base_first)), + KVADDR, &curr, sizeof(curr), "hrtimer_clock_base first", + FAULT_ON_ERROR); + else + readmem((ulong)(base + OFFSET(hrtimer_clock_base_active) + + OFFSET(timerqueue_head_next)), + KVADDR, &curr, sizeof(curr), "hrtimer_clock base", + FAULT_ON_ERROR); + + while (curr && i < next) { + curr = rb_next(curr); + i++; + } + + if (curr) { + if (!hq_enter((ulong)curr)) { + error(INFO, "duplicate rb_node: %lx\n", curr); + return; + } + + timer_cnt++; + next++; + goto next_one; + } + + if (timer_cnt) { + timer_list = (ulong *)GETBUF(timer_cnt * sizeof(long)); + timer_cnt = retrieve_list(timer_list, timer_cnt); + } + hq_close(); + + /* dump hrtimers */ + /* print header */ + expires_len = get_expires_len(timer_cnt, timer_list); + if (expires_len < 8) + expires_len = 8; + + fprintf(fp, " %s %s %s\n", + mkstring(buf1, expires_len, CENTER|RJUST, "EXPIRES"), + mkstring(buf2, VADDR_PRLEN, CENTER|LJUST, "HRTIMER"), + mkstring(buf3, VADDR_PRLEN, CENTER|LJUST, "FUNCTION")); + + /* print timer */ + if (!timer_cnt) + fprintf(fp, " (empty)\n"); + + for (t = 0; t < timer_cnt; t++) { + if (VALID_MEMBER(timerqueue_node_node)) + timer = (void *)(timer_list[t] - + OFFSET(timerqueue_node_node) - + OFFSET(hrtimer_node)); + else + timer = (void *)(timer_list[t] - OFFSET(hrtimer_node)); + + print_timer(timer); + } +} + +static int +get_expires_len(const int timer_cnt, const ulong *timer_list) +{ + void *last_timer; + char buf[BUFSIZE]; + ulonglong softexpires, expires; + int len; + + len = 0; + + if (!timer_cnt) + return 8; + + if (VALID_MEMBER(timerqueue_node_node)) + last_timer = (void *)(timer_list[timer_cnt - 1] - + OFFSET(timerqueue_node_node) - + OFFSET(hrtimer_node)); + else + last_timer = (void *)(timer_list[timer_cnt -1] - + OFFSET(hrtimer_node)); + + /* expire is range */ + if (VALID_MEMBER(hrtimer_softexpires)) { + softexpires = ktime_to_ns(last_timer + OFFSET(hrtimer_softexpires)); + sprintf(buf, "%lld", softexpires); + len += strlen(buf) + 1; + } + + if (VALID_MEMBER(hrtimer_expires)) + expires = ktime_to_ns(last_timer + OFFSET(hrtimer_expires)); + else + expires = ktime_to_ns(last_timer + OFFSET(hrtimer_node) + + OFFSET(timerqueue_node_expires)); + + sprintf(buf, "%lld", expires); + len += strlen(buf); + + return len; +} + +/* + * print hrtimer and its related information + */ +static void +print_timer(const void *timer) +{ + ulonglong softexpires, expires; + + ulong function; + char buf1[BUFSIZE]; + char buf2[BUFSIZE]; + char buf3[BUFSIZE]; + + /* align information */ + fprintf(fp, " "); + + if (!accessible((ulong)timer)) { + fprintf(fp, "(destroyed timer)\n"); + 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)); + sprintf(buf1, "%lld-%lld", softexpires, expires); + } else { + sprintf(buf1, "%lld", expires); + } + fprintf(fp, "%s ", mkstring(buf2, expires_len, CENTER|RJUST, buf1)); + + fprintf(fp, "%lx ", (ulong)timer); + + if (readmem((ulong)(timer + OFFSET(hrtimer_function)), KVADDR, &function, + sizeof(function), "hrtimer function", QUIET|RETURN_ON_ERROR)) { + fprintf(fp, "%lx ", function); + fprintf(fp ,"<%s>", value_to_symstr(function, buf3, 0)); + } + + fprintf(fp, "\n"); +} + +/* + * convert ktime to ns, only need the address of ktime + */ +static ulonglong +ktime_to_ns(const void *ktime) +{ + ulonglong ns; + + ns = 0; + + if (accessible((ulong)ktime)) { + if (VALID_MEMBER(ktime_t_tv64)) { + readmem((ulong)ktime + OFFSET(ktime_t_tv64), KVADDR, &ns, + sizeof(ns), "ktime_t tv64", QUIET|RETURN_ON_ERROR); + } else { + uint32_t sec, nsec; + + sec = 0; + nsec = 0; + + readmem((ulong)ktime + OFFSET(ktime_t_sec), KVADDR, &sec, + sizeof(sec), "ktime_t sec", QUIET|RETURN_ON_ERROR); + + readmem((ulong)ktime + OFFSET(ktime_t_nsec), KVADDR, &nsec, + sizeof(nsec), "ktime_t nsec", QUIET|RETURN_ON_ERROR); + + ns = sec * 1000000000L + nsec; + } + } + + return ns; } /* diff --git a/symbols.c b/symbols.c index 4fb397c..c8e556b 100755 --- a/symbols.c +++ b/symbols.c @@ -8860,6 +8860,44 @@ dump_offset_table(char *spec, ulong makestruct) OFFSET(rt_rq_highest_prio)); fprintf(fp, " rt_rq_rt_nr_running: %ld\n", OFFSET(rt_rq_rt_nr_running)); + fprintf(fp, " hrtimer_cpu_base_clock_base: %ld\n", + OFFSET(hrtimer_cpu_base_clock_base)); + fprintf(fp, " hrtimer_clock_base_offset: %ld\n", + OFFSET(hrtimer_clock_base_offset)); + fprintf(fp, " hrtimer_clock_base_active: %ld\n", + OFFSET(hrtimer_clock_base_active)); + fprintf(fp, " hrtimer_clock_base_first: %ld\n", + OFFSET(hrtimer_clock_base_first)); + fprintf(fp, " hrtimer_clock_base_get_time: %ld\n", + OFFSET(hrtimer_clock_base_get_time)); + fprintf(fp, " hrtimer_base_first: %ld\n", + OFFSET(hrtimer_base_first)); + fprintf(fp, " hrtimer_base_pending: %ld\n", + OFFSET(hrtimer_base_pending)); + fprintf(fp, " hrtimer_base_get_time: %ld\n", + OFFSET(hrtimer_base_get_time)); + fprintf(fp, " hrtimer_node: %ld\n", + OFFSET(hrtimer_node)); + fprintf(fp, " hrtimer_list: %ld\n", + OFFSET(hrtimer_list)); + fprintf(fp, " hrtimer_softexpires: %ld\n", + OFFSET(hrtimer_softexpires)); + fprintf(fp, " hrtimer_expires: %ld\n", + OFFSET(hrtimer_expires)); + fprintf(fp, " hrtimer_function: %ld\n", + OFFSET(hrtimer_function)); + fprintf(fp, " timerqueue_head_next: %ld\n", + OFFSET(timerqueue_head_next)); + fprintf(fp, " timerqueue_node_expires: %ld\n", + OFFSET(timerqueue_node_expires)); + fprintf(fp, " timerqueue_node_node: %ld\n", + OFFSET(timerqueue_node_node)); + fprintf(fp, " ktime_t_tv64: %ld\n", + OFFSET(ktime_t_tv64)); + fprintf(fp, " ktime_t_sec: %ld\n", + OFFSET(ktime_t_sec)); + fprintf(fp, " ktime_t_nsec: %ld\n", + OFFSET(ktime_t_nsec)); fprintf(fp, "\n size_table:\n"); fprintf(fp, " page: %ld\n", SIZE(page)); @@ -9081,6 +9119,10 @@ dump_offset_table(char *spec, ulong makestruct) SIZE(task_group)); fprintf(fp, " vmap_area: %ld\n", SIZE(vmap_area)); + fprintf(fp, " hrtimer_clock_base: %ld\n", + SIZE(hrtimer_clock_base)); + fprintf(fp, " hrtimer_base: %ld\n", + SIZE(hrtimer_base)); fprintf(fp, "\n array_table:\n"); /* -- 1.7.1
>From 39a3075261697d472f21fe13f6f26dfd0583bde6 Mon Sep 17 00:00:00 2001 From: qiaonuohan <qiaonuohan@xxxxxxxxxxxxxx> Date: Mon, 11 Mar 2013 08:58:14 +0800 Subject: [PATCH 1/2] make rbtree manipulation functions global rbtree manipulation functions were only used by runq cmd. Now make them global and available to other commands. --- defs.h | 20 ++++++++++ task.c | 94 ---------------------------------------------- tools.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 148 insertions(+), 94 deletions(-) diff --git a/defs.h b/defs.h index 1f693c3..2993f2b 100755 --- a/defs.h +++ b/defs.h @@ -2256,6 +2256,20 @@ struct alias_data { /* command alias storage */ char argbuf[1]; }; +struct rb_node +{ + unsigned long rb_parent_color; +#define RB_RED 0 +#define RB_BLACK 1 + struct rb_node *rb_right; + struct rb_node *rb_left; +}; + +struct rb_root +{ + struct rb_node *rb_node; +}; + #define NUMBER_STACKFRAMES 4 #define SAVE_RETURN_ADDRESS(retaddr) \ @@ -4082,6 +4096,12 @@ uint16_t swap16(uint16_t, int); uint32_t swap32(uint32_t, int); int make_cpumask(char *, ulong *, int, int *); size_t strlcpy(char *, char *, size_t); +struct rb_node *rb_first(struct rb_root *); +struct rb_node *rb_parent(struct rb_node *, struct rb_node *); +struct rb_node *rb_right(struct rb_node *, struct rb_node *); +struct rb_node *rb_left(struct rb_node *, struct rb_node *); +struct rb_node *rb_next(struct rb_node *); +struct rb_node *rb_last(struct rb_root *); /* * symbols.c diff --git a/task.c b/task.c index fec9f6a..6fb2b4e 100755 --- a/task.c +++ b/task.c @@ -56,13 +56,6 @@ static void dump_runq(void); static void dump_on_rq_timestamp(void); static void dump_runqueues(void); static void dump_prio_array(int, ulong, char *); -struct rb_root; -static struct rb_node *rb_first(struct rb_root *); -struct rb_node; -static struct rb_node *rb_next(struct rb_node *); -static struct rb_node *rb_parent(struct rb_node *, struct rb_node *); -static struct rb_node *rb_right(struct rb_node *, struct rb_node *); -static struct rb_node *rb_left(struct rb_node *, struct rb_node *); static void dump_task_runq_entry(struct task_context *); static void print_group_header_fair(int, ulong, void *); static void print_parent_task_group_fair(void *, int); @@ -7529,93 +7522,6 @@ dump_prio_array(int which, ulong k_prio_array, char *u_prio_array) } } -/* - * CFS scheduler uses Red-Black trees to maintain run queue. - */ -struct rb_node -{ - unsigned long rb_parent_color; -#define RB_RED 0 -#define RB_BLACK 1 - struct rb_node *rb_right; - struct rb_node *rb_left; -}; - -struct rb_root -{ - struct rb_node *rb_node; -}; - -static struct rb_node * -rb_first(struct rb_root *root) -{ - struct rb_root rloc; - struct rb_node *n; - struct rb_node nloc; - - readmem((ulong)root, KVADDR, &rloc, sizeof(struct rb_root), - "rb_root", FAULT_ON_ERROR); - - n = rloc.rb_node; - if (!n) - return NULL; - while (rb_left(n, &nloc)) - n = nloc.rb_left; - - return n; -} - -static struct rb_node * -rb_parent(struct rb_node *node, struct rb_node *nloc) -{ - readmem((ulong)node, KVADDR, nloc, sizeof(struct rb_node), - "rb_node", FAULT_ON_ERROR); - - return (struct rb_node *)(nloc->rb_parent_color & ~3); -} - -static struct rb_node * -rb_right(struct rb_node *node, struct rb_node *nloc) -{ - readmem((ulong)node, KVADDR, nloc, sizeof(struct rb_node), - "rb_node", FAULT_ON_ERROR); - - return nloc->rb_right; -} - -static struct rb_node * -rb_left(struct rb_node *node, struct rb_node *nloc) -{ - readmem((ulong)node, KVADDR, nloc, sizeof(struct rb_node), - "rb_node", FAULT_ON_ERROR); - - return nloc->rb_left; -} - -static struct rb_node * -rb_next(struct rb_node *node) -{ - struct rb_node nloc; - struct rb_node *parent; - - parent = rb_parent(node, &nloc); - - if (parent == node) - return NULL; - - if (nloc.rb_right) { - node = nloc.rb_right; - while (rb_left(node, &nloc)) - node = nloc.rb_left; - return node; - } - - while ((parent = rb_parent(node, &nloc)) && (node == rb_right(parent, &nloc))) - node = parent; - - return parent; -} - #define MAX_GROUP_NUM 200 struct task_group_info { int use; diff --git a/tools.c b/tools.c index d8dd04a..066f7fa 100755 --- a/tools.c +++ b/tools.c @@ -5555,3 +5555,131 @@ strlcpy(char *dest, char *src, size_t size) return ret; } +struct rb_node * +rb_first(struct rb_root *root) +{ + struct rb_root rloc; + struct rb_node *n; + struct rb_node nloc; + + readmem((ulong)root, KVADDR, &rloc, sizeof(struct rb_root), + "rb_root", FAULT_ON_ERROR); + + n = rloc.rb_node; + if (!n) + return NULL; + while (rb_left(n, &nloc)) + n = nloc.rb_left; + + return n; +} + +struct rb_node * +rb_parent(struct rb_node *node, struct rb_node *nloc) +{ + readmem((ulong)node, KVADDR, nloc, sizeof(struct rb_node), + "rb_node", FAULT_ON_ERROR); + + return (struct rb_node *)(nloc->rb_parent_color & ~3); +} + +struct rb_node * +rb_right(struct rb_node *node, struct rb_node *nloc) +{ + readmem((ulong)node, KVADDR, nloc, sizeof(struct rb_node), + "rb_node", FAULT_ON_ERROR); + + return nloc->rb_right; +} + +struct rb_node * +rb_left(struct rb_node *node, struct rb_node *nloc) +{ + readmem((ulong)node, KVADDR, nloc, sizeof(struct rb_node), + "rb_node", FAULT_ON_ERROR); + + return nloc->rb_left; +} + +struct rb_node * +rb_next(struct rb_node *node) +{ + struct rb_node nloc; + struct rb_node *parent; + + /* node is destroyed */ + if (!accessible((ulong)node)) + return NULL; + + parent = rb_parent(node, &nloc); + + if (parent == node) + return NULL; + + if (nloc.rb_right) { + /* rb_right is destroyed */ + if (!accessible((ulong)nloc.rb_right)) + return NULL; + + node = nloc.rb_right; + while (rb_left(node, &nloc)) { + /* rb_left is destroyed */ + if (!accessible((ulong)nloc.rb_left)) + return NULL; + node = nloc.rb_left; + } + return node; + } + + while ((parent = rb_parent(node, &nloc))) { + /* parent is destroyed */ + if (!accessible((ulong)parent)) + return NULL; + + + if (node != rb_right(parent, &nloc)) + break; + + node = parent; + } + + return parent; +} + +struct rb_node * +rb_last(struct rb_root *root) +{ + struct rb_node *node; + struct rb_node nloc; + + /* meet destroyed data */ + if (!accessible((ulong)(root + OFFSET(rb_root_rb_node)))) + return NULL; + + readmem((ulong)(root + OFFSET(rb_root_rb_node)), KVADDR, &node, + sizeof(node), "rb_root node", FAULT_ON_ERROR); + + while (1) { + if (!node) + break; + + /* meet destroyed data */ + if (!accessible((ulong)node)) + return NULL; + + readmem((ulong)node, KVADDR, &nloc, sizeof(struct rb_node), + "rb_node last", FAULT_ON_ERROR); + + /* meet the last one */ + if (!nloc.rb_right) + break; + + /* meet destroyed data */ + if (!!accessible((ulong)nloc.rb_right)) + break; + + node = nloc.rb_right; + } + + return node; +} -- 1.7.1
-- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility