Module: xenomai-head
Branch: master
Commit: 5a8336d7d700ba98c43edf0d253234348572696b
URL:    
http://git.xenomai.org/?p=xenomai-head.git;a=commit;h=5a8336d7d700ba98c43edf0d253234348572696b

Author: Philippe Gerum <r...@xenomai.org>
Date:   Wed Jun  3 11:13:28 2009 +0200

Introduce /proc/xenomai/schedclasses

This PROC_FS hierarchy provides runtime information which relate to
the scheduling classes built into the system. Each scheduler may
export class-specific data there.

---

 include/nucleus/sched.h       |    9 ++
 include/nucleus/thread.h      |   59 +------------
 include/nucleus/timebase.h    |   20 ++--
 include/nucleus/timer.h       |    2 +
 ksrc/nucleus/Makefile         |   12 ++-
 ksrc/nucleus/sched-rt.c       |  183 +++++++++++++++++++++++++++++++++++++++
 ksrc/nucleus/sched-sporadic.c |  191 +++++++++++++++++++++++++++++++++++++++++
 ksrc/nucleus/sched-tp.c       |  170 ++++++++++++++++++++++++++++++++++++
 ksrc/nucleus/sched.c          |  108 +++++++++++++++++------
 ksrc/nucleus/thread.c         |  136 +++++++++++++++++++----------
 ksrc/nucleus/timer.c          |   34 +++++++
 11 files changed, 781 insertions(+), 143 deletions(-)

diff --git a/include/nucleus/sched.h b/include/nucleus/sched.h
index 2db94ce..125a49c 100644
--- a/include/nucleus/sched.h
+++ b/include/nucleus/sched.h
@@ -144,6 +144,12 @@ struct xnsched_class {
        void (*sched_suspend_rpi)(struct xnthread *thread);
        void (*sched_resume_rpi)(struct xnthread *thread);
 #endif
+#ifdef CONFIG_PROC_FS
+       void (*sched_init_proc)(struct proc_dir_entry *root);
+       void (*sched_cleanup_proc)(struct proc_dir_entry *root);
+       struct proc_dir_entry *proc;
+#endif
+       int nthreads;
        struct xnsched_class *next;
        int weight;
        const char *name;
@@ -394,6 +400,8 @@ static inline void xnsched_forget(struct xnthread *thread)
 {
        struct xnsched_class *sched_class = thread->base_class;
 
+       --sched_class->nthreads;
+
        if (sched_class->sched_forget)
                sched_class->sched_forget(thread);
 }
@@ -505,6 +513,7 @@ static inline void xnsched_trackprio(struct xnthread 
*thread,
 
 static inline void xnsched_forget(struct xnthread *thread)
 {
+       --thread->base_class->nthreads;
        __xnsched_rt_forget(thread);
 }
 
diff --git a/include/nucleus/thread.h b/include/nucleus/thread.h
index 4e17000..fbd7fec 100644
--- a/include/nucleus/thread.h
+++ b/include/nucleus/thread.h
@@ -387,66 +387,13 @@ int xnthread_init(struct xnthread *thread,
 
 void xnthread_cleanup_tcb(xnthread_t *thread);
 
-char *xnthread_symbolic_status(xnflags_t status, char *buf, int size);
+char *xnthread_format_status(xnflags_t status, char *buf, int size);
 
 int *xnthread_get_errno_location(xnthread_t *thread);
 
-static inline xnticks_t xnthread_get_timeout(xnthread_t *thread, xnticks_t 
tsc_ns)
-{
-       xnticks_t timeout;
-       xntimer_t *timer;
-
-       if (!xnthread_test_state(thread,XNDELAY))
-               return 0LL;
-
-       if (xntimer_running_p(&thread->rtimer))
-               timer = &thread->rtimer;
-       else if (xntimer_running_p(&thread->ptimer))
-               timer = &thread->ptimer;
-       else
-               return 0LL;
-
-       /*
-        * The caller should have masked IRQs while collecting the
-        * timeout(s), so no tick could be announced in the meantime,
-        * and all timeouts would always use the same epoch
-        * value. Obviously, this can't be a valid assumption for
-        * aperiodic timers, which values are based on the hardware
-        * TSC, and as such the current time will change regardless of
-        * the interrupt state; for this reason, we use the "tsc_ns"
-        * input parameter (TSC converted to nanoseconds) the caller
-        * has passed us as the epoch value instead.
-        */
-
-       if (xntbase_periodic_p(xnthread_time_base(thread)))
-               return xntimer_get_timeout(timer);
-
-       timeout = xntimer_get_date(timer);
-
-       if (timeout <= tsc_ns)
-               return 1;
-
-       return timeout - tsc_ns;
-}
+xnticks_t xnthread_get_timeout(xnthread_t *thread, xnticks_t tsc_ns);
 
-static inline xnticks_t xnthread_get_period(xnthread_t *thread)
-{
-       xnticks_t period = 0;
-
-       /*
-        * The current thread period might be:
-        * - the value of the timer interval for periodic threads (ns/ticks)
-        * - or, the value of the alloted round-robin quantum (ticks)
-        * - or zero, meaning "no periodic activity".
-        */
-       
-       if (xntimer_running_p(&thread->ptimer))
-               period = xntimer_get_interval(&thread->ptimer);
-       else if (xnthread_test_state(thread,XNRRB))
-               period = xnthread_time_slice(thread);
-
-       return period;
-}
+xnticks_t xnthread_get_period(xnthread_t *thread);
 
 #ifdef CONFIG_XENO_OPT_REGISTRY
 static inline int xnthread_register(xnthread_t *thread, const char *name)
diff --git a/include/nucleus/timebase.h b/include/nucleus/timebase.h
index 83f8011..5c8678e 100644
--- a/include/nucleus/timebase.h
+++ b/include/nucleus/timebase.h
@@ -34,16 +34,16 @@ struct xntimer;
 
 typedef struct xntbops {
 
-    int (*start_timer)(struct xntimer *timer,
-                      xnticks_t value,
-                      xnticks_t interval,
-                      xntmode_t mode);
-    void (*stop_timer)(struct xntimer *timer);
-    xnticks_t (*get_timer_date)(struct xntimer *timer);
-    xnticks_t (*get_timer_timeout)(struct xntimer *timer);
-    xnticks_t (*get_timer_interval)(struct xntimer *timer);
-    xnticks_t (*get_timer_raw_expiry)(struct xntimer *timer);
-    void (*move_timer)(struct xntimer *timer);
+       int (*start_timer)(struct xntimer *timer,
+                          xnticks_t value,
+                          xnticks_t interval,
+                          xntmode_t mode);
+       void (*stop_timer)(struct xntimer *timer);
+       xnticks_t (*get_timer_date)(struct xntimer *timer);
+       xnticks_t (*get_timer_timeout)(struct xntimer *timer);
+       xnticks_t (*get_timer_interval)(struct xntimer *timer);
+       xnticks_t (*get_timer_raw_expiry)(struct xntimer *timer);
+       void (*move_timer)(struct xntimer *timer);
 
 } xntbops_t;
 
diff --git a/include/nucleus/timer.h b/include/nucleus/timer.h
index adcfdc7..ef05822 100644
--- a/include/nucleus/timer.h
+++ b/include/nucleus/timer.h
@@ -745,6 +745,8 @@ int xntimer_migrate(xntimer_t *timer,
 
 #define xntimer_set_sched(timer, sched)        xntimer_migrate(timer, sched)
 
+char *xntimer_format_time(xnticks_t value, int periodic,
+                         char *buf, size_t bufsz);
 #ifdef __cplusplus
 }
 #endif
diff --git a/ksrc/nucleus/Makefile b/ksrc/nucleus/Makefile
index 66c493d..fc40dd5 100644
--- a/ksrc/nucleus/Makefile
+++ b/ksrc/nucleus/Makefile
@@ -5,7 +5,7 @@ ifeq ($(PATCHLEVEL),6)
 obj-$(CONFIG_XENO_OPT_NUCLEUS) += xeno_nucleus.o
 
 xeno_nucleus-y := \
-       heap.o intr.o module.o pod.o \
+       heap.o intr.o pod.o \
        synch.o thread.o timebase.o timer.o sched.o
 
 # CAUTION: the declaration order of scheduling classes is
@@ -21,6 +21,10 @@ xeno_nucleus-$(CONFIG_XENO_OPT_MAP) += map.o
 xeno_nucleus-$(CONFIG_XENO_OPT_REGISTRY) += registry.o
 xeno_nucleus-$(CONFIG_XENO_OPT_SELECT) += select.o
 
+# CAUTION: this module shall appear last, so that dependencies may
+# exist on initcalls defined by other object files.
+xeno_nucleus-y += module.o
+
 EXTRA_CFLAGS += -D__IN_XENOMAI__ -Iinclude/xenomai
 
 else
@@ -34,7 +38,7 @@ obj-$(CONFIG_XENO_OPT_NUCLEUS) := xeno_nucleus.o
 list-multi := xeno_nucleus.o
 
 xeno_nucleus-objs := \
-       heap.o intr.o module.o pod.o \
+       heap.o intr.o pod.o \
        synch.o thread.o timebase.o timer.o sched.o
 
 # CAUTION: the declaration order of scheduling classes is
@@ -51,6 +55,10 @@ opt_objs-$(CONFIG_XENO_OPT_SELECT) += select.o
 
 xeno_nucleus-objs += $(opt_objs-y)
 
+# CAUTION: this module shall appear last, so that dependencies may
+# exist on initcalls defined by other object files.
+xeno_nucleus-objs += module.o
+
 export-objs := $(xeno_nucleus-objs)
 
 EXTRA_CFLAGS += -D__IN_XENOMAI__ -I$(TOPDIR)/include/xenomai 
-I$(TOPDIR)/include/xenomai/compat
diff --git a/ksrc/nucleus/sched-rt.c b/ksrc/nucleus/sched-rt.c
index 65d37ff..dc23163 100644
--- a/ksrc/nucleus/sched-rt.c
+++ b/ksrc/nucleus/sched-rt.c
@@ -155,6 +155,185 @@ static struct xnthread *xnsched_rt_peek_rpi(struct 
xnsched *sched)
 
 #endif /* CONFIG_XENO_OPT_PRIOCPL */
 
+#ifdef CONFIG_PROC_FS
+
+#include <linux/seq_file.h>
+
+struct xnsched_rt_seq_iterator {
+       xnticks_t start_time;
+       int nentries;
+       struct xnsched_rt_info {
+               int cpu;
+               pid_t pid;
+               char name[XNOBJECT_NAME_LEN];
+               xnticks_t period;
+               int periodic;
+               int cprio;
+               int dnprio;
+       } sched_info[1];
+};
+
+static void *xnsched_rt_seq_start(struct seq_file *seq, loff_t *pos)
+{
+       struct xnsched_rt_seq_iterator *iter = seq->private;
+
+       if (*pos > iter->nentries)
+               return NULL;
+
+       if (*pos == 0)
+               return SEQ_START_TOKEN;
+
+       return iter->sched_info + *pos - 1;
+}
+
+static void *xnsched_rt_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+       struct xnsched_rt_seq_iterator *iter = seq->private;
+
+       ++*pos;
+
+       if (*pos > iter->nentries)
+               return NULL;
+
+       return iter->sched_info + *pos - 1;
+}
+
+static void xnsched_rt_seq_stop(struct seq_file *seq, void *v)
+{
+}
+
+static int xnsched_rt_seq_show(struct seq_file *seq, void *v)
+{
+       char pribuf[16], ptbuf[16];
+       struct xnsched_rt_info *p;
+
+       if (v == SEQ_START_TOKEN)
+               seq_printf(seq, "%-3s  %-6s %-8s %-10s %s\n",
+                          "CPU", "PID", "PRI", "PERIOD", "NAME");
+       else {
+               p = v;
+
+               if (p->cprio != p->dnprio)
+                       snprintf(pribuf, sizeof(pribuf), "%3d(%d)",
+                                p->cprio, p->dnprio);
+               else
+                       snprintf(pribuf, sizeof(pribuf), "%3d", p->cprio);
+
+               xntimer_format_time(p->period, p->periodic, ptbuf, 
sizeof(ptbuf));
+
+               seq_printf(seq, "%3u  %-6d %-8s %-10s %s\n",
+                          p->cpu,
+                          p->pid,
+                          pribuf,
+                          ptbuf,
+                          p->name);
+       }
+
+       return 0;
+}
+
+static struct seq_operations xnsched_rt_seq_op = {
+       .start = &xnsched_rt_seq_start,
+       .next = &xnsched_rt_seq_next,
+       .stop = &xnsched_rt_seq_stop,
+       .show = &xnsched_rt_seq_show
+};
+
+static int xnsched_rt_seq_open(struct inode *inode, struct file *file)
+{
+       struct xnsched_rt_seq_iterator *iter = NULL;
+       struct xnsched_rt_info *p;
+       struct xnholder *holder;
+       struct xnthread *thread;
+       int ret, count, rev, n;
+       struct seq_file *seq;
+       spl_t s;
+
+       if (!xnpod_active_p())
+               return -ESRCH;
+
+       xnlock_get_irqsave(&nklock, s);
+
+      restart:
+       rev = nkpod->threadq_rev;
+       count = xnsched_class_rt.nthreads;
+       holder = getheadq(&nkpod->threadq);
+
+       xnlock_put_irqrestore(&nklock, s);
+
+       if (iter)
+               kfree(iter);
+
+       if (count == 0)
+               return -ESRCH;
+
+       iter = kmalloc(sizeof(*iter)
+                      + (count - 1) * sizeof(struct xnsched_rt_info),
+                      GFP_KERNEL);
+       if (iter == NULL)
+               return -ENOMEM;
+
+       ret = seq_open(file, &xnsched_rt_seq_op);
+       if (ret) {
+               kfree(iter);
+               return ret;
+       }
+
+       iter->nentries = 0;
+       iter->start_time = xntbase_get_jiffies(&nktbase);
+
+       while (holder) {
+               xnlock_get_irqsave(&nklock, s);
+
+               if (nkpod->threadq_rev != rev)
+                       goto restart;
+
+               rev = nkpod->threadq_rev;
+               thread = link2thread(holder, glink);
+
+               if (thread->base_class != &xnsched_class_rt)
+                       goto skip;
+
+               n = iter->nentries++;
+               p = iter->sched_info + n;
+               p->cpu = xnsched_cpu(thread->sched);
+               p->pid = xnthread_user_pid(thread);
+               memcpy(p->name, thread->name, sizeof(p->name));
+               p->cprio = thread->cprio;
+               p->dnprio = xnthread_get_denormalized_prio(thread, 
thread->cprio);
+               p->period = xnthread_get_period(thread);
+               p->periodic = xntbase_periodic_p(xnthread_time_base(thread));
+       skip:
+               holder = nextq(&nkpod->threadq, holder);
+               xnlock_put_irqrestore(&nklock, s);
+       }
+
+       seq = file->private_data;
+       seq->private = iter;
+
+       return 0;
+}
+
+static struct file_operations xnsched_rt_seq_operations = {
+       .owner = THIS_MODULE,
+       .open = xnsched_rt_seq_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release_private,
+};
+
+void xnsched_rt_init_proc(struct proc_dir_entry *root)
+{
+       rthal_add_proc_seq("threads", &xnsched_rt_seq_operations, 0, root);
+}
+
+void xnsched_rt_cleanup_proc(struct proc_dir_entry *root)
+{
+       remove_proc_entry("threads", root);
+}
+
+#endif /* CONFIG_PROC_FS */
+
 struct xnsched_class xnsched_class_rt = {
 
        .sched_init             =       xnsched_rt_init,
@@ -176,6 +355,10 @@ struct xnsched_class xnsched_class_rt = {
        .sched_suspend_rpi      =       NULL,
        .sched_resume_rpi       =       NULL,
 #endif
+#ifdef CONFIG_PROC_FS
+       .sched_init_proc        =       xnsched_rt_init_proc,
+       .sched_cleanup_proc     =       xnsched_rt_cleanup_proc,
+#endif
        .weight                 =       XNSCHED_CLASS_WEIGHT(1),
        .name                   =       "rt"
 };
diff --git a/ksrc/nucleus/sched-sporadic.c b/ksrc/nucleus/sched-sporadic.c
index 39653a7..57fc357 100644
--- a/ksrc/nucleus/sched-sporadic.c
+++ b/ksrc/nucleus/sched-sporadic.c
@@ -413,6 +413,193 @@ static void xnsched_sporadic_resume_rpi(struct xnthread 
*thread)
 
 #endif /* CONFIG_XENO_OPT_PRIOCPL */
 
+#ifdef CONFIG_PROC_FS
+
+#include <linux/seq_file.h>
+
+struct xnsched_sporadic_seq_iterator {
+       xnticks_t start_time;
+       int nentries;
+       struct xnsched_sporadic_info {
+               int cpu;
+               pid_t pid;
+               char name[XNOBJECT_NAME_LEN];
+               int current_prio;
+               int low_prio;
+               int normal_prio;
+               int periodic;
+               xnticks_t period;
+               xnticks_t timeout;
+               xnticks_t budget;
+       } sched_info[1];
+};
+
+static void *xnsched_sporadic_seq_start(struct seq_file *seq, loff_t *pos)
+{
+       struct xnsched_sporadic_seq_iterator *iter = seq->private;
+
+       if (*pos > iter->nentries)
+               return NULL;
+
+       if (*pos == 0)
+               return SEQ_START_TOKEN;
+
+       return iter->sched_info + *pos - 1;
+}
+
+static void *xnsched_sporadic_seq_next(struct seq_file *seq, void *v, loff_t 
*pos)
+{
+       struct xnsched_sporadic_seq_iterator *iter = seq->private;
+
+       ++*pos;
+
+       if (*pos > iter->nentries)
+               return NULL;
+
+       return iter->sched_info + *pos - 1;
+}
+
+static void xnsched_sporadic_seq_stop(struct seq_file *seq, void *v)
+{
+}
+
+static int xnsched_sporadic_seq_show(struct seq_file *seq, void *v)
+{
+       char lpbuf[16], npbuf[16], ptbuf[16], btbuf[16];
+       struct xnsched_sporadic_info *p;
+
+       if (v == SEQ_START_TOKEN)
+               seq_printf(seq, "%-3s  %-6s %-4s %-4s  %-10s %-10s %s\n",
+                          "CPU", "PID", "LPRI", "NPRI", "BUDGET", "PERIOD", 
"NAME");
+       else {
+               p = v;
+
+               snprintf(lpbuf, sizeof(lpbuf), "%3d%c",
+                        p->low_prio, p->current_prio == p->low_prio ? '*' : ' 
');
+
+               snprintf(npbuf, sizeof(npbuf), "%3d%c",
+                        p->normal_prio, p->current_prio == p->normal_prio ? 
'*' : ' ');
+
+               xntimer_format_time(p->period, p->periodic, ptbuf, 
sizeof(ptbuf));
+               xntimer_format_time(p->budget, p->periodic, btbuf, 
sizeof(btbuf));
+
+               seq_printf(seq, "%3u  %-6d %-4s %-4s  %-10s %-10s %s\n",
+                          p->cpu,
+                          p->pid,
+                          lpbuf,
+                          npbuf,
+                          btbuf,
+                          ptbuf,
+                          p->name);
+       }
+
+       return 0;
+}
+
+static struct seq_operations xnsched_sporadic_seq_op = {
+       .start = &xnsched_sporadic_seq_start,
+       .next = &xnsched_sporadic_seq_next,
+       .stop = &xnsched_sporadic_seq_stop,
+       .show = &xnsched_sporadic_seq_show
+};
+
+static int xnsched_sporadic_seq_open(struct inode *inode, struct file *file)
+{
+       struct xnsched_sporadic_seq_iterator *iter = NULL;
+       struct xnsched_sporadic_info *p;
+       struct xnholder *holder;
+       struct xnthread *thread;
+       int ret, count, rev, n;
+       struct seq_file *seq;
+       spl_t s;
+
+       if (!xnpod_active_p())
+               return -ESRCH;
+
+       xnlock_get_irqsave(&nklock, s);
+
+      restart:
+       rev = nkpod->threadq_rev;
+       count = xnsched_class_sporadic.nthreads;
+       holder = getheadq(&nkpod->threadq);
+
+       xnlock_put_irqrestore(&nklock, s);
+
+       if (iter)
+               kfree(iter);
+
+       if (count == 0)
+               return -ESRCH;
+
+       iter = kmalloc(sizeof(*iter)
+                      + (count - 1) * sizeof(struct xnsched_sporadic_info),
+                      GFP_KERNEL);
+       if (iter == NULL)
+               return -ENOMEM;
+
+       ret = seq_open(file, &xnsched_sporadic_seq_op);
+       if (ret) {
+               kfree(iter);
+               return ret;
+       }
+
+       iter->nentries = 0;
+       iter->start_time = xntbase_get_jiffies(&nktbase);
+
+       while (holder) {
+               xnlock_get_irqsave(&nklock, s);
+
+               if (nkpod->threadq_rev != rev)
+                       goto restart;
+
+               rev = nkpod->threadq_rev;
+               thread = link2thread(holder, glink);
+
+               if (thread->base_class != &xnsched_class_sporadic)
+                       goto skip;
+
+               n = iter->nentries++;
+               p = iter->sched_info + n;
+               p->cpu = xnsched_cpu(thread->sched);
+               p->pid = xnthread_user_pid(thread);
+               memcpy(p->name, thread->name, sizeof(p->name));
+               p->current_prio = thread->cprio;
+               p->low_prio = thread->pss->param.low_prio;
+               p->normal_prio = thread->pss->param.normal_prio;
+               p->period = xnthread_get_period(thread);
+               p->budget = thread->pss->param.init_budget;
+               p->periodic = xntbase_periodic_p(xnthread_time_base(thread));
+       skip:
+               holder = nextq(&nkpod->threadq, holder);
+               xnlock_put_irqrestore(&nklock, s);
+       }
+
+       seq = file->private_data;
+       seq->private = iter;
+
+       return 0;
+}
+
+static struct file_operations xnsched_sporadic_seq_operations = {
+       .owner = THIS_MODULE,
+       .open = xnsched_sporadic_seq_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release_private,
+};
+
+void xnsched_sporadic_init_proc(struct proc_dir_entry *root)
+{
+       rthal_add_proc_seq("threads", &xnsched_sporadic_seq_operations, 0, 
root);
+}
+
+void xnsched_sporadic_cleanup_proc(struct proc_dir_entry *root)
+{
+       remove_proc_entry("threads", root);
+}
+
+#endif /* CONFIG_PROC_FS */
+
 struct xnsched_class xnsched_class_sporadic = {
 
        .sched_init             =       xnsched_sporadic_init,
@@ -435,6 +622,10 @@ struct xnsched_class xnsched_class_sporadic = {
        .sched_suspend_rpi      =       xnsched_sporadic_suspend_rpi,
        .sched_resume_rpi       =       xnsched_sporadic_resume_rpi,
 #endif
+#ifdef CONFIG_PROC_FS
+       .sched_init_proc        =       xnsched_sporadic_init_proc,
+       .sched_cleanup_proc     =       xnsched_sporadic_cleanup_proc,
+#endif
        .weight                 =       XNSCHED_CLASS_WEIGHT(1),
        .name                   =       "pss"
 };
diff --git a/ksrc/nucleus/sched-tp.c b/ksrc/nucleus/sched-tp.c
index 821141f..3d40c76 100644
--- a/ksrc/nucleus/sched-tp.c
+++ b/ksrc/nucleus/sched-tp.c
@@ -277,6 +277,172 @@ int xnsched_tp_get_partition(struct xnsched *sched)
 }
 EXPORT_SYMBOL_GPL(xnsched_tp_get_partition);
 
+#ifdef CONFIG_PROC_FS
+
+#include <linux/seq_file.h>
+
+struct xnsched_tp_seq_iterator {
+       xnticks_t start_time;
+       int nentries;
+       struct xnsched_tp_info {
+               int cpu;
+               pid_t pid;
+               char name[XNOBJECT_NAME_LEN];
+               int prio;
+               int ptid;
+       } sched_info[1];
+};
+
+static void *xnsched_tp_seq_start(struct seq_file *seq, loff_t *pos)
+{
+       struct xnsched_tp_seq_iterator *iter = seq->private;
+
+       if (*pos > iter->nentries)
+               return NULL;
+
+       if (*pos == 0)
+               return SEQ_START_TOKEN;
+
+       return iter->sched_info + *pos - 1;
+}
+
+static void *xnsched_tp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+       struct xnsched_tp_seq_iterator *iter = seq->private;
+
+       ++*pos;
+
+       if (*pos > iter->nentries)
+               return NULL;
+
+       return iter->sched_info + *pos - 1;
+}
+
+static void xnsched_tp_seq_stop(struct seq_file *seq, void *v)
+{
+}
+
+static int xnsched_tp_seq_show(struct seq_file *seq, void *v)
+{
+       struct xnsched_tp_info *p;
+
+       if (v == SEQ_START_TOKEN)
+               seq_printf(seq, "%-3s  %-6s %-4s %-4s  %s\n",
+                          "CPU", "PID", "PTID", "PRI", "NAME");
+       else {
+               p = v;
+
+               seq_printf(seq, "%3u  %-6d %-4d %-4d  %s\n",
+                          p->cpu,
+                          p->pid,
+                          p->ptid,
+                          p->prio,
+                          p->name);
+       }
+
+       return 0;
+}
+
+static struct seq_operations xnsched_tp_seq_op = {
+       .start = &xnsched_tp_seq_start,
+       .next = &xnsched_tp_seq_next,
+       .stop = &xnsched_tp_seq_stop,
+       .show = &xnsched_tp_seq_show
+};
+
+static int xnsched_tp_seq_open(struct inode *inode, struct file *file)
+{
+       struct xnsched_tp_seq_iterator *iter = NULL;
+       struct xnsched_tp_info *p;
+       struct xnholder *holder;
+       struct xnthread *thread;
+       int ret, count, rev, n;
+       struct seq_file *seq;
+       spl_t s;
+
+       if (!xnpod_active_p())
+               return -ESRCH;
+
+       xnlock_get_irqsave(&nklock, s);
+
+      restart:
+       rev = nkpod->threadq_rev;
+       count = xnsched_class_tp.nthreads;
+       holder = getheadq(&nkpod->threadq);
+
+       xnlock_put_irqrestore(&nklock, s);
+
+       if (iter)
+               kfree(iter);
+
+       if (count == 0)
+               return -ESRCH;
+
+       iter = kmalloc(sizeof(*iter)
+                      + (count - 1) * sizeof(struct xnsched_tp_info),
+                      GFP_KERNEL);
+       if (iter == NULL)
+               return -ENOMEM;
+
+       ret = seq_open(file, &xnsched_tp_seq_op);
+       if (ret) {
+               kfree(iter);
+               return ret;
+       }
+
+       iter->nentries = 0;
+       iter->start_time = xntbase_get_jiffies(&nktbase);
+
+       while (holder) {
+               xnlock_get_irqsave(&nklock, s);
+
+               if (nkpod->threadq_rev != rev)
+                       goto restart;
+
+               rev = nkpod->threadq_rev;
+               thread = link2thread(holder, glink);
+
+               if (thread->base_class != &xnsched_class_tp)
+                       goto skip;
+
+               n = iter->nentries++;
+               p = iter->sched_info + n;
+               p->cpu = xnsched_cpu(thread->sched);
+               p->pid = xnthread_user_pid(thread);
+               memcpy(p->name, thread->name, sizeof(p->name));
+               p->ptid = thread->tps - thread->sched->tp.partitions;
+               p->prio = thread->cprio;
+       skip:
+               holder = nextq(&nkpod->threadq, holder);
+               xnlock_put_irqrestore(&nklock, s);
+       }
+
+       seq = file->private_data;
+       seq->private = iter;
+
+       return 0;
+}
+
+static struct file_operations xnsched_tp_seq_operations = {
+       .owner = THIS_MODULE,
+       .open = xnsched_tp_seq_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release_private,
+};
+
+void xnsched_tp_init_proc(struct proc_dir_entry *root)
+{
+       rthal_add_proc_seq("threads", &xnsched_tp_seq_operations, 0, root);
+}
+
+void xnsched_tp_cleanup_proc(struct proc_dir_entry *root)
+{
+       remove_proc_entry("threads", root);
+}
+
+#endif /* CONFIG_PROC_FS */
+
 struct xnsched_class xnsched_class_tp = {
 
        .sched_init             =       xnsched_tp_init,
@@ -292,6 +458,10 @@ struct xnsched_class xnsched_class_tp = {
        .sched_trackprio        =       xnsched_tp_trackprio,
        .sched_declare          =       xnsched_tp_declare,
        .sched_forget           =       xnsched_tp_forget,
+#ifdef CONFIG_PROC_FS
+       .sched_init_proc        =       xnsched_tp_init_proc,
+       .sched_cleanup_proc     =       xnsched_tp_cleanup_proc,
+#endif
        .weight                 =       XNSCHED_CLASS_WEIGHT(2),
        .name                   =       "tp"
 };
diff --git a/ksrc/nucleus/sched.c b/ksrc/nucleus/sched.c
index 615c716..6f2c211 100644
--- a/ksrc/nucleus/sched.c
+++ b/ksrc/nucleus/sched.c
@@ -386,6 +386,7 @@ int xnsched_set_policy(struct xnthread *thread,
                        if (ret)
                                return ret;
                }
+               sched_class->nthreads++;
        }
 
        /*
@@ -665,7 +666,8 @@ struct xnpholder *nextmlq(struct xnsched_mlq *q, struct 
xnpholder *h)
 #ifdef CONFIG_PROC_FS
 
 #include <linux/seq_file.h>
-#include <linux/proc_fs.h>
+
+static struct proc_dir_entry *schedclass_proc_root;
 
 struct sched_seq_iterator {
        xnticks_t start_time;
@@ -678,8 +680,8 @@ struct sched_seq_iterator {
                char sched_class[XNOBJECT_NAME_LEN];
                int cprio;
                int dnprio;
-               xnticks_t period;
-               xnticks_t timeout;
+               int periodic;
+               xnticks_t timeout;
                xnflags_t state;
        } sched_info[1];
 };
@@ -715,11 +717,11 @@ static void sched_seq_stop(struct seq_file *seq, void *v)
 
 static int sched_seq_show(struct seq_file *seq, void *v)
 {
-       char sbuf[64], pbuf[16];
+       char sbuf[64], pbuf[16], tbuf[16];
 
        if (v == SEQ_START_TOKEN)
-               seq_printf(seq, "%-3s  %-6s %-5s  %-8s %-10s %-10s %-8s  %-10s 
%s\n",
-                          "CPU", "PID", "CLASS", "PRI", "PERIOD", "TIMEOUT", 
"TIMEBASE", "STAT", "NAME");
+               seq_printf(seq, "%-3s  %-6s %-5s  %-8s %-8s  %-10s %-10s %s\n",
+                          "CPU", "PID", "CLASS", "PRI", "TIMEOUT", "TIMEBASE", 
"STAT", "NAME");
        else {
                struct sched_seq_info *p = v;
 
@@ -729,16 +731,18 @@ static int sched_seq_show(struct seq_file *seq, void *v)
                else
                        snprintf(pbuf, sizeof(pbuf), "%3d", p->cprio);
 
-               seq_printf(seq, "%3u  %-6d %-5s  %-8s %-10Lu %-10Lu %-8s  %-10s 
%s\n",
+               xntimer_format_time(p->timeout, p->periodic, tbuf, 
sizeof(tbuf));
+               xnthread_format_status(p->state, sbuf, sizeof(sbuf));
+
+               seq_printf(seq, "%3u  %-6d %-5s  %-8s %-8s  %-10s %-10s %s\n",
                           p->cpu,
                           p->pid,
                           p->sched_class,
                           pbuf,
-                          p->period,
-                          p->timeout,
+                          tbuf,
                           p->timebase,
-                          xnthread_symbolic_status(p->state, sbuf,
-                                                   sizeof(sbuf)), p->name);
+                          sbuf,
+                          p->name);
        }
 
        return 0;
@@ -754,8 +758,10 @@ static struct seq_operations sched_op = {
 static int sched_seq_open(struct inode *inode, struct file *file)
 {
        struct sched_seq_iterator *iter = NULL;
+       xnticks_t period, timeout;
+       struct xnholder *holder;
+       struct sched_seq_info *p;
        struct seq_file *seq;
-       xnholder_t *holder;
        int err, count, rev;
        spl_t s;
 
@@ -789,9 +795,10 @@ static int sched_seq_open(struct inode *inode, struct file 
*file)
        iter->nentries = 0;
        iter->start_time = xntbase_get_jiffies(&nktbase);
 
-       /* Take a snapshot element-wise, restart if something changes
-          underneath us. */
-
+       /*
+        * Take a snapshot element-wise, restart if something changes
+        * underneath us.
+        */
        while (holder) {
                xnthread_t *thread;
                int n;
@@ -800,25 +807,43 @@ static int sched_seq_open(struct inode *inode, struct 
file *file)
 
                if (nkpod->threadq_rev != rev)
                        goto restart;
-               rev = nkpod->threadq_rev;
 
+               rev = nkpod->threadq_rev;
                thread = link2thread(holder, glink);
                n = iter->nentries++;
-
-               iter->sched_info[n].cpu = xnsched_cpu(thread->sched);
-               iter->sched_info[n].pid = xnthread_user_pid(thread);
-               memcpy(iter->sched_info[n].name, thread->name, 
sizeof(iter->sched_info[n].name));
-               iter->sched_info[n].cprio = thread->cprio;
-               iter->sched_info[n].dnprio = 
xnthread_get_denormalized_prio(thread, thread->cprio);
-               iter->sched_info[n].period = xnthread_get_period(thread);
-               iter->sched_info[n].timeout = xnthread_get_timeout(thread, 
iter->start_time);
-               iter->sched_info[n].state = xnthread_state_flags(thread);
-               memcpy(iter->sched_info[n].timebase, 
xntbase_name(xnthread_time_base(thread)),
-                      sizeof(iter->sched_info[n].timebase));
-               xnobject_copy_name(iter->sched_info[n].sched_class, 
thread->sched_class->name);
+               p = iter->sched_info + n;
+
+               p->cpu = xnsched_cpu(thread->sched);
+               p->pid = xnthread_user_pid(thread);
+               memcpy(p->name, thread->name, sizeof(p->name));
+               p->cprio = thread->cprio;
+               p->dnprio = xnthread_get_denormalized_prio(thread, 
thread->cprio);
+               p->state = xnthread_state_flags(thread);
+               memcpy(p->timebase, xntbase_name(xnthread_time_base(thread)),
+                      sizeof(p->timebase));
+               xnobject_copy_name(p->sched_class, thread->sched_class->name);
+               period = xnthread_get_period(thread);
+               timeout = xnthread_get_timeout(thread, iter->start_time);
+               /*
+                * Here we cheat: thread is periodic and the sampling
+                * rate may be high, so it is indeed possible that the
+                * next tick date from the ptimer progresses fast
+                * enough while we are busy collecting output data in
+                * this loop, so that next_date - start_time >
+                * period. In such a case, we simply ceil the value to
+                * period to keep the result meaningful, even if not
+                * necessarily accurate. But what does accuracy mean
+                * when the sampling frequency is high, and the way to
+                * read it has to go through the /proc interface
+                * anyway?
+                */
+               if (period > 0 && period < timeout &&
+                   !xntimer_running_p(&thread->rtimer))
+                       timeout = period;
+               p->timeout = timeout;
+               p->periodic = xntbase_periodic_p(xnthread_time_base(thread));
 
                holder = nextq(&nkpod->threadq, holder);
-
                xnlock_put_irqrestore(&nklock, s);
        }
 
@@ -1103,7 +1128,21 @@ static struct file_operations acct_seq_operations = {
 
 void xnsched_init_proc(void)
 {
+       struct xnsched_class *p;
+
        rthal_add_proc_seq("sched", &sched_seq_operations, 0, rthal_proc_root);
+       schedclass_proc_root =
+               create_proc_entry("schedclasses", S_IFDIR, rthal_proc_root);
+
+       for_each_xnsched_class(p) {
+               if (p->sched_init_proc == NULL)
+                       continue;
+               p->proc = create_proc_entry(p->name, S_IFDIR,
+                                           schedclass_proc_root);
+               if (p->proc)
+                       p->sched_init_proc(p->proc);
+       }
+
 #ifdef CONFIG_XENO_OPT_STATS
        rthal_add_proc_seq("stat", &stat_seq_operations, 0, rthal_proc_root);
        rthal_add_proc_seq("acct", &acct_seq_operations, 0, rthal_proc_root);
@@ -1112,10 +1151,21 @@ void xnsched_init_proc(void)
 
 void xnsched_cleanup_proc(void)
 {
+       struct xnsched_class *p;
+
+       for_each_xnsched_class(p) {
+               if (p->proc == NULL)
+                       continue;
+               if (p->sched_cleanup_proc)
+                       p->sched_cleanup_proc(p->proc);
+               remove_proc_entry(p->name, schedclass_proc_root);
+       }
+
 #ifdef CONFIG_XENO_OPT_STATS
        remove_proc_entry("acct", rthal_proc_root);
        remove_proc_entry("stat", rthal_proc_root);
 #endif /* CONFIG_XENO_OPT_STATS */
+       remove_proc_entry("schedclasses", rthal_proc_root);
        remove_proc_entry("sched", rthal_proc_root);
 }
 
diff --git a/ksrc/nucleus/thread.c b/ksrc/nucleus/thread.c
index beb9e91..c8c05cc 100644
--- a/ksrc/nucleus/thread.c
+++ b/ksrc/nucleus/thread.c
@@ -179,7 +179,7 @@ void xnthread_cleanup_tcb(xnthread_t *thread)
 #endif /* CONFIG_XENO_OPT_REGISTRY */
 }
 
-char *xnthread_symbolic_status(xnflags_t status, char *buf, int size)
+char *xnthread_format_status(xnflags_t status, char *buf, int size)
 {
        static const char labels[] = XNTHREAD_STATE_LABELS;
        xnflags_t mask;
@@ -189,54 +189,43 @@ char *xnthread_symbolic_status(xnflags_t status, char 
*buf, int size)
        for (mask = status & ~XNTHREAD_STATE_SPARES, pos = 0, wp = buf;
             mask != 0 && wp - buf < size - 2;  /* 1-letter label + \0 */
             mask >>= 1, pos++) {
-               c = labels[pos];
-
-               if (mask & 1) {
-                       switch (1 << pos) {
-                       case XNFPU:
-
-                               /* Only output the FPU flag for kernel-based
-                                  threads; Others get the same level of fp
-                                  support than any user-space tasks on the
-                                  current platform. */
-
-                               if (status & (XNSHADOW | XNROOT))
-                                       continue;
-
-                               break;
-
-                       case XNROOT:
-
-                               c = 'R';        /* Always mark root as 
runnable. */
-                               break;
-
-                       case XNDELAY:
-
-                               /* Only report genuine delays here, not timed
-                                  waits for resources. */
+               if ((mask & 1) == 0)
+                       continue;
 
-                               if (status & XNPEND)
-                                       continue;
-
-                               break;
-
-                       case XNPEND:
-
-                               /* Report timed waits with lowercase symbol. */
-
-                               if (status & XNDELAY)
-                                       c |= 0x20;
-
-                               break;
-
-                       default:
-
-                               if (c == '.')
-                                       continue;
-                       }
+               c = labels[pos];
 
-                       *wp++ = c;
+               switch (1 << pos) {
+               case XNFPU:
+                       /*
+                        * Only output the FPU flag for kernel-based
+                        * threads; Others get the same level of fp
+                        * support than any user-space tasks on the
+                        * current platform.
+                        */
+                       if (status & (XNSHADOW | XNROOT))
+                               continue;
+                       break;
+               case XNROOT:
+                       c = 'R'; /* Always mark root as runnable. */
+                       break;
+               case XNDELAY:
+                       /*
+                        * Only report genuine delays here, not timed
+                        * waits for resources.
+                        */
+                       if (status & XNPEND)
+                               continue;
+                       break;
+               case XNPEND:
+                       /* Report timed waits with lowercase symbol. */
+                       if (status & XNDELAY)
+                               c |= 0x20;
+                       break;
+               default:
+                       if (c == '.')
+                               continue;
                }
+               *wp++ = c;
        }
 
        *wp = '\0';
@@ -262,3 +251,58 @@ int *xnthread_get_errno_location(xnthread_t *thread)
        return &thread->errcode;
 }
 EXPORT_SYMBOL_GPL(xnthread_get_errno_location);
+
+xnticks_t xnthread_get_timeout(xnthread_t *thread, xnticks_t tsc_ns)
+{
+       xnticks_t timeout;
+       xntimer_t *timer;
+
+       if (!xnthread_test_state(thread,XNDELAY))
+               return 0LL;
+
+       if (xntimer_running_p(&thread->rtimer))
+               timer = &thread->rtimer;
+       else if (xntimer_running_p(&thread->ptimer))
+               timer = &thread->ptimer;
+       else
+               return 0LL;
+       /*
+        * The caller should have masked IRQs while collecting the
+        * timeout(s), so no tick could be announced in the meantime,
+        * and all timeouts would always use the same epoch
+        * value. Obviously, this can't be a valid assumption for
+        * aperiodic timers, which values are based on the hardware
+        * TSC, and as such the current time will change regardless of
+        * the interrupt state; for this reason, we use the "tsc_ns"
+        * input parameter (TSC converted to nanoseconds) the caller
+        * has passed us as the epoch value instead.
+        */
+       if (xntbase_periodic_p(xnthread_time_base(thread)))
+               return xntimer_get_timeout(timer);
+
+       timeout = xntimer_get_date(timer);
+
+       if (timeout <= tsc_ns)
+               return 1;
+
+       return timeout - tsc_ns;
+}
+EXPORT_SYMBOL_GPL(xnthread_get_timeout);
+
+xnticks_t xnthread_get_period(xnthread_t *thread)
+{
+       xnticks_t period = 0;
+       /*
+        * The current thread period might be:
+        * - the value of the timer interval for periodic threads (ns/ticks)
+        * - or, the value of the alloted round-robin quantum (ticks)
+        * - or zero, meaning "no periodic activity".
+        */
+       if (xntimer_running_p(&thread->ptimer))
+               period = xntimer_get_interval(&thread->ptimer);
+       else if (xnthread_test_state(thread,XNRRB))
+               period = xnthread_time_slice(thread);
+
+       return period;
+}
+EXPORT_SYMBOL_GPL(xnthread_get_period);
diff --git a/ksrc/nucleus/timer.c b/ksrc/nucleus/timer.c
index f4676a6..d813c4f 100644
--- a/ksrc/nucleus/timer.c
+++ b/ksrc/nucleus/timer.c
@@ -1064,6 +1064,40 @@ void xntimer_freeze(void)
 }
 EXPORT_SYMBOL_GPL(xntimer_freeze);
 
+char *xntimer_format_time(xnticks_t value, int periodic, char *buf, size_t 
bufsz)
+{
+       unsigned long ms, us, ns;
+       char *p = buf;
+       xnticks_t s;
+
+       if (periodic) {
+               snprintf(buf, bufsz, "%Lut", value);
+               return buf;
+       }
+
+       if (value == 0 && bufsz > 1) {
+               strcpy(buf, "-");
+               return buf;
+       }
+
+       s = xnarch_divrem_billion(value, &ns);
+       us = ns / 1000;
+       ms = us / 1000;
+       us %= 1000;
+
+       if (s)
+               p += snprintf(p, bufsz, "%Lus", s);
+
+       if (ms || (s && us))
+               p += snprintf(p, bufsz - (p - buf), "%lums", ms);
+
+       if (us)
+               p += snprintf(p, bufsz - (p - buf), "%luus", us);
+
+       return buf;
+}
+EXPORT_SYMBOL_GPL(xntimer_format_time);
+
 xntbops_t nktimer_ops_aperiodic = {
 
        .start_timer = &xntimer_start_aperiodic,


_______________________________________________
Xenomai-git mailing list
Xenomai-git@gna.org
https://mail.gna.org/listinfo/xenomai-git

Reply via email to