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

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 are
assigned to, 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 the a per-clock basis as previously.

The two additional contexts (irq and kernel) are added to the clock
gravity settings. The proper value is assigned to the timer gravity
when the timer is initialized, according to the context represented by
the thread is is affine to. If a timer is not affine to any thread
when initialized, we assume a leaf, in-kernel irq handler is
associated, which is a conservative option to prevent early shots.

---

 include/cobalt/kernel/clock.h       |   13 ++++++----
 include/cobalt/kernel/rtdm/driver.h |   11 ++++----
 include/cobalt/kernel/timer.h       |   28 +++++++++++---------
 kernel/cobalt/clock.c               |   45 ++++++++++++++++++++++----------
 kernel/cobalt/posix/timer.c         |    2 +-
 kernel/cobalt/posix/timerfd.c       |    5 ++--
 kernel/cobalt/procfs.c              |    4 +--
 kernel/cobalt/sched-quota.c         |   10 +++++---
 kernel/cobalt/sched-sporadic.c      |    4 +--
 kernel/cobalt/sched-tp.c            |    3 ++-
 kernel/cobalt/sched.c               |    9 ++++---
 kernel/cobalt/thread.c              |   23 +++++++++++------
 kernel/cobalt/timer.c               |   48 ++++++++++++++++++++++++++++-------
 13 files changed, 137 insertions(+), 68 deletions(-)

diff --git a/include/cobalt/kernel/clock.h b/include/cobalt/kernel/clock.h
index 5b74686..ef356ef 100644
--- a/include/cobalt/kernel/clock.h
+++ b/include/cobalt/kernel/clock.h
@@ -38,7 +38,11 @@ struct xnclock {
        /** ns */
        xnticks_t resolution;
        /** raw clock ticks. */
-       unsigned long gravity;
+       struct {
+               unsigned long irq;
+               unsigned long kernel;
+               unsigned long user;
+       }  gravity;
        const char *name;
 #ifdef CONFIG_XENO_OPT_EXTCLOCK
        struct {
@@ -84,6 +88,8 @@ void xnclock_tick(struct xnclock *clock);
 void xnclock_adjust(struct xnclock *clock,
                    xnsticks_t delta);
 
+void xnclock_core_reset_gravity(void);
+
 void xnclock_core_local_shot(struct xnsched *sched);
 
 void xnclock_core_remote_shot(struct xnsched *sched);
@@ -242,10 +248,7 @@ static inline xnticks_t xnclock_get_resolution(struct 
xnclock *clock)
        return clock->resolution; /* ns */
 }
 
-static inline unsigned long xnclock_get_gravity(struct xnclock *clock)
-{
-       return (unsigned long)xnclock_ticks_to_ns(clock, clock->gravity);
-}
+#define xnclock_get_gravity(__clock, __type)  ((__clock)->gravity.__type)
 
 static inline xnticks_t xnclock_read_realtime(struct xnclock *clock)
 {
diff --git a/include/cobalt/kernel/rtdm/driver.h 
b/include/cobalt/kernel/rtdm/driver.h
index 18c4460..dd03e6a 100644
--- a/include/cobalt/kernel/rtdm/driver.h
+++ b/include/cobalt/kernel/rtdm/driver.h
@@ -906,12 +906,13 @@ 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_IGRAV);  \
+       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..c827c03 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_IGRAV    0x00000040
+#define XNTIMER_UGRAV    0x00000080
+#define XNTIMER_KGRAV    0
+
+#define XNTIMER_GRAVITY_MASK   (XNTIMER_IGRAV|XNTIMER_UGRAV)
+#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);
 
 /**
diff --git a/kernel/cobalt/clock.c b/kernel/cobalt/clock.c
index 1107f7a..54a4281 100644
--- a/kernel/cobalt/clock.c
+++ b/kernel/cobalt/clock.c
@@ -121,6 +121,26 @@ EXPORT_SYMBOL_GPL(xnclock_core_ticks_to_ns_rounded);
 EXPORT_SYMBOL_GPL(xnclock_core_ns_to_ticks);
 EXPORT_SYMBOL_GPL(xnclock_divrem_billion);
 
+void xnclock_core_reset_gravity(void)
+{
+       xnticks_t schedlat = xnarch_get_sched_latency();
+
+       nkclock.gravity.user = xnclock_ns_to_ticks(&nkclock, schedlat) + 
nktimerlat;
+       nkclock.gravity.kernel = nkclock.gravity.user;
+       nkclock.gravity.irq = nktimerlat;
+}
+
+static inline unsigned long get_gravity(struct xntimer *timer)
+{
+       if (timer->status & XNTIMER_IGRAV)
+               return nkclock.gravity.irq;
+
+       if (timer->status & XNTIMER_UGRAV)
+               return nkclock.gravity.user;
+
+       return nkclock.gravity.kernel;
+}
+
 void xnclock_core_local_shot(struct xnsched *sched)
 {
        struct xntimerdata *tmd;
@@ -176,7 +196,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_gravity(timer));
 
        if (delay < 0)
                delay = 0;
@@ -554,6 +574,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 +591,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_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 +662,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
                /*
@@ -681,8 +703,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 +712,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_core_reset_gravity();
        xnclock_register(&nkclock);
 
        return 0;
diff --git a/kernel/cobalt/posix/timer.c b/kernel/cobalt/posix/timer.c
index bcec167..ca0749b 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_UGRAV);
 
        return target;
 }
diff --git a/kernel/cobalt/posix/timerfd.c b/kernel/cobalt/posix/timerfd.c
index ebc554c..c28cc36 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_UGRAV);
        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..ef28b9e 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;
 }
diff --git a/kernel/cobalt/sched-quota.c b/kernel/cobalt/sched-quota.c
index 4d908d9..80bb500 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_IGRAV);
        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_IGRAV);
        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..8d62d16 100644
--- a/kernel/cobalt/sched-sporadic.c
+++ b/kernel/cobalt/sched-sporadic.c
@@ -315,10 +315,10 @@ static int xnsched_sporadic_declare(struct xnthread 
*thread,
                return -ENOMEM;
 
        xntimer_init(&pss->repl_timer, &nkclock,
-                    sporadic_replenish_handler, thread);
+                    sporadic_replenish_handler, thread, XNTIMER_IGRAV);
        xntimer_set_name(&pss->repl_timer, "pss-replenish");
        xntimer_init(&pss->drop_timer, &nkclock,
-                    sporadic_drop_handler, thread);
+                    sporadic_drop_handler, thread, XNTIMER_IGRAV);
        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..f8834d8 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_IGRAV);
        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..bc35064 100644
--- a/kernel/cobalt/sched.c
+++ b/kernel/cobalt/sched.c
@@ -191,11 +191,11 @@ 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_IGRAV);
        xntimer_set_priority(&sched->htimer, XNTIMER_LOPRIO);
        xntimer_set_name(&sched->htimer, htimer_name);
        xntimer_init(&sched->rrbtimer, &nkclock,
-                    roundrobin_handler, &sched->rootcb);
+                    roundrobin_handler, &sched->rootcb, XNTIMER_IGRAV);
        xntimer_set_name(&sched->rrbtimer, rrbtimer_name);
        xntimer_set_priority(&sched->rrbtimer, XNTIMER_LOPRIO);
 
@@ -209,8 +209,9 @@ 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_IGRAV);
        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..a4470c4 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_UGRAV : XNTIMER_KGRAV);
        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_UGRAV : XNTIMER_KGRAV);
        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..a7eeb7c 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_IGRAV, the timer activates a leaf timer handler.
+ * - XNTIMER_KGRAV, the timer activates a kernel thread.
+ * - XNTIMER_UGRAV, 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);
        }
 
@@ -349,6 +368,17 @@ void __xntimer_init(struct xntimer *timer,
 }
 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,


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

Reply via email to