1
0
Fork 0
forked from nuttx/nuttx-update

Fix some timer race conditions

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3949 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2011-09-11 17:48:52 +00:00
parent 455b9336fb
commit 81ca27c9b0
4 changed files with 97 additions and 13 deletions

View file

@ -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).

View file

@ -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

View file

@ -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;
}

View file

@ -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
}