diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2013-07-31 13:30:42 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2013-08-01 16:45:46 +0200 |
commit | 9bf74673f928788b0ea4addabf045b94844d40ff (patch) | |
tree | 495ca384343769feefd96f88061ccc5ed5f192bb | |
parent | score: Move nanoseconds since last tick support (diff) | |
download | rtems-9bf74673f928788b0ea4addabf045b94844d40ff.tar.bz2 |
score: Use an ISR lock for TOD
Two issues are addressed.
1. On single processor configurations the set/get of the now/uptime
timestamps is now consistently protected by ISR disable/enable
sequences. Previously nested interrupts could observe partially written
values since 64-bit writes are not atomic on 32-bit architectures in
general. This could lead to non-monotonic uptime timestamps.
2. The TOD now/uptime maintanence is now independent of the giant lock.
This is the first step to remove the giant lock in _Thread_Dispatch().
-rw-r--r-- | cpukit/rtems/src/clockgetuptimeseconds.c | 14 | ||||
-rw-r--r-- | cpukit/score/Makefile.am | 1 | ||||
-rw-r--r-- | cpukit/score/include/rtems/score/todimpl.h | 35 | ||||
-rw-r--r-- | cpukit/score/src/coretod.c | 2 | ||||
-rw-r--r-- | cpukit/score/src/coretodget.c | 4 | ||||
-rw-r--r-- | cpukit/score/src/coretodsecondssinceepoch.c | 32 | ||||
-rw-r--r-- | cpukit/score/src/coretodset.c | 17 | ||||
-rw-r--r-- | cpukit/score/src/coretodtickle.c | 15 |
8 files changed, 90 insertions, 30 deletions
diff --git a/cpukit/rtems/src/clockgetuptimeseconds.c b/cpukit/rtems/src/clockgetuptimeseconds.c index c1dfbf3785..3b597acaa8 100644 --- a/cpukit/rtems/src/clockgetuptimeseconds.c +++ b/cpukit/rtems/src/clockgetuptimeseconds.c @@ -24,18 +24,18 @@ #endif #include <rtems/rtems/clock.h> -#include <rtems/score/isrlevel.h> #include <rtems/score/todimpl.h> time_t rtems_clock_get_uptime_seconds( void ) { - Timestamp_Control snapshot_as_timestamp; - struct timespec snapshot_as_timespec; - ISR_Level level; + TOD_Control *tod = &_TOD; + Timestamp_Control snapshot_as_timestamp; + struct timespec snapshot_as_timespec; + ISR_Level level; - _ISR_Disable( level ); - snapshot_as_timestamp = _TOD.uptime; - _ISR_Enable( level ); + _TOD_Acquire( tod, level ); + snapshot_as_timestamp = tod->uptime; + _TOD_Release( tod, level ); _Timestamp_To_timespec( &snapshot_as_timestamp, &snapshot_as_timespec ); diff --git a/cpukit/score/Makefile.am b/cpukit/score/Makefile.am index e300c3e8ef..173f151258 100644 --- a/cpukit/score/Makefile.am +++ b/cpukit/score/Makefile.am @@ -301,6 +301,7 @@ libscore_a_SOURCES += src/ts64addto.c src/ts64dividebyinteger.c \ ## TOD_C_FILES libscore_a_SOURCES += src/coretod.c src/coretodset.c src/coretodget.c \ src/coretodgetuptimetimespec.c src/coretodtickle.c \ + src/coretodsecondssinceepoch.c \ src/coretodtickspersec.c ## WATCHDOG_C_FILES diff --git a/cpukit/score/include/rtems/score/todimpl.h b/cpukit/score/include/rtems/score/todimpl.h index a7c3e5d737..097965cbc7 100644 --- a/cpukit/score/include/rtems/score/todimpl.h +++ b/cpukit/score/include/rtems/score/todimpl.h @@ -19,6 +19,7 @@ #define _RTEMS_SCORE_TODIMPL_H #include <rtems/score/tod.h> +#include <rtems/score/isrlock.h> #include <rtems/score/timestamp.h> #include <sys/time.h> @@ -130,16 +131,25 @@ extern "C" { */ typedef struct { /** - * @brief Current time of day value. + * @brief Current time of day value. + * + * This field is protected by the lock. */ Timestamp_Control now; /** - * @brief System uptime. + * @brief System uptime. + * + * This field is protected by the lock. */ Timestamp_Control uptime; /** + * @brief Lock to protect the now and uptime fields. + */ + ISR_lock_Control lock; + + /** * @brief Time of day seconds trigger. * * This value specifies the nanoseconds since the last time of day second. @@ -166,14 +176,11 @@ typedef struct { SCORE_EXTERN TOD_Control _TOD; -/** - * @brief Number of seconds Since RTEMS epoch. - * - * The following contains the number of seconds from 00:00:00 - * January 1, TOD_BASE_YEAR until the current time of day. - */ -#define _TOD_Seconds_since_epoch() \ - _Timestamp_Get_seconds(&_TOD.now) +#define _TOD_Acquire( _tod, _isr_cookie ) \ + _ISR_lock_ISR_disable_and_acquire( &( _tod )->lock, _isr_cookie ) + +#define _TOD_Release( _tod, _isr_cookie ) \ + _ISR_lock_Release_and_ISR_enable( &( _tod )->lock, _isr_cookie ) /** * @brief Initializes the time of day handler. @@ -264,6 +271,14 @@ void _TOD_Get_uptime_as_timespec( ); /** + * @brief Number of seconds Since RTEMS epoch. + * + * The following contains the number of seconds from 00:00:00 + * January 1, TOD_BASE_YEAR until the current time of day. + */ +uint32_t _TOD_Seconds_since_epoch( void ); + +/** * @brief Increments time of day at each clock tick. * * This routine increments the ticks field of the current time of diff --git a/cpukit/score/src/coretod.c b/cpukit/score/src/coretod.c index 3359d4e8ca..25edef021d 100644 --- a/cpukit/score/src/coretod.c +++ b/cpukit/score/src/coretod.c @@ -29,6 +29,8 @@ void _TOD_Handler_initialization(void) { TOD_Control *tod = &_TOD; + _ISR_lock_Initialize( &tod->lock ); + _Timestamp_Set( &tod->now, TOD_SECONDS_1970_THROUGH_1988, 0 ); _Timestamp_Set_to_zero( &tod->uptime ); diff --git a/cpukit/score/src/coretodget.c b/cpukit/score/src/coretodget.c index 50262fd2f5..50ca8a0029 100644 --- a/cpukit/score/src/coretodget.c +++ b/cpukit/score/src/coretodget.c @@ -32,10 +32,10 @@ Timestamp_Control *_TOD_Get_with_nanoseconds( Timestamp_Control now; uint32_t nanoseconds; - _ISR_Disable( level ); + _TOD_Acquire( tod, level ); nanoseconds = ( *tod->nanoseconds_since_last_tick )(); now = *clock; - _ISR_Enable( level ); + _TOD_Release( tod, level ); _Timestamp_Set( &offset, 0, nanoseconds ); _Timestamp_Add_to( &now, &offset ); diff --git a/cpukit/score/src/coretodsecondssinceepoch.c b/cpukit/score/src/coretodsecondssinceepoch.c new file mode 100644 index 0000000000..91445c0c80 --- /dev/null +++ b/cpukit/score/src/coretodsecondssinceepoch.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2013 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#if HAVE_CONFIG_H + #include "config.h" +#endif + +#include <rtems/score/todimpl.h> + +uint32_t _TOD_Seconds_since_epoch( void ) +{ + TOD_Control *tod = &_TOD; + ISR_Level level; + Timestamp_Control now; + + _TOD_Acquire( tod, level ); + now = tod->now; + _TOD_Release( tod, level ); + + return _Timestamp_Get_seconds( &now ); +} diff --git a/cpukit/score/src/coretodset.c b/cpukit/score/src/coretodset.c index ff76581bbd..c265606137 100644 --- a/cpukit/score/src/coretodset.c +++ b/cpukit/score/src/coretodset.c @@ -23,12 +23,14 @@ #include <rtems/score/watchdogimpl.h> void _TOD_Set_with_timestamp( - const Timestamp_Control *tod + const Timestamp_Control *tod_as_timestamp ) { - uint32_t nanoseconds = _Timestamp_Get_nanoseconds( tod ); - Watchdog_Interval seconds_next = _Timestamp_Get_seconds( tod ); + TOD_Control *tod = &_TOD; + uint32_t nanoseconds = _Timestamp_Get_nanoseconds( tod_as_timestamp ); + Watchdog_Interval seconds_next = _Timestamp_Get_seconds( tod_as_timestamp ); Watchdog_Interval seconds_now; + ISR_Level level; _Thread_Disable_dispatch(); @@ -39,9 +41,12 @@ void _TOD_Set_with_timestamp( else _Watchdog_Adjust_seconds( WATCHDOG_FORWARD, seconds_next - seconds_now ); - _TOD.now = *tod; - _TOD.seconds_trigger = nanoseconds; - _TOD.is_set = true; + _TOD_Acquire( tod, level ); + tod->now = *tod_as_timestamp; + _TOD_Release( tod, level ); + + tod->seconds_trigger = nanoseconds; + tod->is_set = true; _Thread_Enable_dispatch(); } diff --git a/cpukit/score/src/coretodtickle.c b/cpukit/score/src/coretodtickle.c index 4586e8496f..c9f9597b1d 100644 --- a/cpukit/score/src/coretodtickle.c +++ b/cpukit/score/src/coretodtickle.c @@ -24,8 +24,10 @@ void _TOD_Tickle_ticks( void ) { - Timestamp_Control tick; - uint32_t nanoseconds_per_tick; + TOD_Control *tod = &_TOD; + ISR_Level level; + Timestamp_Control tick; + uint32_t nanoseconds_per_tick; nanoseconds_per_tick = rtems_configuration_get_nanoseconds_per_tick(); @@ -35,12 +37,15 @@ void _TOD_Tickle_ticks( void ) /* Update the counter of ticks since boot */ _Watchdog_Ticks_since_boot += 1; + _TOD_Acquire( tod, level ); + /* Update the uptime */ - _Timestamp_Add_to( &_TOD.uptime, &tick ); - /* we do not care how much the uptime changed */ + _Timestamp_Add_to( &tod->uptime, &tick ); /* Update the current TOD */ - _Timestamp_Add_to( &_TOD.now, &tick ); + _Timestamp_Add_to( &tod->now, &tick ); + + _TOD_Release( tod, level ); _TOD.seconds_trigger += nanoseconds_per_tick; if ( _TOD.seconds_trigger >= 1000000000UL ) { |