Module: xenomai-forge Branch: master 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