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

Author: Philippe Gerum <r...@xenomai.org>
Date:   Fri Aug  2 05:07:18 2013 +0200

cobalt/posix/clock: introduce dynamic clock registration

This patch provides the infrastructure for defining new POSIX clocks
dynamically, in addition to the standard CLOCK_MONOTONIC* and
CLOCK_REALTIME ones.

The API boils down cobalt_clock_register() and
cobalt_clock_deregister(), which operate on a Cobalt clock (struct
xnclock) internally.

---

 include/cobalt/kernel/assert.h  |    3 +
 include/cobalt/kernel/clock.h   |   43 +++++-
 include/cobalt/kernel/timer.h   |   73 ++++++---
 include/cobalt/uapi/time.h      |   18 ++-
 kernel/cobalt/clock.c           |   35 +++--
 kernel/cobalt/posix/clock.c     |  141 +++++++++++++----
 kernel/cobalt/posix/clock.h     |   17 ++-
 kernel/cobalt/posix/extension.h |   24 ++--
 kernel/cobalt/posix/thread.c    |   27 ++-
 kernel/cobalt/posix/thread.h    |   21 ++-
 kernel/cobalt/posix/timer.c     |  341 +++++++++++++++++++--------------------
 kernel/cobalt/posix/timer.h     |    6 +-
 kernel/cobalt/sched.c           |   12 +-
 kernel/cobalt/timer.c           |   32 +++-
 14 files changed, 498 insertions(+), 295 deletions(-)

diff --git a/include/cobalt/kernel/assert.h b/include/cobalt/kernel/assert.h
index 4d4cf9f..f7fd7f0 100644
--- a/include/cobalt/kernel/assert.h
+++ b/include/cobalt/kernel/assert.h
@@ -73,6 +73,9 @@
 
 #define primary_mode_only()    XENO_BUGON(CONTEXT, ipipe_root_p)
 #define secondary_mode_only()  XENO_BUGON(CONTEXT, !ipipe_root_p)
+#define interrupt_only()       XENO_BUGON(CONTEXT, !xnsched_interrupt_p())
+#define atomic_only()          XENO_BUGON(CONTEXT, (xnlock_is_owner(&nklock) \
+                                                    && spltest()) == 0)
 
 void __xnsys_assert_failed(const char *file, int line, const char *msg);
 
diff --git a/include/cobalt/kernel/clock.h b/include/cobalt/kernel/clock.h
index a33bbc1..fbe74d9 100644
--- a/include/cobalt/kernel/clock.h
+++ b/include/cobalt/kernel/clock.h
@@ -36,13 +36,17 @@ struct xntimerdata;
 
 struct xnclock {
        xnticks_t wallclock_offset;
-       struct xntimerdata *timerdata;
+       /** ns */
+       xnticks_t resolution;
+       /** raw clock ticks. */
        unsigned long gravity;
        const char *name;
 #ifdef CONFIG_XENO_OPT_EXTCLOCK
        struct {
                xnticks_t (*read_raw)(struct xnclock *clock);
                xnticks_t (*read_monotonic)(struct xnclock *clock);
+               int (*set_time)(struct xnclock *clock,
+                               const struct timespec *ts);
                xnsticks_t (*ns_to_ticks)(struct xnclock *clock,
                                          xnsticks_t ns);
                xnsticks_t (*ticks_to_ns)(struct xnclock *clock,
@@ -55,10 +59,13 @@ struct xnclock {
                                            struct xnsched *sched);
        } 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 timerq;
+       struct list_head statq;
        int nrtimers;
 #endif /* CONFIG_XENO_OPT_STATS */
 };
@@ -103,7 +110,7 @@ static inline void xnclock_program_shot(struct xnclock 
*clock,
                                        struct xnsched *sched)
 {
        if (likely(clock == &nkclock))
-               xnclock_core_local_shot(clock, sched);
+               xnclock_core_local_shot(sched);
        else if (clock->ops.program_local_shot)
                clock->ops.program_local_shot(clock, sched);
 }
@@ -113,7 +120,7 @@ static inline void xnclock_remote_shot(struct xnclock 
*clock,
 {
 #ifdef CONFIG_SMP
        if (likely(clock == &nkclock))
-               xnclock_core_remote_shot(clock, sched);
+               xnclock_core_remote_shot(sched);
        else if (clock->ops.program_remote_shot)
                clock->ops.program_remote_shot(clock, sched);
 #endif
@@ -162,6 +169,15 @@ static inline xnticks_t xnclock_read_monotonic(struct 
xnclock *clock)
        return clock->ops.read_monotonic(clock);
 }
 
+static inline int xnclock_set_time(struct xnclock *clock,
+                                  const struct timespec *ts)
+{
+       if (likely(clock == &nkclock))
+               return -EINVAL;
+
+       return clock->ops.set_time(clock, ts);
+}
+
 #else /* !CONFIG_XENO_OPT_EXTCLOCK */
 
 static inline void xnclock_program_shot(struct xnclock *clock,
@@ -206,6 +222,15 @@ static inline xnticks_t xnclock_read_monotonic(struct 
xnclock *clock)
        return xnclock_core_read_monotonic();
 }
 
+static inline int xnclock_set_time(struct xnclock *clock,
+                                  const struct timespec *ts)
+{
+       /*
+        * There is no way to change the core clock's idea of time.
+        */
+       return -EINVAL;
+}
+
 #endif /* !CONFIG_XENO_OPT_EXTCLOCK */
 
 static inline xnticks_t xnclock_get_offset(struct xnclock *clock)
@@ -213,6 +238,16 @@ static inline xnticks_t xnclock_get_offset(struct xnclock 
*clock)
        return clock->wallclock_offset;
 }
 
+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);
+}
+
 static inline xnticks_t xnclock_read_realtime(struct xnclock *clock)
 {
        /*
diff --git a/include/cobalt/kernel/timer.h b/include/cobalt/kernel/timer.h
index 4f029a8..7b3243f 100644
--- a/include/cobalt/kernel/timer.h
+++ b/include/cobalt/kernel/timer.h
@@ -180,32 +180,36 @@ xnclock_this_timerdata(struct xnclock *clock)
 }
 
 struct xntimer {
-
 #ifdef CONFIG_XENO_OPT_EXTCLOCK
        struct xnclock *clock;
 #endif
-
-       xntimerh_t aplink;      /* Link in timers list. */
-
+       /** Link in timers list. */
+       xntimerh_t aplink;
        struct list_head adjlink;
-
-       unsigned long status;   /* !< Timer status. */
-
-       xnticks_t interval;     /* !< Periodic interval (in ticks, 0 == one 
shot). */
-
-       xnticks_t pexpect;      /* !< Date of next periodic release point (raw 
ticks). */
-
-       struct xnsched *sched;  /* !< Sched structure to which the timer is
-                                  attached. */
-
-       void (*handler)(struct xntimer *timer); /* !< Timeout handler. */
-
+       /** Timer status. */
+       unsigned long status;
+       /** Periodic interval (raw ticks, 0 == one shot). */
+       xnticks_t interval;
+       /** Date of next periodic release point (raw ticks). */
+       xnticks_t pexpect;
+       /** Sched structure to which the timer is attached. */
+       struct xnsched *sched;
+       /** Timeout handler. */
+       void (*handler)(struct xntimer *timer);
 #ifdef CONFIG_XENO_OPT_STATS
-       char name[XNOBJECT_NAME_LEN]; /* !< Timer name to be displayed. */
-       const char *handler_name; /* !< Handler name to be displayed. */
-       struct list_head next_stat; /* !< Timer holder in timebase. */
-       xnstat_counter_t scheduled; /* !< Number of timer schedules. */
-       xnstat_counter_t fired; /* !< Number of timer events. */
+#ifdef CONFIG_XENO_OPT_EXTCLOCK
+       struct xnclock *tracker;
+#endif
+       /** Timer name to be displayed. */
+       char name[XNOBJECT_NAME_LEN];
+       /** Handler name to be displayed. */
+       const char *handler_name;
+       /** Timer holder in timebase. */
+       struct list_head next_stat;
+       /** Number of timer schedules. */
+       xnstat_counter_t scheduled;
+       /** Number of timer events. */
+       xnstat_counter_t fired;
 #endif /* CONFIG_XENO_OPT_STATS */
 };
 
@@ -290,6 +294,10 @@ static inline int xntimer_reload_p(struct xntimer *timer)
                (XNTIMER_PERIODIC|XNTIMER_DEQUEUED);
 }
 
+void __xntimer_init(struct xntimer *timer,
+                   struct xnclock *clock,
+                   void (*handler)(struct xntimer *timer));
+
 #ifdef CONFIG_XENO_OPT_STATS
 
 #define xntimer_init(timer, clock, handler)            \
@@ -298,6 +306,12 @@ static inline int xntimer_reload_p(struct xntimer *timer)
                (timer)->handler_name = #handler;       \
        } while (0)
 
+static inline void xntimer_reset_stats(struct xntimer *timer)
+{
+       xnstat_counter_set(&timer->scheduled, 0);
+       xnstat_counter_set(&timer->fired, 0);
+}
+
 static inline void xntimer_account_scheduled(struct xntimer *timer)
 {
        xnstat_counter_inc(&timer->scheduled);
@@ -317,6 +331,8 @@ static inline void xntimer_set_name(struct xntimer *timer, 
const char *name)
 
 #define xntimer_init   __xntimer_init
 
+static inline void xntimer_reset_stats(struct xntimer *timer) { }
+
 static inline void xntimer_account_scheduled(struct xntimer *timer) { }
 
 static inline void xntimer_account_fired(struct xntimer *timer) { }
@@ -325,15 +341,20 @@ static inline void xntimer_set_name(struct xntimer 
*timer, const char *name) { }
 
 #endif /* !CONFIG_XENO_OPT_STATS */
 
+#if defined(CONFIG_XENO_OPT_EXTCLOCK) && defined(CONFIG_XENO_OPT_STATS)
+void xntimer_switch_tracking(struct xntimer *timer,
+                            struct xnclock *newclock);
+#else
+static inline
+void xntimer_switch_tracking(struct xntimer *timer,
+                            struct xnclock *newclock) { }
+#endif
+
 #define xntimer_init_noblock(timer, clock, handler)    \
        do {                                            \
                xntimer_init(timer, clock, handler);    \
                (timer)->status |= XNTIMER_NOBLCK;      \
-       } while(0)
-
-void __xntimer_init(struct xntimer *timer,
-                   struct xnclock *clock,
-                   void (*handler)(struct xntimer *timer));
+       } while (0)
 
 void xntimer_destroy(struct xntimer *timer);
 
diff --git a/include/cobalt/uapi/time.h b/include/cobalt/uapi/time.h
index 630f2b1..349d659 100644
--- a/include/cobalt/uapi/time.h
+++ b/include/cobalt/uapi/time.h
@@ -23,10 +23,20 @@
 #endif
 
 /*
- * This clock id. is supposed not to collide with any of the POSIX and
- * Linux kernel definitions so that no ambiguities arise when porting
- * applications in both directions.
+ * Additional clock ids we manage are supposed not to collide with any
+ * of the POSIX and Linux kernel definitions so that no ambiguities
+ * arise when porting applications in both directions.
+ *
+ * The Cobalt API reserves the first 32 extended clock codes. for
+ * dynamically registered clocks. Everything from
+ * __COBALT_CLOCK_CODE(32) onward can be reserved statically for
+ * whatever purpose.
  */
-#define CLOCK_HOST_REALTIME 42
+#define COBALT_MAX_EXTCLOCKS  32
+#define __COBALT_CLOCK_CODE(num)  ((clockid_t)((1 << 16)|num))
+#define __COBALT_CLOCK_INDEX(id)  ((int)(id) & ~(1 << 16))
+#define __COBALT_CLOCK_EXT_P(id)  ((int)(id) & (1 << 16))
+
+#define CLOCK_HOST_REALTIME  __COBALT_CLOCK_CODE(42)
 
 #endif /* !_COBALT_UAPI_TIME_H */
diff --git a/kernel/cobalt/clock.c b/kernel/cobalt/clock.c
index bd06a96..b189500 100644
--- a/kernel/cobalt/clock.c
+++ b/kernel/cobalt/clock.c
@@ -348,7 +348,7 @@ struct vfile_clock_data {
        xnticks_t timeout;
        xnticks_t interval;
        unsigned long status;
-       char handler[12];
+       char handler[XNOBJECT_NAME_LEN];
        char name[XNOBJECT_NAME_LEN];
 };
 
@@ -357,10 +357,10 @@ static int clock_vfile_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->timerq))
+       if (list_empty(&clock->statq))
                return -ESRCH;
 
-       priv->curr = list_first_entry(&clock->timerq, struct xntimer, 
next_stat);
+       priv->curr = list_first_entry(&clock->statq, struct xntimer, next_stat);
 
        return clock->nrtimers;
 }
@@ -376,7 +376,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->timerq))
+       if (list_is_last(&timer->next_stat, &clock->statq))
                priv->curr = NULL;
        else
                priv->curr = list_entry(timer->next_stat.next,
@@ -391,9 +391,7 @@ static int clock_vfile_next(struct 
xnvfile_snapshot_iterator *it, void *data)
        p->timeout = xntimer_get_timeout(timer);
        p->interval = xntimer_get_interval(timer);
        p->status = timer->status;
-       memcpy(p->handler, timer->handler_name,
-              sizeof(p->handler)-1);
-       p->handler[sizeof(p->handler)-1] = 0;
+       strncpy(p->handler, timer->handler_name, 16)[17] = '\0';
        xnobject_copy_name(p->name, timer->name);
 
        return 1;
@@ -404,22 +402,25 @@ static int clock_vfile_show(struct 
xnvfile_snapshot_iterator *it, void *data)
        struct vfile_clock_data *p = data;
        char timeout_buf[]  = "-         ";
        char interval_buf[] = "-         ";
+       char hit_buf[32];
 
        if (p == NULL)
                xnvfile_printf(it,
-                              "%-3s  %-10s  %-10s  %-10s  %-10s  %-11s  
%-15s\n",
-                              "CPU", "SCHEDULED", "FIRED", "TIMEOUT",
+                              "%-3s  %-20s  %-10s  %-10s  %-16s  %s\n",
+                              "CPU", "SCHED/SHOT", "TIMEOUT",
                               "INTERVAL", "HANDLER", "NAME");
        else {
                if ((p->status & XNTIMER_DEQUEUED) == 0)
-                       snprintf(timeout_buf, sizeof(timeout_buf), "%-10llu",
-                                p->timeout);
+                       xntimer_format_time(p->timeout, timeout_buf,
+                                           sizeof(timeout_buf));
                if (p->status & XNTIMER_PERIODIC)
-                       snprintf(interval_buf, sizeof(interval_buf), "%-10llu",
-                                p->interval);
+                       xntimer_format_time(p->interval, interval_buf,
+                                           sizeof(interval_buf));
+               snprintf(hit_buf, sizeof(hit_buf), "%u/%u",
+                        p->scheduled, p->fired);
                xnvfile_printf(it,
-                              "%-3u  %-10u  %-10u  %s  %s  %-11s  %-15s\n",
-                              p->cpu, p->scheduled, p->fired, timeout_buf,
+                              "%-3u  %-20s  %-10s  %-10s  %-16s  %s\n",
+                              p->cpu, hit_buf, timeout_buf,
                               interval_buf, p->handler, p->name);
        }
 
@@ -504,7 +505,7 @@ int xnclock_register(struct xnclock *clock)
        }
 
 #ifdef CONFIG_XENO_OPT_STATS
-       INIT_LIST_HEAD(&clock->timerq);
+       INIT_LIST_HEAD(&clock->statq);
 #endif /* CONFIG_XENO_OPT_STATS */
 
        init_clock_proc(clock);
@@ -680,6 +681,8 @@ EXPORT_SYMBOL_GPL(xnclock_tick);
 
 struct xnclock nkclock = {
        .name = "coreclk",
+       .resolution = 1,        /* nanosecond. */
+       .id = -1,
 };
 EXPORT_SYMBOL_GPL(nkclock);
 
diff --git a/kernel/cobalt/posix/clock.c b/kernel/cobalt/posix/clock.c
index bf5b609..bacf6b0 100644
--- a/kernel/cobalt/posix/clock.c
+++ b/kernel/cobalt/posix/clock.c
@@ -22,7 +22,7 @@
  *
  * Clocks and timers services.
  *
- * Cobalt supports three clocks:
+ * Cobalt supports three built-in clocks:
  *
  * CLOCK_REALTIME maps to the nucleus system clock, keeping time as the amount
  * of time since the Epoch, with a resolution of one nanosecond.
@@ -38,21 +38,33 @@
  * strictly equivalent to CLOCK_MONOTONIC with Xenomai, which is not
  * NTP adjusted either.
  *
+ * In addition, external clocks can be dynamically registered using
+ * the cobalt_clock_register() service. These clocks are fully managed
+ * by Cobalt extension code, which should advertise each incoming tick
+ * by calling xnclock_tick() for the relevant clock, from an interrupt
+ * context.
+ *
  * Timer objects may be created with the timer_create() service using
- * either of the two clocks. The resolution of these timers is one
- * nanosecond, as is the case for clock_nanosleep().
+ * any of the built-in or external clocks. The resolution of these
+ * timers is clock-specific. However, built-in clocks all have
+ * nanosecond resolution, as specified for clock_nanosleep().
  *
  * @see
  * <a 
href="http://www.opengroup.org/onlinepubs/000095399/functions/xsh_chap02_08.html#tag_02_08_05";>
  * Specification.</a>
  *
  *@{*/
-
+#include <linux/bitmap.h>
 #include <cobalt/kernel/vdso.h>
+#include <cobalt/kernel/clock.h>
 #include "internal.h"
 #include "thread.h"
 #include "clock.h"
 
+static struct xnclock *external_clocks[COBALT_MAX_EXTCLOCKS];
+
+DECLARE_BITMAP(cobalt_clock_extids, COBALT_MAX_EXTCLOCKS);
+
 /**
  * Read the host-synchronised realtime clock.
  *
@@ -120,80 +132,112 @@ static int do_clock_host_realtime(struct timespec *tp)
 #endif
 }
 
+#define do_ext_clock(__clock_id, __handler, __ret, __args...)  \
+({                                                             \
+       struct xnclock *__clock;                                \
+       int __val = 0, __nr;                                    \
+       spl_t __s;                                              \
+                                                               \
+       if (!__COBALT_CLOCK_EXT_P(__clock_id))                  \
+               __val = -EINVAL;                                \
+       else {                                                  \
+               __nr = __COBALT_CLOCK_INDEX(__clock_id);        \
+               xnlock_get_irqsave(&nklock, __s);               \
+               if (!test_bit(__nr, cobalt_clock_extids)) {     \
+                       xnlock_put_irqrestore(&nklock, __s);    \
+                       __val = -EINVAL;                        \
+               } else {                                        \
+                       __clock = external_clocks[__nr];        \
+                       (__ret) = xnclock_ ## __handler(__clock, ##__args); \
+                       xnlock_put_irqrestore(&nklock, __s);    \
+               }                                               \
+       }                                                       \
+       __val;                                                  \
+})
+
 int cobalt_clock_getres(clockid_t clock_id, struct timespec __user *u_ts)
 {
        struct timespec ts;
-       int err;
+       xnticks_t ns;
+       int ret;
 
        switch (clock_id) {
        case CLOCK_REALTIME:
        case CLOCK_MONOTONIC:
        case CLOCK_MONOTONIC_RAW:
-               err = 0;
                ns2ts(&ts, 1);
                break;
        default:
-               err = -EINVAL;
+               ret = do_ext_clock(clock_id, get_resolution, ns);
+               if (ret)
+                       return ret;
+               ns2ts(&ts, ns);
        }
 
-       if (err == 0 && __xn_safe_copy_to_user(u_ts, &ts, sizeof(ts)))
+       if (__xn_safe_copy_to_user(u_ts, &ts, sizeof(ts)))
                return -EFAULT;
 
-       return err;
+       return 0;
 }
 
 int cobalt_clock_gettime(clockid_t clock_id, struct timespec __user *u_ts)
 {
-       xnticks_t cpu_time;
        struct timespec ts;
-       int err = 0;
+       xnticks_t ns;
+       int ret;
 
        switch (clock_id) {
        case CLOCK_REALTIME:
                ns2ts(&ts, xnclock_read_realtime(&nkclock));
                break;
-
        case CLOCK_MONOTONIC:
        case CLOCK_MONOTONIC_RAW:
-               cpu_time = xnclock_read_monotonic(&nkclock);
-               ts.tv_sec =
-                       xnarch_uldivrem(cpu_time, ONE_BILLION, &ts.tv_nsec);
+               ns2ts(&ts, xnclock_read_monotonic(&nkclock));
                break;
-
        case CLOCK_HOST_REALTIME:
                if (do_clock_host_realtime(&ts) != 0)
-                       err = -EINVAL;
+                       return -EINVAL;
                break;
-
        default:
-               err = -EINVAL;
+               ret = do_ext_clock(clock_id, read_monotonic, ns);
+               if (ret)
+                       return ret;
+               ns2ts(&ts, ns);
        }
 
-       if (err == 0 && __xn_safe_copy_to_user(u_ts, &ts, sizeof(*u_ts)))
+       if (__xn_safe_copy_to_user(u_ts, &ts, sizeof(*u_ts)))
                return -EFAULT;
 
-       return err;
+       return ret;
 }
 
 int cobalt_clock_settime(clockid_t clock_id, const struct timespec __user 
*u_ts)
 {
        struct timespec ts;
+       int _ret, ret = 0;
        xnticks_t now;
        spl_t s;
 
        if (__xn_safe_copy_from_user(&ts, u_ts, sizeof(ts)))
                return -EFAULT;
 
-       if (clock_id != CLOCK_REALTIME
-           || (unsigned long)ts.tv_nsec >= ONE_BILLION)
+       if ((unsigned long)ts.tv_nsec >= ONE_BILLION)
                return -EINVAL;
 
-       xnlock_get_irqsave(&nklock, s);
-       now = xnclock_read_realtime(&nkclock);
-       xnclock_adjust(&nkclock, (xnsticks_t) (ts2ns(&ts) - now));
-       xnlock_put_irqrestore(&nklock, s);
+       switch (clock_id) {
+       case CLOCK_REALTIME:
+               xnlock_get_irqsave(&nklock, s);
+               now = xnclock_read_realtime(&nkclock);
+               xnclock_adjust(&nkclock, (xnsticks_t) (ts2ns(&ts) - now));
+               xnlock_put_irqrestore(&nklock, s);
+               break;
+       default:
+               _ret = do_ext_clock(clock_id, set_time, ret, &ts);
+               if (_ret)
+                       ret = _ret;
+       }
 
-       return 0;
+       return ret;
 }
 
 int cobalt_clock_nanosleep(clockid_t clock_id, int flags,
@@ -248,4 +292,45 @@ int cobalt_clock_nanosleep(clockid_t clock_id, int flags,
        return err;
 }
 
+int cobalt_clock_register(struct xnclock *clock, clockid_t *clk_id)
+{
+       int ret, nr;
+       spl_t s;
+
+       xnlock_get_irqsave(&nklock, s);
+
+       nr = find_first_zero_bit(cobalt_clock_extids, COBALT_MAX_EXTCLOCKS);
+       if (nr >= COBALT_MAX_EXTCLOCKS) {
+               xnlock_put_irqrestore(&nklock, s);
+               return -EAGAIN;
+       }
+
+       /*
+        * CAUTION: a bit raised in cobalt_clock_extids means that the
+        * corresponding entry in external_clocks[] is valid. The
+        * converse assumption is NOT true.
+        */
+       __set_bit(nr, cobalt_clock_extids);
+       external_clocks[nr] = clock;
+
+       xnlock_put_irqrestore(&nklock, s);
+
+       ret = xnclock_register(clock);
+       if (ret)
+               return ret;
+
+       clock->id = nr;
+       *clk_id = __COBALT_CLOCK_CODE(clock->id);
+
+       return 0;
+}
+
+void cobalt_clock_deregister(struct xnclock *clock)
+{
+       clear_bit(clock->id, cobalt_clock_extids);
+       smp_mb__after_clear_bit();
+       external_clocks[clock->id] = NULL;
+       xnclock_deregister(clock);
+}
+
 /*@}*/
diff --git a/kernel/cobalt/posix/clock.h b/kernel/cobalt/posix/clock.h
index 94ea521..fae85a7 100644
--- a/kernel/cobalt/posix/clock.h
+++ b/kernel/cobalt/posix/clock.h
@@ -18,6 +18,7 @@
 #ifndef _COBALT_POSIX_CLOCK_H
 #define _COBALT_POSIX_CLOCK_H
 
+#include <linux/types.h>
 #include <linux/time.h>
 #include <cobalt/uapi/time.h>
 
@@ -82,14 +83,24 @@ static inline int clock_flag(int flag, clockid_t clock_id)
        return -EINVAL;
 }
 
-int cobalt_clock_getres(clockid_t clock_id, struct timespec __user *u_ts);
+int cobalt_clock_getres(clockid_t clock_id,
+                       struct timespec __user *u_ts);
 
-int cobalt_clock_gettime(clockid_t clock_id, struct timespec __user *u_ts);
+int cobalt_clock_gettime(clockid_t clock_id,
+                        struct timespec __user *u_ts);
 
-int cobalt_clock_settime(clockid_t clock_id, const struct timespec __user 
*u_ts);
+int cobalt_clock_settime(clockid_t clock_id,
+                        const struct timespec __user *u_ts);
 
 int cobalt_clock_nanosleep(clockid_t clock_id, int flags,
                           const struct timespec __user *u_rqt,
                           struct timespec __user *u_rmt);
 
+int cobalt_clock_register(struct xnclock *clock,
+                         clockid_t *clk_id);
+
+void cobalt_clock_deregister(struct xnclock *clock);
+
+extern DECLARE_BITMAP(cobalt_clock_extids, COBALT_MAX_EXTCLOCKS);
+
 #endif /* !_COBALT_POSIX_CLOCK_H */
diff --git a/kernel/cobalt/posix/extension.h b/kernel/cobalt/posix/extension.h
index d9f7238..8c85425 100644
--- a/kernel/cobalt/posix/extension.h
+++ b/kernel/cobalt/posix/extension.h
@@ -19,6 +19,7 @@
 #define _COBALT_POSIX_EXTENSION_H
 
 #include <linux/time.h>
+#include <linux/list.h>
 #include <cobalt/kernel/shadow.h>
 
 #ifdef CONFIG_XENO_OPT_COBALT_EXTENSION
@@ -33,9 +34,14 @@ struct cobalt_extension {
        struct xnpersonality core;
        struct {
                struct cobalt_thread *
-               (*timer_init)(struct cobalt_extref *reftimer,
+               (*timer_init)(struct cobalt_extref *reftimer, /* nklocked, IRQs 
off. */
                              const struct sigevent *__restrict__ evp);
-               int (*timer_cleanup)(struct cobalt_extref *reftimer);
+               int (*timer_settime)(struct cobalt_extref *reftimer, /* 
nklocked, IRQs off. */
+                                    const struct itimerspec *__restrict__ 
value,
+                                    int flags);
+               int (*timer_gettime)(struct cobalt_extref *reftimer, /* 
nklocked, IRQs off. */
+                                    struct itimerspec *__restrict__ value);
+               int (*timer_cleanup)(struct cobalt_extref *reftimer); /* 
nklocked, IRQs off. */
                int (*signal_deliver)(struct cobalt_extref *refthread,
                                      struct siginfo *si,
                                      struct cobalt_sigpending *sigp);
@@ -50,7 +56,7 @@ struct cobalt_extension {
 
 struct cobalt_extref {
        struct cobalt_extension *extension;
-       struct cobalt_thread *owner;
+       struct list_head next;
        void *private;
 };
 
@@ -60,11 +66,10 @@ static inline void cobalt_set_extref(struct cobalt_extref 
*ref,
 {
        ref->extension = ext;
        ref->private = priv;
-       ref->owner = NULL;
 }
 
 /**
- * Both macros return non-zero if some thread-level extension code was
+ * All macros return non-zero if some thread-level extension code was
  * called, leaving the output value into __ret. Otherwise, the __ret
  * value is undefined.
  */
@@ -73,16 +78,13 @@ static inline void cobalt_set_extref(struct cobalt_extref 
*ref,
                int __val = 0;                                                  
\
                if ((__owner) && (__owner)->extref.extension) {                 
\
                        (__extref)->extension = (__owner)->extref.extension;    
\
-                       (__extref)->owner = (__owner);                          
\
                        if ((__extref)->extension->ops.__extfn) {               
\
                                (__ret) = (__extref)->extension->ops.           
\
                                        __extfn(__extref, ##__args );           
\
                                __val = 1;                                      
\
                        }                                                       
\
-               } else {                                                        
\
+               } else                                                          
\
                        (__extref)->extension = NULL;                           
\
-                       (__extref)->owner = NULL;                               
\
-               }                                                               
\
                __val;                                                          
\
        })
                
@@ -97,7 +99,7 @@ static inline void cobalt_set_extref(struct cobalt_extref 
*ref,
                }                                                       \
                __val;                                                  \
        })
-               
+
 #else /* !CONFIG_XENO_OPT_COBALT_EXTENSION */
 
 struct cobalt_extension;
@@ -114,7 +116,7 @@ static inline void cobalt_set_extref(struct cobalt_extref 
*ref,
 #define cobalt_initcall_extension(__extfn, __extref, __owner, __ret, 
__args...)        \
        ({ (void)(__owner); (void)(__ret); 0; })
 
-#define cobalt_call_extension(__extfn, __extref, __ret, __args...)             
\
+#define cobalt_call_extension(__extfn, __extref, __ret, __args...)     \
        ({ (void)(__ret); 0; })
 
 #endif /* !CONFIG_XENO_OPT_COBALT_EXTENSION */
diff --git a/kernel/cobalt/posix/thread.c b/kernel/cobalt/posix/thread.c
index 3c6cd55..444a79a 100644
--- a/kernel/cobalt/posix/thread.c
+++ b/kernel/cobalt/posix/thread.c
@@ -159,7 +159,7 @@ static inline void thread_unhash(const struct 
cobalt_local_hkey *hkey)
 }
 
 static struct cobalt_thread *
-thread_find_local(const struct cobalt_local_hkey *hkey)
+thread_lookup(const struct cobalt_local_hkey *hkey)
 {
        struct local_thread_hash *lslot;
        struct cobalt_thread *thread;
@@ -197,6 +197,18 @@ struct cobalt_thread *cobalt_thread_find(pid_t pid) /* 
nklocked, IRQs off */
 }
 EXPORT_SYMBOL_GPL(cobalt_thread_find);
 
+struct cobalt_thread *cobalt_thread_find_local(pid_t pid) /* nklocked, IRQs 
off */
+{
+       struct cobalt_thread *thread;
+
+       thread = cobalt_thread_find(pid);
+       if (thread == NULL || thread->hkey.mm != current->mm)
+               return NULL;
+
+       return thread;
+}
+EXPORT_SYMBOL_GPL(cobalt_thread_find_local);
+
 struct xnpersonality *cobalt_thread_exit(struct xnthread *curr)
 {
        struct cobalt_thread *thread;
@@ -209,7 +221,6 @@ struct xnpersonality *cobalt_thread_exit(struct xnthread 
*curr)
        thread_unhash(&thread->hkey);
        cobalt_mark_deleted(thread);
        cobalt_signal_flush(thread);
-       cobalt_timer_flush(thread);
        xnsynch_destroy(&thread->monitor_synch);
        xnsynch_destroy(&thread->sigwait);
        list_del(&thread->link);
@@ -461,8 +472,6 @@ static inline int pthread_create(struct cobalt_thread 
**thread_p, const pthread_
        for (n = 0; n < _NSIG; n++)
                INIT_LIST_HEAD(thread->sigqueues + n);
 
-       INIT_LIST_HEAD(&thread->timersq);
-
        cobalt_set_extref(&thread->extref, NULL, NULL);
 
        if (thread->attr.policy == SCHED_RR)
@@ -804,7 +813,7 @@ int cobalt_thread_setschedparam_ex(unsigned long pth,
 
        hkey.u_pth = pth;
        hkey.mm = current->mm;
-       thread = thread_find_local(&hkey);
+       thread = thread_lookup(&hkey);
 
        if (thread == NULL && u_window_offset) {
                thread = cobalt_thread_shadow(current, &hkey, u_window_offset);
@@ -948,7 +957,7 @@ int cobalt_thread_make_periodic_np(unsigned long pth,
 
        hkey.u_pth = pth;
        hkey.mm = current->mm;
-       thread = thread_find_local(&hkey);
+       thread = thread_lookup(&hkey);
 
        if (__xn_safe_copy_from_user(&startt, u_startt, sizeof(startt)))
                return -EFAULT;
@@ -1003,7 +1012,7 @@ int cobalt_thread_set_name_np(unsigned long pth, const 
char __user *u_name)
 
        xnlock_get_irqsave(&nklock, s);
 
-       thread = thread_find_local(&hkey);
+       thread = thread_lookup(&hkey);
        if (thread == NULL) {
                xnlock_put_irqrestore(&nklock, s);
                return -ESRCH;
@@ -1057,7 +1066,7 @@ int cobalt_thread_kill(unsigned long pth, int sig)
 
        hkey.u_pth = pth;
        hkey.mm = current->mm;
-       thread = thread_find_local(&hkey);
+       thread = thread_lookup(&hkey);
        if (thread == NULL) {
                ret = -ESRCH;
                goto out;
@@ -1189,7 +1198,7 @@ int cobalt_thread_getschedparam_ex(unsigned long pth,
 
        hkey.u_pth = pth;
        hkey.mm = current->mm;
-       thread = thread_find_local(&hkey);
+       thread = thread_lookup(&hkey);
        if (thread == NULL)
                return -ESRCH;
 
diff --git a/kernel/cobalt/posix/thread.h b/kernel/cobalt/posix/thread.h
index 1ae2f11..ef52b3c 100644
--- a/kernel/cobalt/posix/thread.h
+++ b/kernel/cobalt/posix/thread.h
@@ -109,9 +109,6 @@ struct cobalt_thread {
         /** Creation attributes. */
        pthread_attr_t attr;
 
-       /** Active timers. */
-       struct list_head timersq;
-
        /** Signal management. */
        sigset_t sigpending;
        struct list_head sigqueues[_NSIG]; /* cobalt_sigpending */
@@ -142,6 +139,8 @@ static inline struct cobalt_thread 
*cobalt_current_thread(void)
 
 struct cobalt_thread *cobalt_thread_find(pid_t pid);
 
+struct cobalt_thread *cobalt_thread_find_local(pid_t pid);
+
 int cobalt_thread_create(unsigned long tid, int policy,
                         struct sched_param_ex __user *u_param,
                         unsigned long __user *u_window_offset);
@@ -202,6 +201,22 @@ void cobalt_thread_extend(struct cobalt_thread *thread,
 
 void cobalt_thread_restrict(struct cobalt_thread *thread);
 
+static inline
+int cobalt_thread_extended_p(const struct cobalt_thread *thread,
+                            const struct cobalt_extension *ext)
+{
+       return thread->extref.extension == ext;
+}
+
+#else /* !CONFIG_XENO_OPT_COBALT_EXTENSION */
+
+static inline
+int cobalt_thread_extended_p(const struct cobalt_thread *thread,
+                            const struct cobalt_extension *ext)
+{
+       return 0;
+}
+
 #endif /* !CONFIG_XENO_OPT_COBALT_EXTENSION */
 
 extern xnticks_t cobalt_time_slice;
diff --git a/kernel/cobalt/posix/timer.c b/kernel/cobalt/posix/timer.c
index 9b64ede..0abb70c 100644
--- a/kernel/cobalt/posix/timer.c
+++ b/kernel/cobalt/posix/timer.c
@@ -21,6 +21,7 @@
  *
  *@{*/
 
+#include <linux/module.h>
 #include <linux/cred.h>
 #include <linux/err.h>
 #include "internal.h"
@@ -33,13 +34,20 @@ struct cobalt_timer *cobalt_timer_pool;
 
 static struct list_head timer_freeq;
 
-static void timer_handler(struct xntimer *xntimer)
+void cobalt_timer_handler(struct xntimer *xntimer)
 {
        struct cobalt_timer *timer;
-
+       /*
+        * Deliver the timer notification via a signal. If we can't do
+        * this because the target thread disappeared, then stop the
+        * timer. It will go away when timer_delete() is called, or
+        * the owner's process exits, whichever comes first.
+        */
        timer = container_of(xntimer, struct cobalt_timer, timerbase);
-       cobalt_signal_send_pid(timer->target, &timer->sigp);
+       if (cobalt_signal_send_pid(timer->target, &timer->sigp) == -ESRCH)
+               xntimer_stop(&timer->timerbase);
 }
+EXPORT_SYMBOL_GPL(cobalt_timer_handler);
 
 static inline struct cobalt_thread *
 timer_init(struct cobalt_timer *timer,
@@ -52,16 +60,22 @@ timer_init(struct cobalt_timer *timer,
         * personality the current thread might originate from.
         */
        if (cobalt_initcall_extension(timer_init, &timer->extref,
-                                     owner, target, evp))
+                                     owner, target, evp) && target)
                return target;
 
        /*
-        * Ok, this did not work out, handle this the pure Cobalt way
-        * then. We currently supports SIGEV_THREAD_ID only when evp
-        * is specified.
+        * Ok, we have no extension available, or we do but it does
+        * not want to overload the standard behavior: handle this
+        * timer the pure Cobalt way then. We only know about standard
+        * clocks in this case.
         */
+       if (timer->clockid != CLOCK_MONOTONIC &&
+           timer->clockid != CLOCK_MONOTONIC_RAW &&
+           timer->clockid != CLOCK_REALTIME)
+               return ERR_PTR(-EINVAL);
+
        if (evp == NULL)
-               return owner;
+               return owner;   /* Assume SIGEV_THREAD_ID. */
 
        if (evp->sigev_notify != SIGEV_THREAD_ID)
                return ERR_PTR(-EINVAL);
@@ -70,10 +84,16 @@ timer_init(struct cobalt_timer *timer,
         * Recipient thread must be a Xenomai shadow in user-space,
         * living in the same process than our caller.
         */
-       target = cobalt_thread_find(evp->sigev_notify_thread_id);
-       if (target == NULL || target->hkey.mm != current->mm)
+       target = cobalt_thread_find_local(evp->sigev_notify_thread_id);
+       if (target == NULL)
                return ERR_PTR(-EINVAL);
 
+       /*
+        * All standard clocks are based on the core clock, and we
+        * want to deliver a signal when a timer elapses.
+        */
+       xntimer_init(&timer->timerbase, &nkclock, cobalt_timer_handler);
+
        return target;
 }
 
@@ -129,11 +149,6 @@ static inline int timer_create(clockid_t clockid,
        timer_t timer_id;
        spl_t s;
 
-       if (clockid != CLOCK_MONOTONIC &&
-           clockid != CLOCK_MONOTONIC_RAW &&
-           clockid != CLOCK_REALTIME)
-               return -EINVAL;
-
        xnlock_get_irqsave(&nklock, s);
 
        if (list_empty(&timer_freeq)) {
@@ -173,9 +188,7 @@ static inline int timer_create(clockid_t clockid,
                goto unlock_and_error;
        }
 
-       xntimer_init(&timer->timerbase, &nkclock, timer_handler);
        timer->target = xnthread_host_pid(&target->threadbase);
-       timer->owner = NULL;
        timer->owningq = cobalt_kqueues(0);
        list_del(&timer->link);
        list_add_tail(&timer->link, &cobalt_kqueues(0)->timerq);
@@ -191,11 +204,25 @@ unlock_and_error:
        return ret;
 }
 
+static void timer_cleanup(struct cobalt_timer *timer)
+{
+       int ret;
+
+       xntimer_destroy(&timer->timerbase);
+
+       list_del(&timer->link);
+
+       if (!list_empty(&timer->sigp.next))
+               list_del(&timer->sigp.next);
+
+       cobalt_call_extension(timer_cleanup, &timer->extref, ret);
+       list_add(&timer->link, &timer_freeq); /* Favour earliest reuse. */
+}
+
 static inline int
-timer_delete(timer_t timerid, struct cobalt_kqueues *q, int force)
+timer_delete(timer_t timerid)
 {
        struct cobalt_timer *timer;
-       int ret = 0;
        spl_t s;
 
        if ((unsigned int)timerid >= CONFIG_XENO_OPT_NRTIMERS)
@@ -205,50 +232,97 @@ timer_delete(timer_t timerid, struct cobalt_kqueues *q, 
int force)
 
        timer = &cobalt_timer_pool[(unsigned int)timerid];
 
-       if (!xntimer_active_p(&timer->timerbase)) {
-               ret = -EINVAL;
-               goto out;
-       }
-
-       if (!force && timer->owningq != cobalt_kqueues(0)) {
-               ret = -EPERM;
-               goto out;
-       }
-
-       xntimer_destroy(&timer->timerbase);
-
-       list_del(&timer->link);
-
-       if (timer->owner)
-               list_del(&timer->tlink);
+       if (!xntimer_active_p(&timer->timerbase) ||
+           timer->owningq != cobalt_kqueues(0))
+               goto fail;
 
-       if (!list_empty(&timer->sigp.next))
-               list_del(&timer->sigp.next);
+       timer_cleanup(timer);
 
-       timer->owner = NULL;
-       cobalt_call_extension(timer_cleanup, &timer->extref, ret);
-       list_add(&timer->link, &timer_freeq); /* Favour earliest reuse. */
-out:
+       return 0;
+fail:
        xnlock_put_irqrestore(&nklock, s);
 
-       return ret;
+       return -EINVAL;
 }
 
 static inline void
 timer_gettimeout(struct cobalt_timer *__restrict__ timer,
                 struct itimerspec *__restrict__ value)
 {
-       if (xntimer_running_p(&timer->timerbase)) {
-               ns2ts(&value->it_value,
-                     xntimer_get_timeout(&timer->timerbase));
-               ns2ts(&value->it_interval,
-                     xntimer_interval(&timer->timerbase));
-       } else {
+       int ret;
+
+       if (!xntimer_running_p(&timer->timerbase)) {
                value->it_value.tv_sec = 0;
                value->it_value.tv_nsec = 0;
                value->it_interval.tv_sec = 0;
                value->it_interval.tv_nsec = 0;
+               return;
        }
+
+       if (!cobalt_call_extension(timer_gettime, &timer->extref,
+                                  ret, value) || ret == 0) {
+               ns2ts(&value->it_value,
+                     xntimer_get_timeout(&timer->timerbase));
+               ns2ts(&value->it_interval,
+                     xntimer_interval(&timer->timerbase));
+       }
+}
+
+static inline int timer_set(struct cobalt_timer *timer, int flags,
+                           const struct itimerspec *__restrict__ value)
+{                              /* nklocked, IRQs off. */
+       xnticks_t start, period;
+       int ret;
+
+       /* First, try offloading the work to an extension. */
+
+       if (cobalt_call_extension(timer_settime, &timer->extref,
+                                 ret, value, flags) && ret != 0)
+               return ret < 0 ? ret : 0;
+
+       /*
+        * No extension, or operation not handled. Default to plain
+        * POSIX behavior.
+        */
+
+       if (value->it_value.tv_nsec == 0 && value->it_value.tv_sec == 0) {
+               xntimer_stop(&timer->timerbase);
+               return 0;
+       }
+
+       if ((unsigned long)value->it_value.tv_nsec >= ONE_BILLION ||
+           ((unsigned long)value->it_interval.tv_nsec >= ONE_BILLION &&
+            (value->it_value.tv_sec != 0 || value->it_value.tv_nsec != 0)))
+               return -EINVAL;
+
+       start = ts2ns(&value->it_value) + 1;
+       period = ts2ns(&value->it_interval);
+       xntimer_set_sched(&timer->timerbase, xnsched_current());
+       /*
+        * Now start the timer. If the timeout data has already
+        * passed, the caller will handle the case.
+        */
+       return xntimer_start(&timer->timerbase, start, period,
+                            clock_flag(flags, timer->clockid));
+}
+
+static inline void
+timer_deliver_late(timer_t timerid)
+{
+       struct cobalt_timer *timer;
+       spl_t s;
+
+       xnlock_get_irqsave(&nklock, s);
+       /*
+        * We dropped the lock shortly, revalidate the timer handle in
+        * case a deletion slipped in.
+        */
+       timer = &cobalt_timer_pool[(unsigned int)timerid];
+
+       if (xntimer_active_p(&timer->timerbase))
+               cobalt_timer_handler(&timer->timerbase);
+
+       xnlock_put_irqrestore(&nklock, s);
 }
 
 /**
@@ -286,10 +360,8 @@ timer_gettimeout(struct cobalt_timer *__restrict__ timer,
  *
  * @retval 0 on success;
  * @retval -1 with @a errno set if:
- * - EPERM, the caller context is invalid;
  * - EINVAL, the specified timer identifier, expiration date or reload value is
- *   invalid;
- * - EPERM, the timer @a timerid does not belong to the current process.
+ *   invalid. For @a timerid to be valid, it must belong to the current 
process.
  *
  * @par Valid contexts:
  * - Cobalt kernel-space thread,
@@ -307,89 +379,41 @@ timer_settime(timer_t timerid, int flags,
              const struct itimerspec *__restrict__ value,
              struct itimerspec *__restrict__ ovalue)
 {
-       struct cobalt_thread *cur = cobalt_current_thread();
-       xnticks_t start, period, now;
        struct cobalt_timer *timer;
-       spl_t s;
        int ret;
+       spl_t s;
 
-       if (cur == NULL) {
-               ret = -EPERM;
-               goto error;
-       }
-
-       if ((unsigned int)timerid >= CONFIG_XENO_OPT_NRTIMERS) {
-               ret = -EINVAL;
-               goto error;
-       }
-
-       if ((unsigned long)value->it_value.tv_nsec >= ONE_BILLION ||
-           ((unsigned long)value->it_interval.tv_nsec >= ONE_BILLION &&
-            (value->it_value.tv_sec != 0 || value->it_value.tv_nsec != 0))) {
-               ret = -EINVAL;
-               goto error;
-       }
+       if ((unsigned int)timerid >= CONFIG_XENO_OPT_NRTIMERS)
+               return -EINVAL;
 
        xnlock_get_irqsave(&nklock, s);
 
        timer = &cobalt_timer_pool[(unsigned int)timerid];
 
-       if (!xntimer_active_p(&timer->timerbase)) {
+       if (!xntimer_active_p(&timer->timerbase) ||
+           timer->owningq != cobalt_kqueues(0)) {
                ret = -EINVAL;
-               goto unlock_and_error;
-       }
-
-#if XENO_DEBUG(COBALT)
-       if (timer->owningq != cobalt_kqueues(0)) {
-               ret = -EPERM;
-               goto unlock_and_error;
+               goto out;
        }
-#endif /* XENO_DEBUG(COBALT) */
 
        if (ovalue)
                timer_gettimeout(timer, ovalue);
 
-       if (timer->owner)
-               list_del(&timer->tlink);
-
-       if (value->it_value.tv_nsec == 0 && value->it_value.tv_sec == 0) {
-               xntimer_stop(&timer->timerbase);
-               timer->owner = NULL;
-       } else {
-               start = ts2ns(&value->it_value) + 1;
-               period = ts2ns(&value->it_interval);
-               xntimer_set_sched(&timer->timerbase, xnsched_current());
+       ret = timer_set(timer, flags, value);
+       if (ret == -ETIMEDOUT) {
                /*
-                * Now start the timer. If the initial delay has
-                * already passed, the call shall succeed, so, let us
-                * tweak the start time until it fits.
+                * Time has already passed, deliver a notification
+                * immediately. Since we are about to dive into the
+                * signal machinery for this, let's drop the nklock to
+                * break the atomic section temporarily.
                 */
-               if (xntimer_start(&timer->timerbase, start, period,
-                                 clock_flag(flags, timer->clockid))) {
-                       now = clock_get_ticks(timer->clockid);
-                       if (period) {
-                               do
-                                       start += period;
-                               while ((xnsticks_t) (start - now) <= 0);
-                       } else
-                               start = now +
-                                       xnclock_ticks_to_ns(&nkclock,
-                                                           nkclock.gravity);
-                       xntimer_start(&timer->timerbase, start, period,
-                                     clock_flag(flags, timer->clockid));
-               }
-
-               timer->owner = cur;
-               list_add_tail(&timer->tlink, &timer->owner->timersq);
+               xnlock_put_irqrestore(&nklock, s);
+               timer_deliver_late(timerid);
+               return 0;
        }
-
+out:
        xnlock_put_irqrestore(&nklock, s);
 
-       return 0;
-
-unlock_and_error:
-       xnlock_put_irqrestore(&nklock, s);
-error:
        return ret;
 }
 
@@ -412,8 +436,8 @@ error:
  *
  * @retval 0 on success;
  * @retval -1 with @a errno set if:
- * - EINVAL, @a timerid is invalid;
- * - EPERM, the timer @a timerid does not belong to the current process.
+ * - EINVAL, @a timerid is invalid. For @a timerid to be valid, it
+ * must belong to the current process.
  *
  * @see
  * <a 
href="http://www.opengroup.org/onlinepubs/000095399/functions/timer_gettime.html";>
@@ -424,44 +448,32 @@ static inline int timer_gettime(timer_t timerid, struct 
itimerspec *value)
 {
        struct cobalt_timer *timer;
        spl_t s;
-       int ret;
 
-       if ((unsigned int)timerid >= CONFIG_XENO_OPT_NRTIMERS) {
-               ret = -EINVAL;
-               goto error;
-       }
+       if ((unsigned int)timerid >= CONFIG_XENO_OPT_NRTIMERS)
+               return -EINVAL;
 
        xnlock_get_irqsave(&nklock, s);
 
        timer = &cobalt_timer_pool[(unsigned int)timerid];
 
-       if (!xntimer_active_p(&timer->timerbase)) {
-               ret = -EINVAL;
-               goto unlock_and_error;
-       }
-
-#if XENO_DEBUG(COBALT)
-       if (timer->owningq != cobalt_kqueues(0)) {
-               ret = -EPERM;
-               goto unlock_and_error;
-       }
-#endif /* XENO_DEBUG(COBALT) */
+       if (!xntimer_active_p(&timer->timerbase) ||
+           timer->owningq != cobalt_kqueues(0))
+               goto fail;
 
        timer_gettimeout(timer, value);
 
        xnlock_put_irqrestore(&nklock, s);
 
        return 0;
-
-unlock_and_error:
+fail:
        xnlock_put_irqrestore(&nklock, s);
-error:
-       return ret;
+
+       return -EINVAL;
 }
 
 int cobalt_timer_delete(timer_t timerid)
 {
-       return timer_delete(timerid, cobalt_kqueues(0), 0);
+       return timer_delete(timerid);
 }
 
 int cobalt_timer_create(clockid_t clock,
@@ -529,40 +541,31 @@ int cobalt_timer_gettime(timer_t tm, struct itimerspec 
__user *u_val)
 int cobalt_timer_getoverrun(timer_t timerid)
 {
        struct cobalt_timer *timer;
-       int overruns, ret;
+       int overruns;
        spl_t s;
 
-       if ((unsigned int)timerid >= CONFIG_XENO_OPT_NRTIMERS) {
-               ret = -EINVAL;
-               goto error;
-       }
+       if ((unsigned int)timerid >= CONFIG_XENO_OPT_NRTIMERS)
+               return -EINVAL;
 
        xnlock_get_irqsave(&nklock, s);
 
        timer = &cobalt_timer_pool[(unsigned int)timerid];
 
-       if (!xntimer_active_p(&timer->timerbase)) {
-               ret = -EINVAL;
-               goto unlock_and_error;
-       }
+       if (!xntimer_active_p(&timer->timerbase))
+               goto fail;
 
-#if XENO_DEBUG(COBALT)
-       if (timer->owningq != cobalt_kqueues(0)) {
-               ret = -EPERM;
-               goto unlock_and_error;
-       }
-#endif /* XENO_DEBUG(COBALT) */
+       if (timer->owningq != cobalt_kqueues(0))
+               goto fail;
 
        overruns = timer->overruns;
 
        xnlock_put_irqrestore(&nklock, s);
 
        return overruns;
-
-unlock_and_error:
+fail:
        xnlock_put_irqrestore(&nklock, s);
-error:
-       return ret;
+
+       return -EINVAL;
 }
 
 int cobalt_timer_deliver(timer_t timerid) /* nklocked, IRQs off. */
@@ -572,10 +575,14 @@ int cobalt_timer_deliver(timer_t timerid) /* nklocked, 
IRQs off. */
 
        timer = &cobalt_timer_pool[(unsigned int)timerid];
 
+       if (!xntimer_active_p(&timer->timerbase))
+               /* Killed before ultimate delivery, who cares then? */
+               return 0;
+
        if (!xntimer_interval(&timer->timerbase))
                timer->overruns = 0;
        else {
-               now = xnclock_read_raw(&nkclock);
+               now = xnclock_read_raw(xntimer_clock(&timer->timerbase));
                timer->overruns = xntimer_get_overruns(&timer->timerbase, now);
                if ((unsigned int)timer->overruns > COBALT_DELAYMAX)
                        timer->overruns = COBALT_DELAYMAX;
@@ -584,24 +591,9 @@ int cobalt_timer_deliver(timer_t timerid) /* nklocked, 
IRQs off. */
        return timer->overruns;
 }
 
-void cobalt_timer_flush(struct cobalt_thread *thread) /* nklocked, IRQs off. */
-{
-       struct cobalt_timer *timer, *tmp;
-
-       if (list_empty(&thread->timersq))
-               return;
-
-       list_for_each_entry_safe(timer, tmp, &thread->timersq, tlink) {
-               list_del(&timer->tlink);
-               xntimer_stop(&timer->timerbase);
-               timer->owner = NULL;
-       }
-}
-
 void cobalt_timerq_cleanup(struct cobalt_kqueues *q)
 {
        struct cobalt_timer *timer, *tmp;
-       timer_t tm;
        spl_t s;
 
        xnlock_get_irqsave(&nklock, s);
@@ -610,8 +602,7 @@ void cobalt_timerq_cleanup(struct cobalt_kqueues *q)
                goto out;
 
        list_for_each_entry_safe(timer, tmp, &q->timerq, link) { 
-               tm = (timer_t)(timer - cobalt_timer_pool);
-               timer_delete(tm, q, 1);
+               timer_cleanup(timer);
                xnlock_put_irqrestore(&nklock, s);
 #if XENO_DEBUG(COBALT)
                printk(XENO_INFO "deleting Cobalt timer %u\n", (unsigned 
int)tm);
diff --git a/kernel/cobalt/posix/timer.h b/kernel/cobalt/posix/timer.h
index 4c370d1..5b361c9 100644
--- a/kernel/cobalt/posix/timer.h
+++ b/kernel/cobalt/posix/timer.h
@@ -30,11 +30,9 @@ struct cobalt_timer {
        struct xntimer timerbase;
        int overruns;
        struct list_head link;
-       struct list_head tlink;
        clockid_t clockid;
        pid_t target;
        struct cobalt_sigpending sigp;
-       struct cobalt_thread *owner;
        struct cobalt_kqueues *owningq;
        struct cobalt_extref extref;
 };
@@ -56,8 +54,6 @@ int cobalt_timer_getoverrun(timer_t tm);
 
 int cobalt_timer_deliver(timer_t timerid);
 
-void cobalt_timer_flush(struct cobalt_thread *zombie);
-
 void cobalt_timerq_cleanup(struct cobalt_kqueues *q);
 
 int cobalt_timer_pkg_init(void);
@@ -76,4 +72,6 @@ static inline struct cobalt_timer *cobalt_timer_by_id(timer_t 
timer_id)
        return &cobalt_timer_pool[(unsigned int)timer_id];
 }
 
+void cobalt_timer_handler(struct xntimer *xntimer);
+
 #endif /* !_COBALT_POSIX_TIMER_H */
diff --git a/kernel/cobalt/sched.c b/kernel/cobalt/sched.c
index 8db8e2a..d46ff36 100644
--- a/kernel/cobalt/sched.c
+++ b/kernel/cobalt/sched.c
@@ -80,17 +80,16 @@ static unsigned long wd_timeout_arg = 
CONFIG_XENO_OPT_WATCHDOG_TIMEOUT;
 module_param_named(watchdog_timeout, wd_timeout_arg, ulong, 0644);
 MODULE_PARM_DESC(watchdog_timeout, "Watchdog timeout (s)");
 
-/*!
+/**
  * @internal
- * \fn void xnsched_watchdog_handler(struct xntimer *timer)
- * \brief Process watchdog ticks.
+ * @fn void watchdog_handler(struct xntimer *timer)
+ * @brief Process watchdog ticks.
  *
  * This internal routine handles incoming watchdog ticks to detect
  * software lockups. It kills any offending thread which is found to
  * monopolize the CPU so as to starve the Linux kernel for too long.
  */
-
-static void xnsched_watchdog_handler(struct xntimer *timer)
+static void watchdog_handler(struct xntimer *timer)
 {
        struct xnsched *sched = xnsched_current();
        struct xnthread *curr = sched->curr;
@@ -177,8 +176,7 @@ void xnsched_init(struct xnsched *sched, int cpu)
        nknrthreads++;
 
 #ifdef CONFIG_XENO_OPT_WATCHDOG
-       xntimer_init_noblock(&sched->wdtimer, &nkclock,
-                            xnsched_watchdog_handler);
+       xntimer_init_noblock(&sched->wdtimer, &nkclock, watchdog_handler);
        xntimer_set_name(&sched->wdtimer, "[watchdog]");
        xntimer_set_priority(&sched->wdtimer, XNTIMER_LOPRIO);
        xntimer_set_sched(&sched->wdtimer, sched);
diff --git a/kernel/cobalt/timer.c b/kernel/cobalt/timer.c
index 6ade2e9..ff71fc1 100644
--- a/kernel/cobalt/timer.c
+++ b/kernel/cobalt/timer.c
@@ -365,6 +365,9 @@ void __xntimer_init(struct xntimer *timer,
        timer->sched = xnsched_current();
 
 #ifdef CONFIG_XENO_OPT_STATS
+#ifdef CONFIG_XENO_OPT_EXTCLOCK
+       timer->tracker = clock;
+#endif
        if (!xnsched_current_thread() || !xnsched_root_p())
                snprintf(timer->name, XNOBJECT_NAME_LEN, "%d/%s",
                         current->pid, current->comm);
@@ -372,11 +375,9 @@ void __xntimer_init(struct xntimer *timer,
                xnobject_copy_name(timer->name,
                                   xnsched_current_thread()->name);
 
-       xnstat_counter_set(&timer->scheduled, 0);
-       xnstat_counter_set(&timer->fired, 0);
-
+       xntimer_reset_stats(timer);
        xnlock_get_irqsave(&nklock, s);
-       list_add_tail(&timer->next_stat, &clock->timerq);
+       list_add_tail(&timer->next_stat, &clock->statq);
        clock->nrtimers++;
        xnvfile_touch(&clock->vfile);
        xnlock_put_irqrestore(&nklock, s);
@@ -384,6 +385,27 @@ void __xntimer_init(struct xntimer *timer,
 }
 EXPORT_SYMBOL_GPL(__xntimer_init);
 
+#if defined(CONFIG_XENO_OPT_EXTCLOCK) && defined(CONFIG_XENO_OPT_STATS)
+
+void xntimer_switch_tracking(struct xntimer *timer,
+                            struct xnclock *newclock)
+{
+       struct xnclock *oldclock = timer->tracker;
+       spl_t s;
+       
+       xnlock_get_irqsave(&nklock, s);
+       list_del(&timer->next_stat);
+       oldclock->nrtimers--;
+       xnvfile_touch(&oldclock->vfile);
+       list_add_tail(&timer->next_stat, &newclock->statq);
+       newclock->nrtimers++;
+       xnvfile_touch(&newclock->vfile);
+       timer->tracker = newclock;
+       xnlock_put_irqrestore(&nklock, s);
+}
+
+#endif /* CONFIG_XENO_OPT_EXTCLOCK && CONFIG_XENO_OPT_STATS */
+
 /*!
  * \fn void xntimer_destroy(struct xntimer *timer)
  *
@@ -498,7 +520,7 @@ EXPORT_SYMBOL_GPL(xntimer_migrate);
  * @param timer The address of a valid timer descriptor.
  *
  * @param now current date (as
- * xnclock_read_monotonic(xntimer_clock(timer)))
+ * xnclock_read_raw(xntimer_clock(timer)))
  *
  * @return the number of overruns of @a timer at date @a now
  */


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

Reply via email to