[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