|
@@ -20,6 +20,13 @@
|
|
|
|
|
|
#include <asm/uaccess.h>
|
|
|
|
|
|
+
|
|
|
+struct timer_list_iter {
|
|
|
+ int cpu;
|
|
|
+ bool second_pass;
|
|
|
+ u64 now;
|
|
|
+};
|
|
|
+
|
|
|
typedef void (*print_fn_t)(struct seq_file *m, unsigned int *classes);
|
|
|
|
|
|
DECLARE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases);
|
|
@@ -247,43 +254,101 @@ static void timer_list_show_tickdevices_header(struct seq_file *m)
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
-static int timer_list_show(struct seq_file *m, void *v)
|
|
|
+static inline void timer_list_header(struct seq_file *m, u64 now)
|
|
|
{
|
|
|
- u64 now = ktime_to_ns(ktime_get());
|
|
|
- int cpu;
|
|
|
-
|
|
|
SEQ_printf(m, "Timer List Version: v0.7\n");
|
|
|
SEQ_printf(m, "HRTIMER_MAX_CLOCK_BASES: %d\n", HRTIMER_MAX_CLOCK_BASES);
|
|
|
SEQ_printf(m, "now at %Ld nsecs\n", (unsigned long long)now);
|
|
|
SEQ_printf(m, "\n");
|
|
|
+}
|
|
|
+
|
|
|
+static int timer_list_show(struct seq_file *m, void *v)
|
|
|
+{
|
|
|
+ struct timer_list_iter *iter = v;
|
|
|
+ u64 now = ktime_to_ns(ktime_get());
|
|
|
+
|
|
|
+ if (iter->cpu == -1 && !iter->second_pass)
|
|
|
+ timer_list_header(m, now);
|
|
|
+ else if (!iter->second_pass)
|
|
|
+ print_cpu(m, iter->cpu, iter->now);
|
|
|
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
|
|
|
+ else if (iter->cpu == -1 && iter->second_pass)
|
|
|
+ timer_list_show_tickdevices_header(m);
|
|
|
+ else
|
|
|
+ print_tickdevice(m, tick_get_device(iter->cpu), iter->cpu);
|
|
|
+#endif
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+void sysrq_timer_list_show(void)
|
|
|
+{
|
|
|
+ u64 now = ktime_to_ns(ktime_get());
|
|
|
+ int cpu;
|
|
|
+
|
|
|
+ timer_list_header(NULL, now);
|
|
|
|
|
|
for_each_online_cpu(cpu)
|
|
|
- print_cpu(m, cpu, now);
|
|
|
+ print_cpu(NULL, cpu, now);
|
|
|
|
|
|
#ifdef CONFIG_GENERIC_CLOCKEVENTS
|
|
|
- timer_list_show_tickdevices_header(m);
|
|
|
+ timer_list_show_tickdevices_header(NULL);
|
|
|
for_each_online_cpu(cpu)
|
|
|
- print_tickdevice(m, tick_get_device(cpu), cpu);
|
|
|
+ print_tickdevice(NULL, tick_get_device(cpu), cpu);
|
|
|
#endif
|
|
|
+ return;
|
|
|
+}
|
|
|
|
|
|
- return 0;
|
|
|
+static void *timer_list_start(struct seq_file *file, loff_t *offset)
|
|
|
+{
|
|
|
+ struct timer_list_iter *iter = file->private;
|
|
|
+
|
|
|
+ if (!*offset) {
|
|
|
+ iter->cpu = -1;
|
|
|
+ iter->now = ktime_to_ns(ktime_get());
|
|
|
+ } else if (iter->cpu >= nr_cpu_ids) {
|
|
|
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
|
|
|
+ if (!iter->second_pass) {
|
|
|
+ iter->cpu = -1;
|
|
|
+ iter->second_pass = true;
|
|
|
+ } else
|
|
|
+ return NULL;
|
|
|
+#else
|
|
|
+ return NULL;
|
|
|
+#endif
|
|
|
+ }
|
|
|
+ return iter;
|
|
|
}
|
|
|
|
|
|
-void sysrq_timer_list_show(void)
|
|
|
+static void *timer_list_next(struct seq_file *file, void *v, loff_t *offset)
|
|
|
{
|
|
|
- timer_list_show(NULL, NULL);
|
|
|
+ struct timer_list_iter *iter = file->private;
|
|
|
+ iter->cpu = cpumask_next(iter->cpu, cpu_online_mask);
|
|
|
+ ++*offset;
|
|
|
+ return timer_list_start(file, offset);
|
|
|
}
|
|
|
|
|
|
+static void timer_list_stop(struct seq_file *seq, void *v)
|
|
|
+{
|
|
|
+}
|
|
|
+
|
|
|
+static const struct seq_operations timer_list_sops = {
|
|
|
+ .start = timer_list_start,
|
|
|
+ .next = timer_list_next,
|
|
|
+ .stop = timer_list_stop,
|
|
|
+ .show = timer_list_show,
|
|
|
+};
|
|
|
+
|
|
|
static int timer_list_open(struct inode *inode, struct file *filp)
|
|
|
{
|
|
|
- return single_open(filp, timer_list_show, NULL);
|
|
|
+ return seq_open_private(filp, &timer_list_sops,
|
|
|
+ sizeof(struct timer_list_iter));
|
|
|
}
|
|
|
|
|
|
static const struct file_operations timer_list_fops = {
|
|
|
.open = timer_list_open,
|
|
|
.read = seq_read,
|
|
|
.llseek = seq_lseek,
|
|
|
- .release = single_release,
|
|
|
+ .release = seq_release_private,
|
|
|
};
|
|
|
|
|
|
static int __init init_timer_list_procfs(void)
|