Module: xenomai-forge Branch: master Commit: e4c5e06674ceb6a9ec08e89a44bd8d1d03f3f9af URL: http://git.xenomai.org/?p=xenomai-forge.git;a=commit;h=e4c5e06674ceb6a9ec08e89a44bd8d1d03f3f9af
Author: Philippe Gerum <r...@xenomai.org> Date: Sat Nov 26 16:07:24 2011 +0100 copperplate/clockobj, lib: assume fixed clock resolution during runtime For performance reason, we want to run locklessly for common time unit conversions, so the clockobj implementation now assumes that the clock resolution will not be updated on-the-fly. This means that clockobj_set_resolution() shall be called from init - or known to be safe - context only. COPPERPLATE_PROTECT sections have been removed around client API calls which do not involve locking anymore. --- include/copperplate/clockobj.h | 29 +--------------- lib/alchemy/internal.c | 3 -- lib/alchemy/task.c | 7 +--- lib/alchemy/timer.c | 9 ----- lib/copperplate/clockobj.c | 72 ++++++++++++++++++++++++++------------- lib/psos/tm.c | 4 +- lib/vxworks/tickLib.c | 2 +- 7 files changed, 54 insertions(+), 72 deletions(-) diff --git a/include/copperplate/clockobj.h b/include/copperplate/clockobj.h index 8e07946..7537c01 100644 --- a/include/copperplate/clockobj.h +++ b/include/copperplate/clockobj.h @@ -22,7 +22,6 @@ #include <pthread.h> #include <time.h> #include <xeno_config.h> -#include <copperplate/init.h> #include <copperplate/list.h> #include <copperplate/debug.h> #include <copperplate/lock.h> @@ -96,11 +95,9 @@ timespec_after(const struct timespec *t1, const struct timespec *t2) extern "C" { #endif -void clockobj_set_date(struct clockobj *clkobj, - ticks_t ticks, unsigned int resolution_ns); +void clockobj_set_date(struct clockobj *clkobj, ticks_t ticks); -void clockobj_get_date(struct clockobj *clkobj, - ticks_t *pticks); +void clockobj_get_date(struct clockobj *clkobj, ticks_t *pticks); void clockobj_get_time(struct clockobj *clkobj, ticks_t *pticks, ticks_t *ptsc); @@ -220,18 +217,6 @@ void clockobj_ticks_to_timespec(struct clockobj *clkobj, } static inline -int __clockobj_set_resolution(struct clockobj *clkobj, - unsigned int resolution_ns) -{ - if (resolution_ns > 1) { - warning("support for low resolution clock disabled"); - return __bt(-EINVAL); - } - - return 0; -} - -static inline unsigned int clockobj_get_resolution(struct clockobj *clkobj) { return 1; @@ -273,16 +258,6 @@ void clockobj_ticks_to_timespec(struct clockobj *clkobj, } static inline -int __clockobj_set_resolution(struct clockobj *clkobj, - unsigned int resolution_ns) -{ - clkobj->resolution = resolution_ns; - clkobj->frequency = 1000000000 / resolution_ns; - - return 0; -} - -static inline unsigned int clockobj_get_resolution(struct clockobj *clkobj) { return clkobj->resolution; diff --git a/lib/alchemy/internal.c b/lib/alchemy/internal.c index fd2479c..445d50e 100644 --- a/lib/alchemy/internal.c +++ b/lib/alchemy/internal.c @@ -42,13 +42,10 @@ char *alchemy_build_name(char *buf, const char *name, RTIME alchemy_rel2abs_timeout(RTIME timeout) { - struct service svc; ticks_t now; if (timeout != TM_INFINITE && timeout != TM_NONBLOCK) { - COPPERPLATE_PROTECT(svc); clockobj_get_time(&alchemy_clock, &now, NULL); - COPPERPLATE_UNPROTECT(svc); timeout += now; } diff --git a/lib/alchemy/task.c b/lib/alchemy/task.c index e52e14c..5cfd1d0 100644 --- a/lib/alchemy/task.c +++ b/lib/alchemy/task.c @@ -475,7 +475,6 @@ int rt_task_sleep(RTIME delay) int rt_task_sleep_until(RTIME date) { struct timespec ts; - struct service svc; ticks_t now; if (!threadobj_current_p()) @@ -485,14 +484,10 @@ int rt_task_sleep_until(RTIME date) ts.tv_sec = (time_t)-1 >> 1; ts.tv_nsec = 999999999; } else { - COPPERPLATE_PROTECT(svc); clockobj_get_time(&alchemy_clock, &now, NULL); - if (date <= now) { - COPPERPLATE_UNPROTECT(svc); + if (date <= now) return -ETIMEDOUT; - } clockobj_ticks_to_timespec(&alchemy_clock, date, &ts); - COPPERPLATE_UNPROTECT(svc); } return threadobj_sleep(&ts); diff --git a/lib/alchemy/timer.c b/lib/alchemy/timer.c index 447d7dd..28c5989 100644 --- a/lib/alchemy/timer.c +++ b/lib/alchemy/timer.c @@ -23,12 +23,9 @@ struct clockobj alchemy_clock; RTIME rt_timer_read(void) { - struct service svc; ticks_t ticks; - COPPERPLATE_PROTECT(svc); clockobj_get_time(&alchemy_clock, &ticks, NULL); - COPPERPLATE_UNPROTECT(svc); return ticks; } @@ -45,18 +42,12 @@ SRTIME rt_timer_ticks2ns(SRTIME ticks) int rt_timer_inquire(RT_TIMER_INFO *info) { - struct service svc; - - COPPERPLATE_PROTECT(svc); - info->period = clockobj_get_resolution(&alchemy_clock); if (info->period == 1) info->period = TM_ONESHOT; clockobj_get_time(&alchemy_clock, &info->date, &info->tsc); - COPPERPLATE_UNPROTECT(svc); - return 0; } diff --git a/lib/copperplate/clockobj.c b/lib/copperplate/clockobj.c index 4cc4a63..d40a79c 100644 --- a/lib/copperplate/clockobj.c +++ b/lib/copperplate/clockobj.c @@ -27,6 +27,7 @@ #include "copperplate/lock.h" #include "copperplate/clockobj.h" #include "copperplate/debug.h" +#include "internal.h" void timespec_sub(struct timespec *r, const struct timespec *t1, const struct timespec *t2) @@ -80,7 +81,21 @@ void timespec_adds(struct timespec *r, } } -#ifndef CONFIG_XENO_LORES_CLOCK_DISABLED +#ifdef CONFIG_XENO_LORES_CLOCK_DISABLED + +static inline +int __clockobj_set_resolution(struct clockobj *clkobj, + unsigned int resolution_ns) +{ + if (resolution_ns > 1) { + warning("support for low resolution clock disabled"); + return __bt(-EINVAL); + } + + return 0; +} + +#else /* !CONFIG_XENO_LORES_CLOCK_DISABLED */ void __clockobj_ticks_to_timespec(struct clockobj *clkobj, ticks_t ticks, @@ -103,13 +118,21 @@ void __clockobj_ticks_to_timeout(struct clockobj *clkobj, { struct timespec delta; - read_lock_nocancel(&clkobj->lock); __RT(clock_gettime(clk_id, ts)); __clockobj_ticks_to_timespec(clkobj, ticks, &delta); - read_unlock(&clkobj->lock); timespec_add(ts, ts, &delta); } +static inline +int __clockobj_set_resolution(struct clockobj *clkobj, + unsigned int resolution_ns) +{ + clkobj->resolution = resolution_ns; + clkobj->frequency = 1000000000 / resolution_ns; + + return 0; +} + #endif /* !CONFIG_XENO_LORES_CLOCK_DISABLED */ static const int mdays[] = { @@ -164,11 +187,9 @@ void clockobj_ticks_to_caltime(struct clockobj *clkobj, unsigned int freq; time_t nsecs; - read_lock_nocancel(&clkobj->lock); freq = clockobj_get_frequency(clkobj); nsecs = ticks / freq; *rticks = ticks % freq; - read_unlock(&clkobj->lock); for (year = 1970;; year++) { /* Years since 1970. */ int ysecs = ((year % 4) ? 365 : 366) * SECBYDAY; @@ -209,39 +230,47 @@ void clockobj_caltime_to_timeout(struct clockobj *clkobj, const struct tm *tm, { ticks_t ticks; - read_lock_nocancel(&clkobj->lock); clockobj_caltime_to_ticks(clkobj, tm, rticks, &ticks); __clockobj_ticks_to_timespec(clkobj, ticks, ts); timespec_sub(ts, ts, &clkobj->offset); - read_unlock(&clkobj->lock); } -void clockobj_set_date(struct clockobj *clkobj, - ticks_t ticks, unsigned int resolution_ns) +void clockobj_set_date(struct clockobj *clkobj, ticks_t ticks) { struct timespec now; + /* + * XXX: we grab the lock to exclude other threads from reading + * the clock offset while we update it, so that they either + * compute against the old value, or the new one, but always + * see a valid offset. + */ read_lock_nocancel(&clkobj->lock); __RT(clock_gettime(CLOCK_COPPERPLATE, &now)); - /* Change the resolution on-the-fly if given. */ - if (resolution_ns) - __clockobj_set_resolution(clkobj, resolution_ns); - __clockobj_ticks_to_timespec(clkobj, ticks, &clkobj->epoch); timespec_sub(&clkobj->offset, &clkobj->epoch, &now); read_unlock(&clkobj->lock); } +/* + * XXX: clockobj_set_resolution() should be called during the init + * phase, not after. For performance reason, we want to run locklessly + * for common time unit conversions, so the clockobj implementation + * does assume that the clock resolution will not be updated + * on-the-fly. + */ int clockobj_set_resolution(struct clockobj *clkobj, unsigned int resolution_ns) { #ifdef CONFIG_XENO_LORES_CLOCK_DISABLED assert(resolution_ns == 1); #else + __clockobj_set_resolution(clkobj, resolution_ns); + /* Changing the resolution implies resetting the epoch. */ - clockobj_set_date(clkobj, 0, resolution_ns); + clockobj_set_date(clkobj, 0); #endif return 0; } @@ -265,8 +294,6 @@ void clockobj_get_time(struct clockobj *clkobj, { unsigned long long ns, tsc; - read_lock_nocancel(&clkobj->lock); - tsc = __xn_rdtsc(); ns = xnarch_tsc_to_ns(tsc); if (clockobj_get_resolution(clkobj) > 1) @@ -275,8 +302,6 @@ void clockobj_get_time(struct clockobj *clkobj, if (ptsc) *ptsc = tsc; - - read_unlock(&clkobj->lock); } void clockobj_get_date(struct clockobj *clkobj, ticks_t *pticks) @@ -310,8 +335,6 @@ void clockobj_get_time(struct clockobj *clkobj, ticks_t *pticks, __RT(clock_gettime(CLOCK_COPPERPLATE, &now)); - read_lock_nocancel(&clkobj->lock); - /* Convert the time value to ticks, with no offset. */ if (clockobj_get_resolution(clkobj) > 1) *pticks = (ticks_t)now.tv_sec * clockobj_get_frequency(clkobj) @@ -325,8 +348,6 @@ void clockobj_get_time(struct clockobj *clkobj, ticks_t *pticks, */ if (ptsc) *ptsc = *pticks; - - read_unlock(&clkobj->lock); } void clockobj_get_date(struct clockobj *clkobj, ticks_t *pticks) @@ -356,11 +377,9 @@ void clockobj_ticks_to_clock(struct clockobj *clkobj, { struct timespec ts, now; - read_lock_nocancel(&clkobj->lock); __RT(clock_gettime(CLOCK_COPPERPLATE, &now)); /* Absolute timeout, CLOCK_COPPERPLATE-based. */ __clockobj_ticks_to_timespec(clkobj, ticks, &ts); - read_unlock(&clkobj->lock); /* Offset from CLOCK_COPPERPLATE epoch. */ timespec_sub(timeout, &ts, &now); /* Current time for clk_id. */ @@ -384,6 +403,11 @@ int clockobj_init(struct clockobj *clkobj, if (ret) return __bt(ret); + /* + * FIXME: this lock is only used to protect the wallclock + * offset readings from updates. We should replace this by a + * confirmed reading loop. + */ __RT(pthread_mutexattr_init(&mattr)); __RT(pthread_mutexattr_setprotocol(&mattr, PTHREAD_PRIO_INHERIT)); __RT(pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_PRIVATE)); diff --git a/lib/psos/tm.c b/lib/psos/tm.c index a4d7ccd..acc79b7 100644 --- a/lib/psos/tm.c +++ b/lib/psos/tm.c @@ -302,7 +302,7 @@ u_long tm_set(u_long date, u_long time, u_long ticks) goto out; clockobj_caltime_to_ticks(&psos_clock, &tm, ticks, &t); - clockobj_set_date(&psos_clock, t, 0); + clockobj_set_date(&psos_clock, t); out: COPPERPLATE_UNPROTECT(svc); @@ -317,8 +317,8 @@ u_long tm_get(u_long *date_r, u_long *time_r, u_long *ticks_r) COPPERPLATE_PROTECT(svc); clockobj_get_date(&psos_clock, &t); - clockobj_ticks_to_caltime(&psos_clock, t, &tm, ticks_r); COPPERPLATE_UNPROTECT(svc); + clockobj_ticks_to_caltime(&psos_clock, t, &tm, ticks_r); *date_r = ((tm.tm_year + 1900) << 16) | ((tm.tm_mon + 1) << 8) | tm.tm_mday; *time_r = (tm.tm_hour << 16) | (tm.tm_min << 8) | tm.tm_sec; diff --git a/lib/vxworks/tickLib.c b/lib/vxworks/tickLib.c index 9fe5730..effb68b 100644 --- a/lib/vxworks/tickLib.c +++ b/lib/vxworks/tickLib.c @@ -42,5 +42,5 @@ ULONG tickGet(void) void tickSet(ULONG ticks) { - clockobj_set_date(&wind_clock, ticks, 0); + clockobj_set_date(&wind_clock, ticks); } _______________________________________________ Xenomai-git mailing list Xenomai-git@gna.org https://mail.gna.org/listinfo/xenomai-git