diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2011-09-11 17:48:52 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2011-09-11 17:48:52 +0000 |
commit | 94c3b8e72eb81b2ca7b3ab69b6996602d5207c19 (patch) | |
tree | ab669712a23a13022adf6abd05d240d08714370d | |
parent | 024c4051ba207d5ad1b68753848bbf80599b3877 (diff) | |
download | nuttx-94c3b8e72eb81b2ca7b3ab69b6996602d5207c19.tar.gz nuttx-94c3b8e72eb81b2ca7b3ab69b6996602d5207c19.tar.bz2 nuttx-94c3b8e72eb81b2ca7b3ab69b6996602d5207c19.zip |
Fix some timer race conditions
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3949 42af7a65-404d-4744-a932-0658087f49c3
-rw-r--r-- | nuttx/ChangeLog | 7 | ||||
-rw-r--r-- | nuttx/sched/clock_gettime.c | 75 | ||||
-rw-r--r-- | nuttx/sched/clock_settime.c | 4 | ||||
-rw-r--r-- | nuttx/sched/clock_systimer.c | 24 |
4 files changed, 97 insertions, 13 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog index 57eaf7a99..fcf4df8e4 100644 --- a/nuttx/ChangeLog +++ b/nuttx/ChangeLog @@ -2018,7 +2018,7 @@ * arch/arm/src/kinetis/kinetis_sdhc.c: SDHC driver for Kinetis parts. Initially check-in is just a crude port of the STM32 SDIO driver. - Much more is needed. + Much more work is needed. * graphics/, include/nuttx/nx: Add new NX interfaces for drawing circles -- both circular outlines and filled circles. * graphic/nxglib/nxglib_spitline.c: Add a "fudge factor" that eliminates @@ -2041,7 +2041,10 @@ * drivers/mtd/flash_eraseall.c: Add a callable function that accepts the path to a block driver and then erases the underlying FLASH memory (assuming that the block driver is an MTD driver wrapped in the FTL - layer). + layer). Hmmm... this is probably not the best long term solution; + flash_eraseall() should be a user-callable function that operates + one driver interfaces; not an internal, OS function that operates + on directly on block drivers. * drivers/bch: Fixed some important bugs in the BCH driver (noted by Li Zhuoyi (Lzyy)). This would have effected any large reads or writes (larger than the hardware sector size). diff --git a/nuttx/sched/clock_gettime.c b/nuttx/sched/clock_gettime.c index 3fdfe9602..1dc48aeb7 100644 --- a/nuttx/sched/clock_gettime.c +++ b/nuttx/sched/clock_gettime.c @@ -45,6 +45,8 @@ #include <errno.h> #include <debug.h> +#include <arch/irq.h> + #include "clock_internal.h" /************************************************************************ @@ -93,7 +95,14 @@ int clock_gettime(clockid_t clock_id, struct timespec *tp) uint32_t msecs; uint32_t secs; uint32_t nsecs; +#else + uint32_t system_utc; + uint32_t tickcount; +#endif +#if defined(CONFIG_RTC) || defined(CONFIG_SYSTEM_UTC) + irqstate_t flags; #endif + int ret = OK; sdbg("clock_id=%d\n", clock_id); @@ -147,14 +156,58 @@ int clock_gettime(clockid_t clock_id, struct timespec *tp) #ifdef CONFIG_RTC if (g_rtc_enabled) { - tp->tv_sec = up_rtc_gettime(); - tp->tv_nsec = (up_rtc_getclock() & (RTC_CLOCKS_PER_SEC-1) ) * (1000000000/RTC_CLOCKS_PER_SEC); + /* up_rtc_gettime() returns the time in seconds and up_rtc_getclock() + * will return the time int RTC clock ticks. Under the hood, these + * are probably based on the same running time. However, since we + * sample this time twice, we have to add the following strange logic + * to assure that the fractional second value does not rollover to + * a full second between sampling times. + */ + + clock_t rtc_frac; /* Current fractional seconds in RTC ticks */ + clock_t rtc_last; /* Previous fractional seconds in RTC ticks */ + time_t rtc_sec; /* Current seconds */ + + /* Interrupts are disabled here only to prevent interrupts and context + * switches from interfering with the consecutive time samples. I + * expect to go through this loop 1 time 99.9% of the time and then + * only twice on the remaining cornercases. + */ + + flags = irqsave(); + rtc_frac = up_rtc_getclock() & (RTC_CLOCKS_PER_SEC-1); + do + { + rtc_last = rtc_frac; + rtc_sec = up_rtc_gettime(); + rtc_frac = up_rtc_getclock() & (RTC_CLOCKS_PER_SEC-1); + } + while (rtc_frac < rtc_last); + irqrestore(flags); + + /* Okay.. the samples should be as close together in time as possible + * and we can be assured that no fractional second rollover occurred + * between the samples. + */ + + tp->tv_sec = rtc_sec; + tp->tv_nsec = rtc_frac * (1000000000/RTC_CLOCKS_PER_SEC); } else #endif { - tp->tv_sec = g_system_utc; - tp->tv_nsec = g_tickcount * (1000000000/TICK_PER_SEC); + /* Disable interrupts while g_system_utc and g_tickcount are sampled + * so that we can be assured that g_system_utc and g_tickcount are based + * at the same point in time. + */ + + flags = irqsave(); + system_utc = g_system_utc; + tickcount = g_tickcount; + irqrestore(flags); + + tp->tv_sec = system_utc; + tp->tv_nsec = tickcount * (1000000000/TICK_PER_SEC); } #endif @@ -169,8 +222,18 @@ int clock_gettime(clockid_t clock_id, struct timespec *tp) #ifdef CONFIG_RTC else if (clock_id == CLOCK_ACTIVETIME && g_rtc_enabled && tp) { - tp->tv_sec = g_system_utc; - tp->tv_nsec = g_tickcount * (1000000000/TICK_PER_SEC); + /* Disable interrupts while g_system_utc and g_tickcount are sampled + * so that we can be assured that g_system_utc and g_tickcount are based + * at the same point in time. + */ + + flags = irqsave(); + system_utc = g_system_utc; + tickcount = g_tickcount; + irqrestore(flags); + + tp->tv_sec = system_utc; + tp->tv_nsec = tickcount * (1000000000/TICK_PER_SEC); } #endif diff --git a/nuttx/sched/clock_settime.c b/nuttx/sched/clock_settime.c index 72fb8276e..77b6ebecc 100644 --- a/nuttx/sched/clock_settime.c +++ b/nuttx/sched/clock_settime.c @@ -116,7 +116,7 @@ int clock_settime(clockid_t clock_id, const struct timespec *tp) #ifdef CONFIG_RTC if (g_rtc_enabled) { - up_rtc_settime( tp->tv_sec ); + up_rtc_settime(tp->tv_sec); } else #endif @@ -143,7 +143,7 @@ int clock_settime(clockid_t clock_id, const struct timespec *tp) else { sdbg("Returning ERROR\n"); - *get_errno_ptr() = EINVAL; + set_errno(EINVAL); ret = ERROR; } diff --git a/nuttx/sched/clock_systimer.c b/nuttx/sched/clock_systimer.c index 71577df76..cfa019fc7 100644 --- a/nuttx/sched/clock_systimer.c +++ b/nuttx/sched/clock_systimer.c @@ -45,6 +45,8 @@ #include <nuttx/rtc.h> #include <nuttx/time.h> +#include <arch/irq.h> + #if !defined(clock_systimer) /* See nuttx/clock.h */ /**************************************************************************** @@ -77,6 +79,12 @@ uint32_t clock_systimer(void) { +#ifdef CONFIG_SYSTEM_UTC + irqstate_t flags; + uint32_t system_utc; + uint32_t tickcount; +#endif + /* Fetch the g_system_timer value from timer hardware, if available */ #ifdef CONFIG_RTC @@ -89,14 +97,24 @@ uint32_t clock_systimer(void) if (g_rtc_enabled) { -// return up_rtc_getclock(); - } + /* return up_rtc_getclock(); */ + } #endif #ifndef CONFIG_SYSTEM_UTC return g_system_timer; #else - return g_system_utc * TICK_PER_SEC + g_tickcount; + /* Disable interrupts while g_system_utc and g_tickcount are sampled + * so that we can be assured that g_system_utc and g_tickcount are based + * at the same point in time. + */ + + flags = irqsave(); + system_utc = g_system_utc; + tickcount = g_tickcount; + irqrestore(flags); + + return system_utc * TICK_PER_SEC + tickcount; #endif } |