Module: xenomai-forge
Branch: next
Commit: d26d8c0c2b8d2bcb6101830bc33d6955967327fe
URL:    
http://git.xenomai.org/?p=xenomai-forge.git;a=commit;h=d26d8c0c2b8d2bcb6101830bc33d6955967327fe

Author: Philippe Gerum <r...@xenomai.org>
Date:   Tue Jul 15 19:01:15 2014 +0200

cobalt/timer: introduce context-sensitive timer gravity

Applying a single gravity value for anticipating on all timer shots -
regardless of what the issuing timer is being used for - falls short
of considering the proper latency attached to the context. This leads
to poor tuning, with either negative latencies (i.e. early shots)
observed on measuring the jitter for irq handlers, or higher latencies
than expected for user-space threads when using too optimistic
(i.e. small) clock gravities.

Typically, the distance between the core clock handler and the
associated kernel-based handler the former calls, is much shorter than
what has to be traversed for switching in a kernel thread. It is even
shorter than the latency incurred for switching a user-space thread
from the core clock handler.

To solve this, we differentiate timers on the final context they
activate, between irq(handler), kernel and user threads, using the
appropriate gravity value when planning for the next shot, on a
per-timer basis, instead of using a single per-clock gravity as
previously.

Two additional contexts (irq and kernel) are added to the clock
gravity settings. The user can pass a hint to xntimer_init() for
indicating which kind of context will be activated by this timer (see
XNTIMER_[IKU]GRAVITY).

There are side-effects for this change on the procfs support:

- the information previously available from the xenomai/timer entry is
  now obtained by reading xenomai/clock/coreclk. In addition, the
  clock gravity values are reported.

- the former contents of xenomai/clock/* entries (i.e. the list of
  active timers running on the associated clock) is now available from
  the new xenomai/timer/* entries, also indexed on the clock name.

Writing to an entry under xenomai/clock/* can be used to change the
gravity values of the associated clock.

/* change the user gravity (default) */
echo 3000 > /proc/xenomai/clock/coreclck
/* change the IRQ gravity */
echo 1000i > /proc/xenomai/clock/coreclck
/* change the user and kernel gravities */
echo "2000u 1000k" > /proc/xenomai/clock/coreclck

---

 include/cobalt/kernel/clock.h       |   56 +++++++--
 include/cobalt/kernel/rtdm/driver.h |   12 +-
 include/cobalt/kernel/timer.h       |   32 ++---
 kernel/cobalt/clock.c               |  228 +++++++++++++++++++++++++++++------
 kernel/cobalt/posix/timer.c         |    2 +-
 kernel/cobalt/posix/timerfd.c       |    5 +-
 kernel/cobalt/procfs.c              |    6 +-
 kernel/cobalt/sched-quota.c         |   10 +-
 kernel/cobalt/sched-sporadic.c      |    8 +-
 kernel/cobalt/sched-tp.c            |    3 +-
 kernel/cobalt/sched.c               |   11 +-
 kernel/cobalt/thread.c              |   23 ++--
 kernel/cobalt/timer.c               |   98 +++++++--------
 kernel/cobalt/vfile.c               |   13 +-
 14 files changed, 352 insertions(+), 155 deletions(-)

diff --git a/include/cobalt/kernel/clock.h b/include/cobalt/kernel/clock.h
index 5b74686..35a07c1 100644
--- a/include/cobalt/kernel/clock.h
+++ b/include/cobalt/kernel/clock.h
@@ -32,16 +32,22 @@
 struct xnsched;
 struct xntimerdata;
 
+struct xnclock_gravity {
+       unsigned long irq;
+       unsigned long kernel;
+       unsigned long user;
+};
+
 struct xnclock {
        /** ns */
        xnticks_t wallclock_offset;
        /** ns */
        xnticks_t resolution;
        /** raw clock ticks. */
-       unsigned long gravity;
+       struct xnclock_gravity gravity;
        const char *name;
-#ifdef CONFIG_XENO_OPT_EXTCLOCK
        struct {
+#ifdef CONFIG_XENO_OPT_EXTCLOCK
                xnticks_t (*read_raw)(struct xnclock *clock);
                xnticks_t (*read_monotonic)(struct xnclock *clock);
                int (*set_time)(struct xnclock *clock,
@@ -56,17 +62,27 @@ struct xnclock {
                                           struct xnsched *sched);
                void (*program_remote_shot)(struct xnclock *clock,
                                            struct xnsched *sched);
+#endif
+               int (*set_gravity)(struct xnclock *clock,
+                                  const struct xnclock_gravity *p);
+               void (*reset_gravity)(struct xnclock *clock);
+#ifdef CONFIG_XENO_OPT_VFILE
+               void (*print_status)(struct xnclock *clock,
+                                    struct xnvfile_regular_iterator *it);
+#endif
        } ops;
-#endif 
        /* Private section. */
        struct xntimerdata *timerdata;
        int id;
 #ifdef CONFIG_XENO_OPT_STATS
-       struct xnvfile_snapshot vfile;
-       struct xnvfile_rev_tag revtag;
-       struct list_head statq;
+       struct xnvfile_snapshot timer_vfile;
+       struct xnvfile_rev_tag timer_revtag;
+       struct list_head timerq;
        int nrtimers;
 #endif /* CONFIG_XENO_OPT_STATS */
+#ifdef CONFIG_XENO_OPT_VFILE
+       struct xnvfile_regular vfile;
+#endif
 };
 
 extern struct xnclock nkclock;
@@ -242,11 +258,23 @@ static inline xnticks_t xnclock_get_resolution(struct 
xnclock *clock)
        return clock->resolution; /* ns */
 }
 
-static inline unsigned long xnclock_get_gravity(struct xnclock *clock)
+static inline int xnclock_set_gravity(struct xnclock *clock,
+                                     const struct xnclock_gravity *gravity)
+{
+       if (clock->ops.set_gravity)
+               return clock->ops.set_gravity(clock, gravity);
+
+       return -EINVAL;
+}
+
+static inline void xnclock_reset_gravity(struct xnclock *clock)
 {
-       return (unsigned long)xnclock_ticks_to_ns(clock, clock->gravity);
+       if (clock->ops.reset_gravity)
+               clock->ops.reset_gravity(clock);
 }
 
+#define xnclock_get_gravity(__clock, __type)  ((__clock)->gravity.__type)
+
 static inline xnticks_t xnclock_read_realtime(struct xnclock *clock)
 {
        /*
@@ -261,9 +289,19 @@ unsigned long long xnclock_divrem_billion(unsigned long 
long value,
 
 xnticks_t xnclock_get_host_time(void);
 
-#ifdef CONFIG_XENO_OPT_STATS
+#ifdef CONFIG_XENO_OPT_VFILE
+
 void xnclock_init_proc(void);
+
 void xnclock_cleanup_proc(void);
+
+static inline void xnclock_print_status(struct xnclock *clock,
+                                       struct xnvfile_regular_iterator *it)
+{
+       if (clock->ops.print_status)
+               clock->ops.print_status(clock, it);
+}
+
 #else
 static inline void xnclock_init_proc(void) { }
 static inline void xnclock_cleanup_proc(void) { }
diff --git a/include/cobalt/kernel/rtdm/driver.h 
b/include/cobalt/kernel/rtdm/driver.h
index 18c4460..ffc9607 100644
--- a/include/cobalt/kernel/rtdm/driver.h
+++ b/include/cobalt/kernel/rtdm/driver.h
@@ -906,12 +906,14 @@ enum rtdm_timer_mode {
 /** @} rtdm_timer */
 
 #ifndef DOXYGEN_CPP /* Avoid broken doxygen output */
-#define rtdm_timer_init(timer, handler, name)          \
-({                                                     \
-       xntimer_init((timer), &nkclock, handler, NULL); \
-       xntimer_set_name((timer), (name));              \
-       0;                                              \
+#define rtdm_timer_init(timer, handler, name)                          \
+({                                                                     \
+       xntimer_init((timer), &nkclock, handler,                        \
+                    NULL, XNTIMER_IGRAVITY);                           \
+       xntimer_set_name((timer), (name));                              \
+       0;                                                              \
 })
+
 #endif /* !DOXYGEN_CPP */
 
 void rtdm_timer_destroy(rtdm_timer_t *timer);
diff --git a/include/cobalt/kernel/timer.h b/include/cobalt/kernel/timer.h
index 9f8c959..055661c 100644
--- a/include/cobalt/kernel/timer.h
+++ b/include/cobalt/kernel/timer.h
@@ -45,6 +45,12 @@ typedef enum xntmode {
 #define XNTIMER_REALTIME  0x00000008
 #define XNTIMER_FIRED     0x00000010
 #define XNTIMER_NOBLCK   0x00000020
+#define XNTIMER_KGRAVITY  0x00000040
+#define XNTIMER_UGRAVITY  0x00000080
+#define XNTIMER_IGRAVITY  0    /* most conservative */
+
+#define XNTIMER_GRAVITY_MASK   (XNTIMER_KGRAVITY|XNTIMER_UGRAVITY)
+#define XNTIMER_INIT_MASK      (XNTIMER_GRAVITY_MASK|XNTIMER_NOBLCK)
 
 /* These flags are available to the real-time interfaces */
 #define XNTIMER_SPARE0  0x01000000
@@ -313,15 +319,19 @@ static inline int xntimer_reload_p(struct xntimer *timer)
 void __xntimer_init(struct xntimer *timer,
                    struct xnclock *clock,
                    void (*handler)(struct xntimer *timer),
-                   struct xnthread *thread);
+                   struct xnthread *thread,
+                   int flags);
+
+void xntimer_set_gravity(struct xntimer *timer,
+                        int gravity);
 
 #ifdef CONFIG_XENO_OPT_STATS
 
-#define xntimer_init(timer, clock, handler, thread)            \
-       do {                                                    \
-               __xntimer_init(timer, clock, handler, thread);  \
-               (timer)->handler_name = #handler;               \
-       } while (0)
+#define xntimer_init(__timer, __clock, __handler, __thread, __flags)   \
+do {                                                                   \
+       __xntimer_init(__timer, __clock, __handler, __thread, __flags); \
+       (__timer)->handler_name = #__handler;                           \
+} while (0)
 
 static inline void xntimer_reset_stats(struct xntimer *timer)
 {
@@ -367,12 +377,6 @@ void xntimer_switch_tracking(struct xntimer *timer,
                             struct xnclock *newclock) { }
 #endif
 
-#define xntimer_init_noblock(timer, clock, handler, thread)    \
-       do {                                                    \
-               xntimer_init(timer, clock, handler, thread);    \
-               (timer)->status |= XNTIMER_NOBLCK;              \
-       } while (0)
-
 void xntimer_destroy(struct xntimer *timer);
 
 /**
@@ -443,10 +447,6 @@ static inline void xntimer_dequeue(struct xntimer *timer,
 
 /** @} */
 
-void xntimer_init_proc(void);
-
-void xntimer_cleanup_proc(void);
-
 unsigned long long xntimer_get_overruns(struct xntimer *timer, xnticks_t now);
 
 #ifdef CONFIG_SMP
diff --git a/kernel/cobalt/clock.c b/kernel/cobalt/clock.c
index 1107f7a..a552a9b 100644
--- a/kernel/cobalt/clock.c
+++ b/kernel/cobalt/clock.c
@@ -121,6 +121,17 @@ EXPORT_SYMBOL_GPL(xnclock_core_ticks_to_ns_rounded);
 EXPORT_SYMBOL_GPL(xnclock_core_ns_to_ticks);
 EXPORT_SYMBOL_GPL(xnclock_divrem_billion);
 
+static inline unsigned long get_timer_gravity(struct xntimer *timer)
+{
+       if (timer->status & XNTIMER_KGRAVITY)
+               return nkclock.gravity.kernel;
+
+       if (timer->status & XNTIMER_UGRAVITY)
+               return nkclock.gravity.user;
+
+       return nkclock.gravity.irq;
+}
+
 void xnclock_core_local_shot(struct xnsched *sched)
 {
        struct xntimerdata *tmd;
@@ -176,7 +187,7 @@ void xnclock_core_local_shot(struct xnsched *sched)
        }
 
        delay = xntimerh_date(&timer->aplink) -
-               (xnclock_core_read_raw() + nkclock.gravity);
+               (xnclock_core_read_raw() + get_timer_gravity(timer));
 
        if (delay < 0)
                delay = 0;
@@ -329,9 +340,9 @@ EXPORT_SYMBOL_GPL(xnclock_core_read_monotonic);
 
 #ifdef CONFIG_XENO_OPT_STATS
 
-static struct xnvfile_directory clock_vfroot;
+static struct xnvfile_directory timerlist_vfroot;
 
-static struct xnvfile_snapshot_ops vfile_clock_ops;
+static struct xnvfile_snapshot_ops timerlist_ops;
 
 struct vfile_clock_priv {
        struct xntimer *curr;
@@ -348,20 +359,20 @@ struct vfile_clock_data {
        char name[XNOBJECT_NAME_LEN];
 };
 
-static int clock_vfile_rewind(struct xnvfile_snapshot_iterator *it)
+static int timerlist_rewind(struct xnvfile_snapshot_iterator *it)
 {
        struct vfile_clock_priv *priv = xnvfile_iterator_priv(it);
        struct xnclock *clock = xnvfile_priv(it->vfile);
 
-       if (list_empty(&clock->statq))
+       if (list_empty(&clock->timerq))
                return -ESRCH;
 
-       priv->curr = list_first_entry(&clock->statq, struct xntimer, next_stat);
+       priv->curr = list_first_entry(&clock->timerq, struct xntimer, 
next_stat);
 
        return clock->nrtimers;
 }
 
-static int clock_vfile_next(struct xnvfile_snapshot_iterator *it, void *data)
+static int timerlist_next(struct xnvfile_snapshot_iterator *it, void *data)
 {
        struct vfile_clock_priv *priv = xnvfile_iterator_priv(it);
        struct xnclock *clock = xnvfile_priv(it->vfile);
@@ -372,7 +383,7 @@ static int clock_vfile_next(struct 
xnvfile_snapshot_iterator *it, void *data)
                return 0;
 
        timer = priv->curr;
-       if (list_is_last(&timer->next_stat, &clock->statq))
+       if (list_is_last(&timer->next_stat, &clock->timerq))
                priv->curr = NULL;
        else
                priv->curr = list_entry(timer->next_stat.next,
@@ -393,7 +404,7 @@ static int clock_vfile_next(struct 
xnvfile_snapshot_iterator *it, void *data)
        return 1;
 }
 
-static int clock_vfile_show(struct xnvfile_snapshot_iterator *it, void *data)
+static int timerlist_show(struct xnvfile_snapshot_iterator *it, void *data)
 {
        struct vfile_clock_data *p = data;
        char timeout_buf[]  = "-         ";
@@ -423,46 +434,168 @@ static int clock_vfile_show(struct 
xnvfile_snapshot_iterator *it, void *data)
        return 0;
 }
 
-static struct xnvfile_snapshot_ops vfile_clock_ops = {
-       .rewind = clock_vfile_rewind,
-       .next = clock_vfile_next,
-       .show = clock_vfile_show,
+static struct xnvfile_snapshot_ops timerlist_ops = {
+       .rewind = timerlist_rewind,
+       .next = timerlist_next,
+       .show = timerlist_show,
+};
+
+static void init_timerlist_proc(struct xnclock *clock)
+{
+       memset(&clock->timer_vfile, 0, sizeof(clock->timer_vfile));
+       clock->timer_vfile.privsz = sizeof(struct vfile_clock_priv);
+       clock->timer_vfile.datasz = sizeof(struct vfile_clock_data);
+       clock->timer_vfile.tag = &clock->timer_revtag;
+       clock->timer_vfile.ops = &timerlist_ops;
+
+       xnvfile_init_snapshot(clock->name, &clock->timer_vfile, 
&timerlist_vfroot);
+       xnvfile_priv(&clock->timer_vfile) = clock;
+}
+
+static void cleanup_timerlist_proc(struct xnclock *clock)
+{
+       xnvfile_destroy_snapshot(&clock->timer_vfile);
+}
+
+void init_timerlist_root(void)
+{
+       xnvfile_init_dir("timer", &timerlist_vfroot, &nkvfroot);
+}
+
+void cleanup_timerlist_root(void)
+{
+       xnvfile_destroy_dir(&timerlist_vfroot);
+}
+
+#else  /* !CONFIG_XENO_OPT_STATS */
+
+static inline void init_timerlist_proc(struct xnclock *clock) { }
+
+static inline void cleanup_timerlist_proc(struct xnclock *clock) { }
+
+#endif /* !CONFIG_XENO_OPT_STATS */
+
+#ifdef CONFIG_XENO_OPT_VFILE
+
+static struct xnvfile_directory clock_vfroot;
+
+void print_core_clock_status(struct xnclock *clock,
+                            struct xnvfile_regular_iterator *it)
+{
+       const char *tm_status, *wd_status = "";
+
+       tm_status = atomic_read(&nkclklk) > 0 ? "locked" : "on";
+#ifdef CONFIG_XENO_OPT_WATCHDOG
+       wd_status = "+watchdog";
+#endif /* CONFIG_XENO_OPT_WATCHDOG */
+
+       xnvfile_printf(it, "%7s: timer=%s, clock=%s\n",
+                      "devices", ipipe_timer_name(), ipipe_clock_name());
+       xnvfile_printf(it, "%7s: %s%s\n", "status", tm_status, wd_status);
+       xnvfile_printf(it, "%7s: %Lu\n", "setup",
+                      xnclock_ticks_to_ns(&nkclock, nktimerlat));
+}
+
+static int clock_show(struct xnvfile_regular_iterator *it, void *data)
+{
+       struct xnclock *clock = xnvfile_priv(it->vfile);
+
+       xnvfile_printf(it, "%7s: irq=%Ld kernel=%Ld user=%Ld\n", "gravity",
+                      xnclock_ticks_to_ns(clock, xnclock_get_gravity(clock, 
irq)),
+                      xnclock_ticks_to_ns(clock, xnclock_get_gravity(clock, 
kernel)),
+                      xnclock_ticks_to_ns(clock, xnclock_get_gravity(clock, 
user)));
+
+       xnclock_print_status(clock, it);
+
+       xnvfile_printf(it, "%7s: %Lu\n", "ticks", xnclock_read_raw(clock));
+
+       return 0;
+}
+
+static ssize_t clock_store(struct xnvfile_input *input)
+{
+       char buf[128], *args = buf, *p;
+       struct xnclock_gravity gravity;
+       struct xnvfile_regular *vfile;
+       unsigned long ns, ticks;
+       struct xnclock *clock;
+       ssize_t nbytes;
+       int ret;
+
+       nbytes = xnvfile_get_string(input, buf, sizeof(buf));
+       if (nbytes < 0)
+               return nbytes;
+
+       vfile = container_of(input->vfile, struct xnvfile_regular, entry);
+       clock = xnvfile_priv(vfile);
+       gravity = clock->gravity;
+
+       while ((p = strsep(&args, " \t:/,")) != NULL) {
+               if (*p == '\0')
+                       continue;
+               ns = simple_strtol(p, &p, 10);
+               ticks = xnclock_ns_to_ticks(clock, ns);
+               switch (*p) {
+               case 'i':
+                       gravity.irq = ticks;
+                       break;
+               case 'k':
+                       gravity.kernel = ticks;
+                       break;
+               case 'u':
+               case '\0':
+                       gravity.user = ticks;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               ret = xnclock_set_gravity(clock, &gravity);
+               if (ret)
+                       return ret;
+       }
+
+       return nbytes;
+}
+
+static struct xnvfile_regular_ops clock_ops = {
+       .show = clock_show,
+       .store = clock_store,
 };
 
 static void init_clock_proc(struct xnclock *clock)
 {
        memset(&clock->vfile, 0, sizeof(clock->vfile));
-       clock->vfile.privsz = sizeof(struct vfile_clock_priv);
-       clock->vfile.datasz = sizeof(struct vfile_clock_data);
-       clock->vfile.tag = &clock->revtag;
-       clock->vfile.ops = &vfile_clock_ops;
-
-       xnvfile_init_snapshot(clock->name, &clock->vfile, &clock_vfroot);
+       clock->vfile.ops = &clock_ops;
+       xnvfile_init_regular(clock->name, &clock->vfile, &clock_vfroot);
        xnvfile_priv(&clock->vfile) = clock;
+       init_timerlist_proc(clock);
 }
 
 static void cleanup_clock_proc(struct xnclock *clock)
 {
-       xnvfile_destroy_snapshot(&clock->vfile);
+       cleanup_timerlist_proc(clock);
+       xnvfile_destroy_regular(&clock->vfile);
 }
 
 void xnclock_init_proc(void)
 {
        xnvfile_init_dir("clock", &clock_vfroot, &nkvfroot);
+       init_timerlist_root();
 }
 
 void xnclock_cleanup_proc(void)
 {
        xnvfile_destroy_dir(&clock_vfroot);
+       cleanup_timerlist_root();
 }
 
-#else  /* !CONFIG_XENO_OPT_STATS */
+#else /* !CONFIG_XENO_OPT_VFILE */
 
 static inline void init_clock_proc(struct xnclock *clock) { }
 
 static inline void cleanup_clock_proc(struct xnclock *clock) { }
 
-#endif /* !CONFIG_XENO_OPT_STATS */
+#endif /* !CONFIG_XENO_OPT_VFILE */
 
 /**
  * @fn void xnclock_register(struct xnclock *clock)
@@ -493,7 +626,7 @@ int xnclock_register(struct xnclock *clock)
        }
 
 #ifdef CONFIG_XENO_OPT_STATS
-       INIT_LIST_HEAD(&clock->statq);
+       INIT_LIST_HEAD(&clock->timerq);
 #endif /* CONFIG_XENO_OPT_STATS */
 
        init_clock_proc(clock);
@@ -554,6 +687,7 @@ void xnclock_tick(struct xnclock *clock)
        xntimerq_t *timerq = &xnclock_this_timerdata(clock)->q;
        struct xnsched *sched = xnsched_current();
        xnticks_t now, interval_ticks;
+       unsigned long gravity;
        struct xntimer *timer;
        xnsticks_t delta;
        xntimerh_t *h;
@@ -570,18 +704,19 @@ void xnclock_tick(struct xnclock *clock)
                timer = container_of(h, struct xntimer, aplink);
                /*
                 * If the delay to the next shot is greater than the
-                * clock gravity value, we may stop scanning the timer
+                * timer gravity value, we may stop scanning the timer
                 * queue, since timeout dates are ordered by
                 * increasing values.
                 *
-                * (*) The gravity gives the amount of time expressed
-                * in clock ticks, by which we should anticipate the
-                * next shot. For instance, this value is equal to the
-                * typical latency observed on an idle system for
-                * Xenomai's core clock (nkclock).
+                * The gravity gives the amount of time expressed in
+                * clock ticks, by which we should anticipate the next
+                * shot for the given timer, to account for the
+                * typical system latency when delivering the event to
+                * an irq handler, or a kernel/user thread.
                 */
+               gravity = get_timer_gravity(timer);
                delta = (xnsticks_t)(xntimerh_date(&timer->aplink) - now);
-               if (delta > (xnsticks_t)clock->gravity)
+               if (delta > (xnsticks_t)gravity)
                        break;
 
                trace_cobalt_timer_expire(timer);
@@ -640,7 +775,7 @@ void xnclock_tick(struct xnclock *clock)
                do {
                        timer->periodic_ticks += interval_ticks;
                        xntimer_update_date(timer);
-               } while (xntimerh_date(&timer->aplink) < now + clock->gravity);
+               } while (xntimerh_date(&timer->aplink) < now + gravity);
        requeue:
 #ifdef CONFIG_SMP
                /*
@@ -667,9 +802,35 @@ void xnclock_tick(struct xnclock *clock)
 }
 EXPORT_SYMBOL_GPL(xnclock_tick);
 
+static int set_core_clock_gravity(struct xnclock *clock,
+                                 const struct xnclock_gravity *p)
+{
+       nkclock.gravity = *p;
+
+       return 0;
+}
+
+static void reset_core_clock_gravity(struct xnclock *clock)
+{
+       xnticks_t schedlat = xnarch_get_sched_latency();
+       struct xnclock_gravity gravity;
+
+       gravity.user = xnclock_ns_to_ticks(&nkclock, schedlat) + nktimerlat;
+       gravity.kernel = gravity.user;
+       gravity.irq = nktimerlat;
+       set_core_clock_gravity(clock, &gravity);
+}
+
 struct xnclock nkclock = {
        .name = "coreclk",
        .resolution = 1,        /* nanosecond. */
+       .ops = {
+               .set_gravity = set_core_clock_gravity,
+               .reset_gravity = reset_core_clock_gravity,
+#ifdef CONFIG_XENO_OPT_VFILE
+               .print_status = print_core_clock_status,
+#endif
+       },
        .id = -1,
 };
 EXPORT_SYMBOL_GPL(nkclock);
@@ -681,8 +842,6 @@ void xnclock_cleanup(void)
 
 int __init xnclock_init(unsigned long long freq)
 {
-       xnticks_t schedlat;
-
        clockfreq = freq;
 #ifdef XNARCH_HAVE_LLMULSHFT
        xnarch_init_llmulshft(1000000000, freq, &tsc_scale, &tsc_shift);
@@ -692,8 +851,7 @@ int __init xnclock_init(unsigned long long freq)
 #endif
 #endif
        nktimerlat = xnarch_timer_calibrate();
-       schedlat = xnarch_get_sched_latency();
-       nkclock.gravity = xnclock_ns_to_ticks(&nkclock, schedlat) + nktimerlat;
+       xnclock_reset_gravity(&nkclock);
        xnclock_register(&nkclock);
 
        return 0;
diff --git a/kernel/cobalt/posix/timer.c b/kernel/cobalt/posix/timer.c
index bcec167..56e0c50 100644
--- a/kernel/cobalt/posix/timer.c
+++ b/kernel/cobalt/posix/timer.c
@@ -85,7 +85,7 @@ timer_init(struct cobalt_timer *timer,
         * want to deliver a signal when a timer elapses.
         */
        xntimer_init(&timer->timerbase, &nkclock, cobalt_timer_handler,
-                    &target->threadbase);
+                    &target->threadbase, XNTIMER_UGRAVITY);
 
        return target;
 }
diff --git a/kernel/cobalt/posix/timerfd.c b/kernel/cobalt/posix/timerfd.c
index ebc554c..f76c8d1 100644
--- a/kernel/cobalt/posix/timerfd.c
+++ b/kernel/cobalt/posix/timerfd.c
@@ -181,7 +181,8 @@ int cobalt_timerfd_create(int ufd, int clockid, int flags)
 
        tfd->flags = flags;
        tfd->clockid = clockid;
-       xntimer_init(&tfd->timer, &nkclock, timerfd_handler, NULL);
+       xntimer_init(&tfd->timer, &nkclock, timerfd_handler,
+                    xnshadow_current(), XNTIMER_UGRAVITY);
        xnsynch_init(&tfd->readers, XNSYNCH_PRIO | XNSYNCH_NOPIP, NULL);
        xnselect_init(&tfd->read_select);
        tfd->target = NULL;
@@ -238,7 +239,7 @@ int cobalt_timerfd_settime(int fd, int flags,
        xnlock_get_irqsave(&nklock, s);
 
        if (flags & TFD_WAKEUP) {
-               tfd->target = xnshadow_thread(current);
+               tfd->target = xnshadow_current();
                if (tfd->target == NULL) {
                        err = -EPERM;
                        goto out_unlock;
diff --git a/kernel/cobalt/procfs.c b/kernel/cobalt/procfs.c
index 053cd05..2e8c3ce 100644
--- a/kernel/cobalt/procfs.c
+++ b/kernel/cobalt/procfs.c
@@ -95,7 +95,7 @@ static struct xnvfile_regular lock_vfile = {
 static int latency_vfile_show(struct xnvfile_regular_iterator *it, void *data)
 {
        xnvfile_printf(it, "%Lu\n",
-                      xnclock_ticks_to_ns(&nkclock, nkclock.gravity));
+                      xnclock_ticks_to_ns(&nkclock, nkclock.gravity.user));
 
        return 0;
 }
@@ -109,7 +109,7 @@ static ssize_t latency_vfile_store(struct xnvfile_input 
*input)
        if (ret < 0)
                return ret;
 
-       nkclock.gravity = xnclock_ns_to_ticks(&nkclock, val);
+       nkclock.gravity.user = xnclock_ns_to_ticks(&nkclock, val);
 
        return ret;
 }
@@ -227,7 +227,6 @@ void xnprocfs_cleanup_tree(void)
        xnvfile_destroy_regular(&latency_vfile);
        xnintr_cleanup_proc();
        xnheap_cleanup_proc();
-       xntimer_cleanup_proc();
        xnclock_cleanup_proc();
        xnsched_cleanup_proc();
        xnvfile_destroy_root();
@@ -246,7 +245,6 @@ int __init xnprocfs_init_tree(void)
                return ret;
 
        xnclock_init_proc();
-       xntimer_init_proc();
        xnheap_init_proc();
        xnintr_init_proc();
        xnvfile_init_regular("latency", &latency_vfile, &nkvfroot);
diff --git a/kernel/cobalt/sched-quota.c b/kernel/cobalt/sched-quota.c
index 4d908d9..ac0f1ca 100644
--- a/kernel/cobalt/sched-quota.c
+++ b/kernel/cobalt/sched-quota.c
@@ -223,13 +223,15 @@ static void xnsched_quota_init(struct xnsched *sched)
        strcpy(refiller_name, "[quota-refill]");
        strcpy(limiter_name, "[quota-limit]");
 #endif
-       xntimer_init_noblock(&qs->refill_timer,
-                            &nkclock, quota_refill_handler, NULL);
+       xntimer_init(&qs->refill_timer,
+                    &nkclock, quota_refill_handler, NULL,
+                    XNTIMER_NOBLCK|XNTIMER_IGRAVITY);
        xntimer_set_sched(&qs->refill_timer, sched);
        xntimer_set_name(&qs->refill_timer, refiller_name);
 
-       xntimer_init_noblock(&qs->limit_timer,
-                            &nkclock, quota_limit_handler, NULL);
+       xntimer_init(&qs->limit_timer,
+                    &nkclock, quota_limit_handler, NULL,
+                    XNTIMER_NOBLCK|XNTIMER_IGRAVITY);
        xntimer_set_sched(&qs->limit_timer, sched);
        xntimer_set_name(&qs->limit_timer, limiter_name);
 }
diff --git a/kernel/cobalt/sched-sporadic.c b/kernel/cobalt/sched-sporadic.c
index f21e0bd..e869dc6 100644
--- a/kernel/cobalt/sched-sporadic.c
+++ b/kernel/cobalt/sched-sporadic.c
@@ -314,11 +314,11 @@ static int xnsched_sporadic_declare(struct xnthread 
*thread,
        if (pss == NULL)
                return -ENOMEM;
 
-       xntimer_init(&pss->repl_timer, &nkclock,
-                    sporadic_replenish_handler, thread);
+       xntimer_init(&pss->repl_timer, &nkclock, sporadic_replenish_handler,
+                    thread, XNTIMER_IGRAVITY);
        xntimer_set_name(&pss->repl_timer, "pss-replenish");
-       xntimer_init(&pss->drop_timer, &nkclock,
-                    sporadic_drop_handler, thread);
+       xntimer_init(&pss->drop_timer, &nkclock, sporadic_drop_handler,
+                    thread, XNTIMER_IGRAVITY);
        xntimer_set_name(&pss->drop_timer, "pss-drop");
 
        thread->pss = pss;
diff --git a/kernel/cobalt/sched-tp.c b/kernel/cobalt/sched-tp.c
index c7b2061..7f48fe0 100644
--- a/kernel/cobalt/sched-tp.c
+++ b/kernel/cobalt/sched-tp.c
@@ -100,7 +100,8 @@ static void xnsched_tp_init(struct xnsched *sched)
        tp->tps = NULL;
        tp->gps = NULL;
        INIT_LIST_HEAD(&tp->threads);
-       xntimer_init_noblock(&tp->tf_timer, &nkclock, tp_tick_handler, NULL);
+       xntimer_init(&tp->tf_timer, &nkclock, tp_tick_handler,
+                    NULL, XNTIMER_NOBLCK|XNTIMER_IGRAVITY);
        xntimer_set_sched(&tp->tf_timer, sched);
        xntimer_set_name(&tp->tf_timer, timer_name);
 }
diff --git a/kernel/cobalt/sched.c b/kernel/cobalt/sched.c
index 0d08c49..4e4ca0d 100644
--- a/kernel/cobalt/sched.c
+++ b/kernel/cobalt/sched.c
@@ -191,11 +191,12 @@ void xnsched_init(struct xnsched *sched, int cpu)
         * postponed to xnintr_irq_handler(), as part of the interrupt
         * exit code.
         */
-       xntimer_init(&sched->htimer, &nkclock, NULL, &sched->rootcb);
+       xntimer_init(&sched->htimer, &nkclock, NULL,
+                    &sched->rootcb, XNTIMER_IGRAVITY);
        xntimer_set_priority(&sched->htimer, XNTIMER_LOPRIO);
        xntimer_set_name(&sched->htimer, htimer_name);
-       xntimer_init(&sched->rrbtimer, &nkclock,
-                    roundrobin_handler, &sched->rootcb);
+       xntimer_init(&sched->rrbtimer, &nkclock, roundrobin_handler,
+                    &sched->rootcb, XNTIMER_IGRAVITY);
        xntimer_set_name(&sched->rrbtimer, rrbtimer_name);
        xntimer_set_priority(&sched->rrbtimer, XNTIMER_LOPRIO);
 
@@ -209,8 +210,8 @@ void xnsched_init(struct xnsched *sched, int cpu)
        nknrthreads++;
 
 #ifdef CONFIG_XENO_OPT_WATCHDOG
-       xntimer_init_noblock(&sched->wdtimer, &nkclock,
-                            watchdog_handler, &sched->rootcb);
+       xntimer_init(&sched->wdtimer, &nkclock, watchdog_handler,
+                    &sched->rootcb, XNTIMER_NOBLCK|XNTIMER_IGRAVITY);
        xntimer_set_name(&sched->wdtimer, "[watchdog]");
        xntimer_set_priority(&sched->wdtimer, XNTIMER_LOPRIO);
 #endif /* CONFIG_XENO_OPT_WATCHDOG */
diff --git a/kernel/cobalt/thread.c b/kernel/cobalt/thread.c
index b25a8d2..47ede97 100644
--- a/kernel/cobalt/thread.c
+++ b/kernel/cobalt/thread.c
@@ -187,10 +187,14 @@ int __xnthread_init(struct xnthread *thread,
        thread->entry = NULL;
        thread->cookie = NULL;
 
-       xntimer_init(&thread->rtimer, &nkclock, timeout_handler, thread);
+       xntimer_init(&thread->rtimer, &nkclock, timeout_handler, thread,
+                    xnthread_test_state(thread, XNUSER) ?
+                    XNTIMER_UGRAVITY : XNTIMER_KGRAVITY);
        xntimer_set_name(&thread->rtimer, thread->name);
        xntimer_set_priority(&thread->rtimer, XNTIMER_HIPRIO);
-       xntimer_init(&thread->ptimer, &nkclock, periodic_handler, thread);
+       xntimer_init(&thread->ptimer, &nkclock, periodic_handler, thread,
+                    xnthread_test_state(thread, XNUSER) ?
+                    XNTIMER_UGRAVITY : XNTIMER_KGRAVITY);
        xntimer_set_name(&thread->ptimer, thread->name);
        xntimer_set_priority(&thread->ptimer, XNTIMER_HIPRIO);
 
@@ -1234,11 +1238,14 @@ int xnthread_set_periodic(struct xnthread *thread, 
xnticks_t idate,
                goto unlock_and_exit;
        }
 
-       if (period < xnclock_ticks_to_ns(&nkclock, nkclock.gravity)) {
+       if (period < xnclock_ticks_to_ns(&nkclock,
+                                        xnclock_get_gravity(&nkclock,
+                                                            kernel))) {
                /*
                 * LART: detect periods which are shorter than the
-                * clock gravity. This can't work, caller must have
-                * messed up with arguments.
+                * core clock gravity for kernel thread timers. This
+                * can't work, caller must have messed up with
+                * arguments.
                 */
                ret = -EINVAL;
                goto unlock_and_exit;
@@ -1366,8 +1373,8 @@ EXPORT_SYMBOL_GPL(xnthread_wait_period);
  *   - the base scheduling class of the target thread does not support
  *   time-slicing,
  *
- *   - @a quantum is smaller than the master clock gravity, which
- * denotes a spurious value.
+ *   - @a quantum is smaller than the master clock gravity for a user
+ * thread, which denotes a spurious value.
  *
  * @coretags{task-unrestricted}
  */
@@ -1376,7 +1383,7 @@ int xnthread_set_slice(struct xnthread *thread, xnticks_t 
quantum)
        struct xnsched *sched;
        spl_t s;
 
-       if (quantum <= xnclock_get_gravity(&nkclock))
+       if (quantum <= xnclock_get_gravity(&nkclock, user))
                return -EINVAL;
 
        xnlock_get_irqsave(&nklock, s);
diff --git a/kernel/cobalt/timer.c b/kernel/cobalt/timer.c
index b0113e0..f312a88 100644
--- a/kernel/cobalt/timer.c
+++ b/kernel/cobalt/timer.c
@@ -269,7 +269,7 @@ xnticks_t xntimer_get_timeout(struct xntimer *timer)
 EXPORT_SYMBOL_GPL(xntimer_get_timeout);
 
 /**
- * @fn void xntimer_init(struct xntimer *timer,struct xnclock *clock,void 
(*handler)(struct xntimer *timer), struct xnthread *thread)
+ * @fn void xntimer_init(struct xntimer *timer,struct xnclock *clock,void 
(*handler)(struct xntimer *timer), struct xnthread *thread, int flags)
  * @brief Initialize a timer object.
  *
  * Creates a timer. When created, a timer is left disarmed; it must be
@@ -289,8 +289,21 @@ EXPORT_SYMBOL_GPL(xntimer_get_timeout);
  *
  * @param thread The optional thread object the new timer is affine
  * to. If non-NULL, the timer will fire on the same CPU @a thread
- * currently runs on by default. A call to xntimer_set_sched() may
- * change this setting.
+ * currently runs on by default, otherwise it will fire on the CPU
+ * which initialized it.
+ *
+ * @param flags A set of flags describing the timer. The valid flags are:
+ *
+ * - XNTIMER_NOBLCK, the timer won't be frozen while GDB takes over
+ * control of the application.
+ *
+ * A set of clock gravity hints can be passed via the @a flags
+ * argument, used for optimizing the built-in heuristics aimed at
+ * latency reduction:
+ *
+ * - XNTIMER_IGRAVITY, the timer activates a leaf timer handler.
+ * - XNTIMER_KGRAVITY, the timer activates a kernel thread.
+ * - XNTIMER_UGRAVITY, the timer activates a user-space thread.
  *
  * There is no limitation on the number of timers which can be
  * created/active concurrently.
@@ -300,13 +313,15 @@ EXPORT_SYMBOL_GPL(xntimer_get_timeout);
 #ifdef DOXYGEN_CPP
 void xntimer_init(struct xntimer *timer, struct xnclock *clock,
                  void (*handler)(struct xntimer *timer),
-                 struct xnthread *thread);
+                 struct xnthread *thread,
+                 int flags);
 #endif
 
 void __xntimer_init(struct xntimer *timer,
                    struct xnclock *clock,
                    void (*handler)(struct xntimer *timer),
-                   struct xnthread *thread)
+                   struct xnthread *thread,
+                   int flags)
 {
        spl_t s __maybe_unused;
        int cpu;
@@ -317,19 +332,23 @@ void __xntimer_init(struct xntimer *timer,
        xntimerh_init(&timer->aplink);
        xntimerh_date(&timer->aplink) = XN_INFINITE;
        xntimer_set_priority(timer, XNTIMER_STDPRIO);
-       timer->status = XNTIMER_DEQUEUED;
+       timer->status = (XNTIMER_DEQUEUED|(flags & XNTIMER_INIT_MASK));
        timer->handler = handler;
        timer->interval_ns = 0;
        /*
         * Timers have to run on a real-time CPU, i.e. a member of the
         * xnsched_realtime_cpus mask. If the new timer is affine to a
-        * thread, we assign it the same CPU (which has to be correct),
-        * otherwise pick the first valid real-time CPU by default.
+        * thread, we assign it the same CPU (which has to be
+        * correct), otherwise pick the current CPU if valid, or the
+        * first valid real-time CPU otherwise.
         */
        if (thread)
                timer->sched = thread->sched;
        else {
-               cpu = first_cpu(xnsched_realtime_cpus);
+               cpu = ipipe_processor_id();
+               if (!xnsched_supported_cpu(cpu))
+                       cpu = first_cpu(xnsched_realtime_cpus);
+
                timer->sched = xnsched_struct(cpu);
        }
 
@@ -341,14 +360,25 @@ void __xntimer_init(struct xntimer *timer,
                 current->pid, current->comm);
        xntimer_reset_stats(timer);
        xnlock_get_irqsave(&nklock, s);
-       list_add_tail(&timer->next_stat, &clock->statq);
+       list_add_tail(&timer->next_stat, &clock->timerq);
        clock->nrtimers++;
-       xnvfile_touch(&clock->vfile);
+       xnvfile_touch(&clock->timer_vfile);
        xnlock_put_irqrestore(&nklock, s);
 #endif /* CONFIG_XENO_OPT_STATS */
 }
 EXPORT_SYMBOL_GPL(__xntimer_init);
 
+void xntimer_set_gravity(struct xntimer *timer, int gravity)
+{
+       spl_t s;
+
+       xnlock_get_irqsave(&nklock, s);
+       timer->status &= ~XNTIMER_GRAVITY_MASK;
+       timer->status |= gravity;
+       xnlock_put_irqrestore(&nklock, s);
+}
+EXPORT_SYMBOL_GPL(xntimer_set_gravity);
+
 #if defined(CONFIG_XENO_OPT_EXTCLOCK) && defined(CONFIG_XENO_OPT_STATS)
 
 void xntimer_switch_tracking(struct xntimer *timer,
@@ -361,7 +391,7 @@ void xntimer_switch_tracking(struct xntimer *timer,
        list_del(&timer->next_stat);
        oldclock->nrtimers--;
        xnvfile_touch(&oldclock->vfile);
-       list_add_tail(&timer->next_stat, &newclock->statq);
+       list_add_tail(&timer->next_stat, &newclock->timerq);
        newclock->nrtimers++;
        xnvfile_touch(&newclock->vfile);
        timer->tracker = newclock;
@@ -396,7 +426,7 @@ void xntimer_destroy(struct xntimer *timer)
 #ifdef CONFIG_XENO_OPT_STATS
        list_del(&timer->next_stat);
        clock->nrtimers--;
-       xnvfile_touch(&clock->vfile);
+       xnvfile_touch(&clock->timer_vfile);
 #endif /* CONFIG_XENO_OPT_STATS */
        xnlock_put_irqrestore(&nklock, s);
 }
@@ -701,46 +731,4 @@ void xntimer_release_hardware(int cpu)
        ipipe_timer_stop(cpu);
 }
 
-#ifdef CONFIG_XENO_OPT_VFILE
-
-#include <cobalt/kernel/vfile.h>
-
-static int timer_vfile_show(struct xnvfile_regular_iterator *it, void *data)
-{
-       const char *tm_status, *wd_status = "";
-
-       tm_status = atomic_read(&nkclklk) > 0 ? "locked" : "on";
-#ifdef CONFIG_XENO_OPT_WATCHDOG
-       wd_status = "+watchdog";
-#endif /* CONFIG_XENO_OPT_WATCHDOG */
-
-       xnvfile_printf(it,
-                      
"status=%s%s:setup=%Lu:clock=%Lu:timerdev=%s:clockdev=%s\n",
-                      tm_status, wd_status,
-                      xnclock_ticks_to_ns(&nkclock, nktimerlat),
-                      xnclock_read_raw(&nkclock),
-                      ipipe_timer_name(), ipipe_clock_name());
-       return 0;
-}
-
-static struct xnvfile_regular_ops timer_vfile_ops = {
-       .show = timer_vfile_show,
-};
-
-static struct xnvfile_regular timer_vfile = {
-       .ops = &timer_vfile_ops,
-};
-
-void xntimer_init_proc(void)
-{
-       xnvfile_init_regular("timer", &timer_vfile, &nkvfroot);
-}
-
-void xntimer_cleanup_proc(void)
-{
-       xnvfile_destroy_regular(&timer_vfile);
-}
-
-#endif /* CONFIG_XENO_OPT_VFILE */
-
 /** @} */
diff --git a/kernel/cobalt/vfile.c b/kernel/cobalt/vfile.c
index 416eb0a..7816e75 100644
--- a/kernel/cobalt/vfile.c
+++ b/kernel/cobalt/vfile.c
@@ -827,8 +827,8 @@ EXPORT_SYMBOL_GPL(xnvfile_get_blob);
  * maxlen is larger than the actual string length, the input is
  * truncated to @a maxlen.
  *
- * @return The number of characters read and copied to the destination
- * buffer upon success. Otherwise, a negative error code is returned:
+ * @return The number of characters read upon success. Otherwise, a
+ * negative error code is returned:
  *
  * - -EFAULT indicates an invalid source buffer address.
  *
@@ -837,7 +837,7 @@ EXPORT_SYMBOL_GPL(xnvfile_get_blob);
 ssize_t xnvfile_get_string(struct xnvfile_input *input,
                           char *s, size_t maxlen)
 {
-       ssize_t nbytes;
+       ssize_t nbytes, eol;
 
        if (maxlen < 1)
                return -EINVAL;
@@ -846,10 +846,11 @@ ssize_t xnvfile_get_string(struct xnvfile_input *input,
        if (nbytes < 0)
                return nbytes;
 
-       if (nbytes > 0 && s[nbytes - 1] == '\n')
-               nbytes--;
+       eol = nbytes;
+       if (eol > 0 && s[eol - 1] == '\n')
+               eol--;
 
-       s[nbytes] = '\0';
+       s[eol] = '\0';
 
        return nbytes;
 }


_______________________________________________
Xenomai-git mailing list
Xenomai-git@xenomai.org
http://www.xenomai.org/mailman/listinfo/xenomai-git

Reply via email to