[PATCH 5/5] score: Use an ISR lock for TOD
Sebastian Huber
sebastian.huber at embedded-brains.de
Wed Jul 31 13:15:14 UTC 2013
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 a non-monotonous 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().
---
cpukit/rtems/src/clockgetuptimeseconds.c | 14 +++++-----
cpukit/score/Makefile.am | 1 +
cpukit/score/include/rtems/score/todimpl.h | 35 +++++++++++++++++++-------
cpukit/score/src/coretod.c | 2 +
cpukit/score/src/coretodget.c | 4 +-
cpukit/score/src/coretodsecondssinceepoch.c | 32 ++++++++++++++++++++++++
cpukit/score/src/coretodset.c | 17 ++++++++----
cpukit/score/src/coretodtickle.c | 15 +++++++----
8 files changed, 90 insertions(+), 30 deletions(-)
create mode 100644 cpukit/score/src/coretodsecondssinceepoch.c
diff --git a/cpukit/rtems/src/clockgetuptimeseconds.c b/cpukit/rtems/src/clockgetuptimeseconds.c
index c1dfbf3..3b597ac 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 e300c3e..173f151 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 a7c3e5d..2a7671f 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_Acquire( &( _tod )->lock, _isr_cookie )
+
+#define _TOD_Release( _tod, _isr_cookie ) \
+ _ISR_lock_Release( &( _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 3359d4e..25edef0 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 50262fd..50ca8a0 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 0000000..91445c0
--- /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 at 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 ff76581..c265606 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 4586e84..c9f9597 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 ) {
--
1.7.7
More information about the devel
mailing list