summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2011-09-11 17:48:52 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2011-09-11 17:48:52 +0000
commit94c3b8e72eb81b2ca7b3ab69b6996602d5207c19 (patch)
treeab669712a23a13022adf6abd05d240d08714370d
parent024c4051ba207d5ad1b68753848bbf80599b3877 (diff)
downloadnuttx-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/ChangeLog7
-rw-r--r--nuttx/sched/clock_gettime.c75
-rw-r--r--nuttx/sched/clock_settime.c4
-rw-r--r--nuttx/sched/clock_systimer.c24
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
}