[PATCH 3/4] smp: New SMP lock API

Sebastian Huber sebastian.huber at embedded-brains.de
Wed May 29 15:31:08 UTC 2013


Move the SMP lock implementation to the CPU port.  An optimal SMP lock
implementation is highly architecture dependent.  For example the memory
models may be fundamentally different.

The new SMP lock API has a flaw.  It does not provide the ability to use
a local context for aquire and release pairs.  Such a context is
necessary to implement for example the Mellor-Crummey and Scott (MCS)
locks.  The SMP lock is currently used in _Thread_Disable_dispatch() and
_Thread_Enable_dispatch() and makes them to a giant lock acquire and
release.  Since these functions do not pass state information via a
local context there is currently no use case for such a feature.
---
 cpukit/score/Makefile.am                         |    2 +-
 cpukit/score/cpu/i386/Makefile.am                |    1 +
 cpukit/score/cpu/i386/preinstall.am              |    4 +
 cpukit/score/cpu/i386/rtems/score/cpu.h          |    9 -
 cpukit/score/cpu/i386/rtems/score/cpusmplock.h   |  100 ++++++++
 cpukit/score/cpu/no_cpu/Makefile.am              |    1 +
 cpukit/score/cpu/no_cpu/preinstall.am            |    4 +
 cpukit/score/cpu/no_cpu/rtems/score/cpusmplock.h |  114 +++++++++
 cpukit/score/cpu/sparc/Makefile.am               |    1 +
 cpukit/score/cpu/sparc/preinstall.am             |    4 +
 cpukit/score/cpu/sparc/rtems/score/cpu.h         |   18 --
 cpukit/score/cpu/sparc/rtems/score/cpusmplock.h  |  105 ++++++++
 cpukit/score/include/rtems/score/percpu.h        |    2 +-
 cpukit/score/include/rtems/score/smplock.h       |  173 ++++++--------
 cpukit/score/include/rtems/score/thread.h        |    9 +-
 cpukit/score/src/smp.c                           |   14 +-
 cpukit/score/src/smplock.c                       |  285 ----------------------
 cpukit/score/src/threaddispatchdisablelevel.c    |   86 ++++----
 18 files changed, 469 insertions(+), 463 deletions(-)
 create mode 100644 cpukit/score/cpu/i386/rtems/score/cpusmplock.h
 create mode 100644 cpukit/score/cpu/no_cpu/rtems/score/cpusmplock.h
 create mode 100644 cpukit/score/cpu/sparc/rtems/score/cpusmplock.h
 delete mode 100644 cpukit/score/src/smplock.c

diff --git a/cpukit/score/Makefile.am b/cpukit/score/Makefile.am
index 604ab34..d4c79ac 100644
--- a/cpukit/score/Makefile.am
+++ b/cpukit/score/Makefile.am
@@ -135,7 +135,7 @@ libscore_a_SOURCES += src/mpci.c src/objectmp.c src/threadmp.c
 endif
 
 if HAS_SMP
-libscore_a_SOURCES += src/isrsmp.c src/smp.c src/smplock.c \
+libscore_a_SOURCES += src/isrsmp.c src/smp.c \
     src/schedulersimplesmpblock.c src/schedulersimplesmpschedule.c \
     src/schedulersimplesmpunblock.c src/schedulersimplesmptick.c 
 endif
diff --git a/cpukit/score/cpu/i386/Makefile.am b/cpukit/score/cpu/i386/Makefile.am
index d25002d..e35a81c 100644
--- a/cpukit/score/cpu/i386/Makefile.am
+++ b/cpukit/score/cpu/i386/Makefile.am
@@ -11,6 +11,7 @@ include_rtems_score_HEADERS += rtems/score/interrupts.h
 include_rtems_score_HEADERS += rtems/score/registers.h
 include_rtems_score_HEADERS += rtems/score/idtr.h
 include_rtems_score_HEADERS += rtems/score/cpuatomic.h
+include_rtems_score_HEADERS += rtems/score/cpusmplock.h
 
 noinst_LIBRARIES = libscorecpu.a
 libscorecpu_a_SOURCES = cpu.c cpu_asm.S
diff --git a/cpukit/score/cpu/i386/preinstall.am b/cpukit/score/cpu/i386/preinstall.am
index 060176b..f9faf87 100644
--- a/cpukit/score/cpu/i386/preinstall.am
+++ b/cpukit/score/cpu/i386/preinstall.am
@@ -55,3 +55,7 @@ $(PROJECT_INCLUDE)/rtems/score/cpuatomic.h: rtems/score/cpuatomic.h $(PROJECT_IN
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/cpuatomic.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/cpuatomic.h
 
+$(PROJECT_INCLUDE)/rtems/score/cpusmplock.h: rtems/score/cpusmplock.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/cpusmplock.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/cpusmplock.h
+
diff --git a/cpukit/score/cpu/i386/rtems/score/cpu.h b/cpukit/score/cpu/i386/rtems/score/cpu.h
index c262e3c..3f7a331 100644
--- a/cpukit/score/cpu/i386/rtems/score/cpu.h
+++ b/cpukit/score/cpu/i386/rtems/score/cpu.h
@@ -455,15 +455,6 @@ uint32_t   _CPU_ISR_Get_level( void );
   #define _CPU_Context_switch_to_first_task_smp( _the_context ) \
      _CPU_Context_restore( (_the_context) );
 
-  /* address space 1 is uncacheable */
-  #define SMP_CPU_SWAP( _address, _value, _previous ) \
-    do { \
-      asm volatile("lock; xchgl %0, %1" : \
-        "+m" (*_address), "=a" (_previous) : \
-        "1" (_value) : \
-        "cc"); \
-    } while (0)
-
   static inline void _CPU_Processor_event_broadcast( void )
   {
     __asm__ volatile ( "" : : : "memory" );
diff --git a/cpukit/score/cpu/i386/rtems/score/cpusmplock.h b/cpukit/score/cpu/i386/rtems/score/cpusmplock.h
new file mode 100644
index 0000000..34f02db
--- /dev/null
+++ b/cpukit/score/cpu/i386/rtems/score/cpusmplock.h
@@ -0,0 +1,100 @@
+/**
+ * @file
+ *
+ * @ingroup ScoreSMPLockI386
+ *
+ * @brief i386 SMP Lock Implementation
+ */
+
+/*
+ * COPYRIGHT (c) 1989-2011.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * Copyright (c) 2013 embedded brains GmbH
+ *
+ * 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.
+ */
+
+#ifndef _RTEMS_SCORE_I386_SMPLOCK_H
+#define _RTEMS_SCORE_I386_SMPLOCK_H
+
+#include <rtems/score/cpu.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * @defgroup ScoreSMPLockI386 i386 SMP Locks
+ *
+ * @ingroup ScoreSMPLock
+ *
+ * The implementation is Test and Test-and-set.
+ *
+ * @{
+ */
+
+typedef struct {
+  uint32_t locked;
+} CPU_SMP_lock_Control;
+
+#define CPU_SMP_LOCK_INITIALIZER { 0 }
+
+static inline void _CPU_SMP_lock_Initialize( CPU_SMP_lock_Control *lock )
+{
+  lock->locked = 0;
+}
+
+static inline uint32_t _I386_Atomic_swap(
+  volatile uint32_t *address,
+  uint32_t value
+)
+{
+  uint32_t previous;
+
+  asm volatile(
+    "lock; xchgl %0, %1"
+    : "+m" (*address), "=a" (previous)
+    : "1" (value)
+    : "cc"
+  );
+
+  return previous;
+}
+
+static inline void _CPU_SMP_lock_Acquire( CPU_SMP_lock_Control *lock )
+{
+  do {
+    while ( lock->locked ) {
+      /* Do nothing */
+    }
+  } while ( _I386_Atomic_swap( &lock->locked, 1 ) );
+}
+
+static inline void _CPU_SMP_lock_Release( CPU_SMP_lock_Control *lock )
+{
+  RTEMS_COMPILER_MEMORY_BARRIER();
+  lock->locked = 0;
+}
+
+#define _CPU_SMP_lock_ISR_disable_and_acquire( lock, isr_cookie ) \
+  do { \
+    _CPU_ISR_Disable( isr_cookie ); \
+    _CPU_SMP_lock_Acquire( lock ); \
+  } while (0)
+
+#define _CPU_SMP_lock_Release_and_ISR_enable( lock, isr_cookie ) \
+  do { \
+    _CPU_SMP_lock_Release( lock ); \
+    _CPU_ISR_Enable( isr_cookie ); \
+  } while (0)
+
+/**@}*/
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _RTEMS_SCORE_I386_SMPLOCK_H */
diff --git a/cpukit/score/cpu/no_cpu/Makefile.am b/cpukit/score/cpu/no_cpu/Makefile.am
index 820579c..2451743 100644
--- a/cpukit/score/cpu/no_cpu/Makefile.am
+++ b/cpukit/score/cpu/no_cpu/Makefile.am
@@ -8,6 +8,7 @@ include_rtems_score_HEADERS = rtems/score/cpu.h
 include_rtems_score_HEADERS += rtems/score/no_cpu.h
 include_rtems_score_HEADERS += rtems/score/cpu_asm.h
 include_rtems_score_HEADERS += rtems/score/types.h
+include_rtems_score_HEADERS += rtems/score/cpusmplock.h
 
 noinst_LIBRARIES = libscorecpu.a
 libscorecpu_a_SOURCES = cpu.c cpu_asm.c
diff --git a/cpukit/score/cpu/no_cpu/preinstall.am b/cpukit/score/cpu/no_cpu/preinstall.am
index a56caea..a46f8b0 100644
--- a/cpukit/score/cpu/no_cpu/preinstall.am
+++ b/cpukit/score/cpu/no_cpu/preinstall.am
@@ -43,3 +43,7 @@ $(PROJECT_INCLUDE)/rtems/score/types.h: rtems/score/types.h $(PROJECT_INCLUDE)/r
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/types.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/types.h
 
+$(PROJECT_INCLUDE)/rtems/score/cpusmplock.h: rtems/score/cpusmplock.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/cpusmplock.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/cpusmplock.h
+
diff --git a/cpukit/score/cpu/no_cpu/rtems/score/cpusmplock.h b/cpukit/score/cpu/no_cpu/rtems/score/cpusmplock.h
new file mode 100644
index 0000000..387bbb4
--- /dev/null
+++ b/cpukit/score/cpu/no_cpu/rtems/score/cpusmplock.h
@@ -0,0 +1,114 @@
+/**
+ * @file
+ *
+ * @ingroup ScoreSMPLockCPU
+ *
+ * @brief CPU SMP Lock Implementation
+ */
+
+/*
+ * Copyright (c) 2013 embedded brains GmbH
+ *
+ * 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.
+ */
+
+#ifndef _RTEMS_SCORE_NO_CPU_SMPLOCK_H
+#define _RTEMS_SCORE_NO_CPU_SMPLOCK_H
+
+#include <rtems/score/cpu.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * @defgroup ScoreSMPLockCPU CPU SMP Locks
+ *
+ * @ingroup ScoreSMPLock
+ *
+ * This example will implement a ticket lock.
+ *
+ * @{
+ */
+
+/**
+ * @brief CPU SMP lock control.
+ */
+typedef struct {
+  unsigned int next_ticket;
+  unsigned int now_serving;
+} CPU_SMP_lock_Control;
+
+/**
+ * @brief CPU SMP lock control initializer for static initialization.
+ */
+#define CPU_SMP_LOCK_INITIALIZER { 0, 0 }
+
+/**
+ * @brief Initializes a CPU SMP lock control.
+ *
+ * @param[out] lock The CPU SMP lock control.
+ */
+static inline void _CPU_SMP_lock_Initialize( CPU_SMP_lock_Control *lock )
+{
+  lock->next_ticket = 0;
+  lock->now_serving = 0;
+}
+
+/**
+ * @brief Acquires a CPU SMP lock.
+ *
+ * @param[in/out] lock The CPU SMP lock control.
+ */
+static inline void _CPU_SMP_lock_Acquire( CPU_SMP_lock_Control *lock )
+{
+  unsigned int my_ticket = _Atomic_Fetch_and_increment( &lock->next_ticket );
+
+  while ( _Atomic_Load_and_acquire( &lock->now_serving ) != my_ticket ) {
+    _Wait_some_time();
+  }
+}
+
+/**
+ * @brief Releases a CPU SMP lock.
+ *
+ * @param[in/out] lock The CPU SMP lock control.
+ */
+static inline void _CPU_SMP_lock_Release( CPU_SMP_lock_Control *lock )
+{
+  _Atomic_Store_and_release( &lock->now_serving, lock->now_serving + 1 );
+}
+
+/**
+ * @brief Disables interrupts and acquires the CPU SMP lock.
+ *
+ * @param[in/out] lock The CPU SMP lock control.
+ * @param[out] isr_cookie The ISR cookie.
+ */
+#define _CPU_SMP_lock_ISR_disable_and_acquire( lock, isr_cookie ) \
+  do { \
+    _CPU_ISR_Disable( isr_cookie ); \
+    _CPU_SMP_lock_Acquire( lock ); \
+  } while (0)
+
+/**
+ * @brief Releases the CPU SMP lock and enables interrupts.
+ *
+ * @param[in/out] lock The CPU SMP lock control.
+ * @param[in] isr_cookie The ISR cookie.
+ */
+#define _CPU_SMP_lock_Release_and_ISR_enable( lock, isr_cookie ) \
+  do { \
+    _CPU_SMP_lock_Release( lock ); \
+    _CPU_ISR_Enable( isr_cookie ); \
+  } while (0)
+
+/**@}*/
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _RTEMS_SCORE_NO_CPU_SMPLOCK_H */
diff --git a/cpukit/score/cpu/sparc/Makefile.am b/cpukit/score/cpu/sparc/Makefile.am
index 4bb09c6..3065f3c 100644
--- a/cpukit/score/cpu/sparc/Makefile.am
+++ b/cpukit/score/cpu/sparc/Makefile.am
@@ -8,6 +8,7 @@ include_rtems_score_HEADERS = rtems/score/sparc.h
 include_rtems_score_HEADERS += rtems/score/cpu.h
 include_rtems_score_HEADERS += rtems/score/types.h
 include_rtems_score_HEADERS += rtems/score/cpuatomic.h
+include_rtems_score_HEADERS += rtems/score/cpusmplock.h
 
 noinst_LIBRARIES = libscorecpu.a
 libscorecpu_a_SOURCES = cpu.c cpu_asm.S
diff --git a/cpukit/score/cpu/sparc/preinstall.am b/cpukit/score/cpu/sparc/preinstall.am
index a2bb01b..e497b48 100644
--- a/cpukit/score/cpu/sparc/preinstall.am
+++ b/cpukit/score/cpu/sparc/preinstall.am
@@ -43,3 +43,7 @@ $(PROJECT_INCLUDE)/rtems/score/cpuatomic.h: rtems/score/cpuatomic.h $(PROJECT_IN
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/cpuatomic.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/cpuatomic.h
 
+$(PROJECT_INCLUDE)/rtems/score/cpusmplock.h: rtems/score/cpusmplock.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/cpusmplock.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/cpusmplock.h
+
diff --git a/cpukit/score/cpu/sparc/rtems/score/cpu.h b/cpukit/score/cpu/sparc/rtems/score/cpu.h
index 9654c29..defc01a 100644
--- a/cpukit/score/cpu/sparc/rtems/score/cpu.h
+++ b/cpukit/score/cpu/sparc/rtems/score/cpu.h
@@ -1186,24 +1186,6 @@ void _CPU_Context_restore(
     Context_Control *new_context
   );
 
-  /**
-   * Macro to access memory and bypass the cache.
-   *
-   * NOTE: address space 1 is uncacheable
-   */
-  #define SMP_CPU_SWAP( _address, _value, _previous ) \
-    do { \
-      register unsigned int _val = _value; \
-      asm volatile( \
-        "swapa [%2] %3, %0" : \
-        "=r" (_val) : \
-        "0" (_val), \
-        "r" (_address), \
-        "i" (1) \
-      ); \
-      _previous = _val; \
-    } while (0)
-
   static inline void _CPU_Processor_event_broadcast( void )
   {
     __asm__ volatile ( "" : : : "memory" );
diff --git a/cpukit/score/cpu/sparc/rtems/score/cpusmplock.h b/cpukit/score/cpu/sparc/rtems/score/cpusmplock.h
new file mode 100644
index 0000000..b2acd3f
--- /dev/null
+++ b/cpukit/score/cpu/sparc/rtems/score/cpusmplock.h
@@ -0,0 +1,105 @@
+/**
+ * @file
+ *
+ * @ingroup ScoreSMPLockSPARC
+ *
+ * @brief SPARC SMP Lock Implementation
+ */
+
+/*
+ * COPYRIGHT (c) 1989-2011.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * Copyright (c) 2013 embedded brains GmbH
+ *
+ * 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.
+ */
+
+#ifndef _RTEMS_SCORE_SPARC_SMPLOCK_H
+#define _RTEMS_SCORE_SPARC_SMPLOCK_H
+
+#include <rtems/score/cpu.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * @defgroup ScoreSMPLockSPARC SPARC SMP Locks
+ *
+ * @ingroup ScoreSMPLock
+ *
+ * The implementation is Test and Test-and-set.
+ *
+ * @{
+ */
+
+typedef struct {
+  uint32_t locked;
+} CPU_SMP_lock_Control;
+
+#define CPU_SMP_LOCK_INITIALIZER { 0 }
+
+static inline void _CPU_SMP_lock_Initialize( CPU_SMP_lock_Control *lock )
+{
+  lock->locked = 0;
+}
+
+/*
+ * Function to access memory and bypass the cache.
+ *
+ * NOTE: address space 1 is uncacheable
+ *
+ * FIXME: This implementation uses specific Leon features.
+ */
+static inline uint32_t _SPARC_Atomic_swap(
+  volatile uint32_t *address,
+  uint32_t value
+)
+{
+  asm volatile (
+    "swapa [%2] %3, %0"
+    : "=r" (value)
+    : "0" (value), "r" (address), "i" (1)
+    : "memory"
+  );
+
+  return value;
+}
+
+static inline void _CPU_SMP_lock_Acquire( CPU_SMP_lock_Control *lock )
+{
+  do {
+    while ( lock->locked ) {
+      /* Do nothing */
+    }
+  } while ( _SPARC_Atomic_swap( &lock->locked, 1 ) );
+}
+
+static inline void _CPU_SMP_lock_Release( CPU_SMP_lock_Control *lock )
+{
+  RTEMS_COMPILER_MEMORY_BARRIER();
+  lock->locked = 0;
+}
+
+#define _CPU_SMP_lock_ISR_disable_and_acquire( lock, isr_cookie ) \
+  do { \
+    _CPU_ISR_Disable( isr_cookie ); \
+    _CPU_SMP_lock_Acquire( lock ); \
+  } while (0)
+
+#define _CPU_SMP_lock_Release_and_ISR_enable( lock, isr_cookie ) \
+  do { \
+    _CPU_SMP_lock_Release( lock ); \
+    _CPU_ISR_Enable( isr_cookie ); \
+  } while (0)
+
+/**@}*/
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _RTEMS_SCORE_SPARC_SMPLOCK_H */
diff --git a/cpukit/score/include/rtems/score/percpu.h b/cpukit/score/include/rtems/score/percpu.h
index f545310..3b97a68 100644
--- a/cpukit/score/include/rtems/score/percpu.h
+++ b/cpukit/score/include/rtems/score/percpu.h
@@ -167,7 +167,7 @@ typedef struct {
 
   #if defined(RTEMS_SMP)
     /** This element is used to lock this structure */
-    SMP_lock_spinlock_simple_Control  lock;
+    SMP_lock_Control lock;
 
     /**
      *  This is the request for the interrupt.
diff --git a/cpukit/score/include/rtems/score/smplock.h b/cpukit/score/include/rtems/score/smplock.h
index 6db8a43..e9c7088 100644
--- a/cpukit/score/include/rtems/score/smplock.h
+++ b/cpukit/score/include/rtems/score/smplock.h
@@ -1,149 +1,122 @@
 /**
- *  @file  rtems/score/smplock.h
+ * @file
  *
- *  @brief Interface for Atomic Locks
+ * @ingroup ScoreSMPLock
  *
- *  This include file defines the interface for atomic locks
- *  which can be used in multiprocessor configurations.
+ * @brief SMP Lock API
  */
 
 /*
- *  COPYRIGHT (c) 1989-2011.
- *  On-Line Applications Research Corporation (OAR).
+ * COPYRIGHT (c) 1989-2011.
+ * On-Line Applications Research Corporation (OAR).
  *
- *  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.
+ * Copyright (c) 2013 embedded brains GmbH
+ *
+ * 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.
  */
 
-#ifndef _RTEMS_LOCK_H
-#define _RTEMS_LOCK_H
+#ifndef _RTEMS_SCORE_SMPLOCK_H
+#define _RTEMS_SCORE_SMPLOCK_H
 
+#include <rtems/score/cpusmplock.h>
 #include <rtems/score/isr.h>
 
-/**
- *  @defgroup RTEMS Lock Interface
- *
- *  @ingroup Score
- *
- */
-
-/**@{*/
-
 #ifdef __cplusplus
 extern "C" {
-#endif
+#endif /* __cplusplus */
 
 /**
- *  This type is used to lock elements for atomic access.
- *  This spinlock is a simple non-nesting spinlock, and
- *  may be used for short non-nesting accesses.
+ * @defgroup ScoreSMPLock SMP Locks
+ *
+ * @ingroup Score
+ *
+ * The SMP lock implementation is architecture dependent.  The implementation
+ * should provide fairness in case of concurrent lock attempts.
+ *
+ * This SMP lock API has a flaw.  It does not provide the ability to use a
+ * local context for aquire and release pairs.  Such a context is necessary to
+ * implement for example the Mellor-Crummey and Scott (MCS) locks.  The SMP
+ * lock is currently used in _Thread_Disable_dispatch() and
+ * _Thread_Enable_dispatch() and makes them to a giant lock acquire and
+ * release.  Since these functions do not pass state information via a local
+ * context there is currently no use case for such a feature.
+ *
+ * @{
  */
-typedef uint32_t SMP_lock_spinlock_simple_Control;
 
 /**
- *  This type is used to lock elements for atomic access.
- *  This spinlock supports nesting, but is slightly more
- *  complicated to use.  Please see the descriptions of
- *  obtain and release prior to using in order to understand
- *  the callers responsibilty of managing short interupt disable
- *  times.
+ * @brief SMP lock control.
+ *
+ * This is an opaque type.  The SMP lock implementation is architecture
+ * dependent.
  */
-typedef struct {
-  SMP_lock_spinlock_simple_Control lock;
-  uint32_t  count;
-  int       cpu_id;
-} SMP_lock_spinlock_nested_Control;
+typedef CPU_SMP_lock_Control SMP_lock_Control;
 
 /**
- *  @brief Initialize a lock.
- *
- *  This method is used to initialize the lock at @a lock.
- *
- *  @param [in] lock is the address of the lock to obtain.
+ * @brief SMP lock control initializer for static initialization.
  */
-void _SMP_lock_spinlock_simple_Initialize(
-  SMP_lock_spinlock_simple_Control *lock
-);
+#define SMP_LOCK_INITIALIZER CPU_SMP_LOCK_INITIALIZER
 
 /**
- *  @brief Obtain a lock.
+ * @brief Initializes a SMP lock control.
  *
- *  This method is used to obtain the lock at @a lock.
+ * Concurrent initialization leads to unpredictable results.
  *
- *  @param [in] lock is the address of the lock to obtain.
- *
- *  @retval This method returns with processor interrupts disabled.
- *          The previous level is returned.
+ * @param[out] lock The SMP lock control.
  */
-ISR_Level _SMP_lock_spinlock_simple_Obtain(
-  SMP_lock_spinlock_simple_Control *lock
-);
+static inline void _SMP_lock_Initialize( SMP_lock_Control *lock )
+{
+  _CPU_SMP_lock_Initialize( lock );
+}
 
 /**
- *  @brief Release a lock.
+ * @brief Acquires a SMP lock.
  *
- *  This method is used to release the lock at @a lock.
+ * This function will not disable interrupts.  The caller must ensure that the
+ * current thread of execution is not interrupted indefinite once it obtained
+ * the SMP lock.
  *
- *  @param [in] lock is the address of the lock to obtain.
+ * @param[in/out] lock The SMP lock control.
  */
-void _SMP_lock_spinlock_simple_Release(
-  SMP_lock_spinlock_simple_Control  *lock,
-  ISR_Level                         level
-);
+static inline void _SMP_lock_Acquire( SMP_lock_Control *lock )
+{
+  _CPU_SMP_lock_Acquire( lock );
+}
 
 /**
- *  @brief Initialize a lock.
- *
- *  This method is used to initialize the lock at @a lock.
+ * @brief Releases a SMP lock.
  *
- *  @param [in] lock is the address of the lock to obtain.
+ * @param[in/out] lock The SMP lock control.
  */
-void _SMP_lock_spinlock_nested_Initialize(
-  SMP_lock_spinlock_nested_Control *lock
-);
+static inline void _SMP_lock_Release( SMP_lock_Control *lock )
+{
+  _CPU_SMP_lock_Release( lock );
+}
 
 /**
- *  @brief Obtain a lock.
- *
- *  This method is used to obtain the lock at @a lock.  ISR's are
- *  disabled when this routine returns and it is the callers responsibility
- *  to either:
- *
- *   # Do something very short and then call
- *      _SMP_lock_spinlock_nested_Release  or
- *   # Do something very sort, call isr enable, then when ready
- *      call isr_disable and _SMP_lock_spinlock_nested_Release
+ * @brief Disables interrupts and acquires the SMP lock.
  *
- *  @param [in] lock is the address of the lock to obtain.
- *
- *  @retval This method returns with processor interrupts disabled.
- *          The previous level is returned.
+ * @param[in/out] lock The SMP lock control.
+ * @param[out] isr_cookie The ISR cookie.
  */
-ISR_Level _SMP_lock_spinlock_nested_Obtain(
-  SMP_lock_spinlock_nested_Control *lock
-);
+#define _SMP_lock_ISR_disable_and_acquire( lock, isr_cookie ) \
+  _CPU_SMP_lock_ISR_disable_and_acquire( lock, isr_cookie )
 
 /**
- *  @brief Release a lock.
- *
- *  This method is used to release the lock at @a lock.
+ * @brief Releases the SMP lock and enables interrupts.
  *
- *  @note ISR's are reenabled by this method and are expected to be
- *  disabled upon entry to the method.
- *
- *  @param [in] lock is the address of the lock to obtain.
+ * @param[in/out] lock The SMP lock control.
+ * @param[in] isr_cookie The ISR cookie.
  */
-void _SMP_lock_spinlock_nested_Release(
-  SMP_lock_spinlock_nested_Control  *lock,
-  ISR_Level                         level
-);
+#define _SMP_lock_Release_and_ISR_enable( lock, isr_cookie ) \
+  _CPU_SMP_lock_Release_and_ISR_enable( lock, isr_cookie )
+
+/**@}*/
 
 #ifdef __cplusplus
 }
-#endif
-
-/**@}*/
+#endif /* __cplusplus */
 
-#endif
-/* end of include file */
+#endif /* _RTEMS_SCORE_SMPLOCK_H */
diff --git a/cpukit/score/include/rtems/score/thread.h b/cpukit/score/include/rtems/score/thread.h
index 248be62..9461c85 100644
--- a/cpukit/score/include/rtems/score/thread.h
+++ b/cpukit/score/include/rtems/score/thread.h
@@ -470,11 +470,18 @@ SCORE_EXTERN Context_Control _Thread_BSP_context;
 SCORE_EXTERN volatile uint32_t   _Thread_Dispatch_disable_level;
 
 #if defined(RTEMS_SMP)
+  typedef struct {
+    SMP_lock_Control lock;
+    int owner_cpu;
+    int nest_level;
+  } Thread_Dispatch_disable_level_lock_control;
+
   /**
    * The following declares the smp spinlock to be used to control
    * the dispatch critical section accesses across cpus.
    */
-  SCORE_EXTERN SMP_lock_spinlock_nested_Control _Thread_Dispatch_disable_level_lock;
+  SCORE_EXTERN Thread_Dispatch_disable_level_lock_control
+    _Thread_Dispatch_disable_level_lock;
 #endif
 
 /**
diff --git a/cpukit/score/src/smp.c b/cpukit/score/src/smp.c
index 69f5337..6f1bc55 100644
--- a/cpukit/score/src/smp.c
+++ b/cpukit/score/src/smp.c
@@ -69,10 +69,10 @@ void rtems_smp_process_interrupt( void )
   ISR_Level        level;
 
 
-  level = _SMP_lock_spinlock_simple_Obtain( &per_cpu->lock );
+  _SMP_lock_ISR_disable_and_acquire( &per_cpu->lock, level );
   message = per_cpu->message;
   per_cpu->message = 0;
-  _SMP_lock_spinlock_simple_Release( &per_cpu->lock, level );
+  _SMP_lock_Release_and_ISR_enable( &per_cpu->lock, level );
 
   #if defined(RTEMS_DEBUG)
     {
@@ -115,9 +115,9 @@ void _SMP_Send_message( int cpu, uint32_t message )
       printk( "Send 0x%x to %d\n", message, cpu );
   #endif
 
-  level = _SMP_lock_spinlock_simple_Obtain( &per_cpu->lock );
+  _SMP_lock_ISR_disable_and_acquire( &per_cpu->lock, level );
   per_cpu->message |= message;
-  _SMP_lock_spinlock_simple_Release( &per_cpu->lock, level );
+  _SMP_lock_Release_and_ISR_enable( &per_cpu->lock, level );
 
   bsp_smp_interrupt_cpu( cpu );
 }
@@ -131,9 +131,11 @@ void _SMP_Broadcast_message( uint32_t message )
   for ( cpu = 0 ; cpu < ncpus ; ++cpu ) {
     if ( cpu != self ) {
       Per_CPU_Control *per_cpu = &_Per_CPU_Information[ cpu ];
-      ISR_Level level = _SMP_lock_spinlock_simple_Obtain( &per_cpu->lock );
+      ISR_Level level;
+
+      _SMP_lock_ISR_disable_and_acquire( &per_cpu->lock, level );
       per_cpu->message |= message;
-      _SMP_lock_spinlock_simple_Release( &per_cpu->lock, level );
+      _SMP_lock_Release_and_ISR_enable( &per_cpu->lock, level );
     }
   }
 
diff --git a/cpukit/score/src/smplock.c b/cpukit/score/src/smplock.c
deleted file mode 100644
index 89f8a86..0000000
--- a/cpukit/score/src/smplock.c
+++ /dev/null
@@ -1,285 +0,0 @@
-/**
- *  @file
- *
- *  @brief SMP Locking Support
- *  @ingroup RTEMS
- */
-
-/*
- *  COPYRIGHT (c) 1989-2011.
- *  On-Line Applications Research Corporation (OAR).
- *
- *  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/system.h>
-#include <rtems/score/smplock.h>
-#include <rtems/score/smp.h>
-#include <rtems/score/isr.h>
-
-/*
- * Some debug stuff that is being left in, but disabled.  This will keep 
- * a log of lock/unlock sequences that can be printed out when the 
- * lockcount appears to have gotten off track.
- */
-/* #define SMPLOCK_DEBUG */
-#if defined (SMPLOCK_DEBUG)
-  #include <rtems/score/thread.h>
-  #include <rtems/bspIo.h>
-  #include <rtems/score/percpu.h>
-  #if (0)
-    #define  ENABLE_ONESHOT_DEBUG_LOGGING
-  #else
-    #define ENABLE_LOOPED_DEBUG_LOGGING
-  #endif
-  #define ENABLE_DEBUG_LOGGING 
-#endif
-
-/*
- * Prototypes and structures used in the debug lock/unlock error log.
- */
-#if defined(ENABLE_DEBUG_LOGGING)
-  typedef struct {
-    char      action;
-    char      lock;
-    char      cpu;
-    char      count;
-    uint32_t  nest_level;
-    void      *ret1;
-    void      *ret2;
-    void      *ret3;
-    void      *ret4;
-  } debug_spinlog_t;
-
-  extern void start(void);
-  extern void _fini(void);
-
-  #define DEBUG_SPINLOG_MAX 1024
-  debug_spinlog_t DEBUG_SPINLOG[DEBUG_SPINLOG_MAX];
-  int DEBUG_SPINLOG_INDEX = 0;
-
-  static void debug_logit(
-    char                             act,
-    SMP_lock_spinlock_nested_Control *lock
-  );
-  static void debug_dump_log(void);
-#else
-  #define debug_logit( _act, _lock )
-  #define debug_dump_log()
-#endif
-
-void _SMP_lock_spinlock_simple_Initialize(
-  SMP_lock_spinlock_simple_Control *lock
-)
-{
-  *lock = 0;
-}
-
-ISR_Level _SMP_lock_spinlock_simple_Obtain(
-  SMP_lock_spinlock_simple_Control *lock
-)
-{
-   ISR_Level  level = 0;
-   uint32_t   value = 1;
-   uint32_t   previous;
-
-   /* Note: Disable provides an implicit memory barrier. */
-  _ISR_Disable_on_this_core( level );
-   do {
-     RTEMS_COMPILER_MEMORY_BARRIER();
-     SMP_CPU_SWAP( lock, value, previous );
-     RTEMS_COMPILER_MEMORY_BARRIER();
-   } while (previous == 1);
-
-  return level;
-}
-
-void _SMP_lock_spinlock_simple_Release(
-  SMP_lock_spinlock_simple_Control *lock,
-  ISR_Level                        level
-)
-{
-   *lock = 0;
-   _ISR_Enable_on_this_core( level );
-}
-
-void _SMP_lock_spinlock_nested_Initialize(
-  SMP_lock_spinlock_nested_Control *lock
-)
-{
-  lock->lock = 0;
-  lock->count = 0;
-  lock->cpu_id = -1;
-}
-
-void _SMP_lock_spinlock_nested_Release(
-  SMP_lock_spinlock_nested_Control *lock,
-  ISR_Level                        level
-)
-{
-  #if defined (RTEMS_DEBUG) || defined(SMPLOCK_DEBUG)
-    if ( lock->count == 0 ) {
-      printk(
-        "\ncpu %d lock %d Releasing spinlock when count is already "
-        "zero (%p from %p,%p)?!?!\n",
-        bsp_smp_processor_id(),  
-        lock->cpu_id,
-        lock,
-        __builtin_return_address(0),
-        __builtin_return_address(1)
-      );
-      debug_dump_log();
-      return;
-    }
-  #endif
-
-  /* assume we actually have it */
-  if (lock->count == 1) {
-    lock->cpu_id = -1;
-    debug_logit( 'U', lock );
-    lock->count  = 0;
-    RTEMS_COMPILER_MEMORY_BARRIER();
-    lock->lock = 0;
-  } else {
-    debug_logit( 'u', lock );
-    lock->count--;
-  }
-
-  _ISR_Enable_on_this_core( level ); 
-}
-
-ISR_Level _SMP_lock_spinlock_nested_Obtain(
-  SMP_lock_spinlock_nested_Control *lock
-)
-{
-  ISR_Level  level = 0;
-  uint32_t   value = 1;
-  uint32_t   previous;
-  int        cpu_id;
-
-  /* Note: Disable provides an implicit memory barrier. */
-  _ISR_Disable_on_this_core( level ); 
-
-  cpu_id = bsp_smp_processor_id();
-
-  /*
-   *  Attempt to obtain the lock.  If we do not get it immediately, then
-   *  do a single "monitor" iteration.  This should allow the loop to back
-   *  off the bus a bit and allow the other core to finish sooner.
-   */
-  while (1) {
-    RTEMS_COMPILER_MEMORY_BARRIER();
-    SMP_CPU_SWAP( &lock->lock, value, previous );
-    RTEMS_COMPILER_MEMORY_BARRIER();
-    if ( previous == 0 ) {
-      /* was not locked */
-      break;
-    }
-
-    /* Deal with nested calls from one cpu */
-    if (cpu_id == lock->cpu_id) {
-      lock->count++;
-      debug_logit( 'l', lock );
-      return level;
-    }
-  }
-
-  lock->cpu_id = cpu_id;
-  lock->count = 1;
-  debug_logit( 'L', lock );
-
-  return level;
-}
-
-/*
- * Debug log for debugging nested lock/unlock problems.
- */
-#if defined(ENABLE_DEBUG_LOGGING)
-  static void debug_logit(
-    char                             act,
-    SMP_lock_spinlock_nested_Control *lock
-  )
-  { 
-    debug_debug_spinlog_t *sp;
-    if ( DEBUG_SPINLOG_INDEX == DEBUG_SPINLOG_MAX )
-      #if defined (ENABLE_LOOPED_DEBUG_LOGGING)
-        DEBUG_SPINLOG_INDEX = 0;
-      #else
-        return;
-      #endif
-
-    sp = &DEBUG_SPINLOG[ DEBUG_SPINLOG_INDEX++ ];
-    sp->action = act;
-
-    #if 0
-      if ( lock == &_ISR_SMP_Lock )
-        sp->lock = 'I';
-      else 
-    #endif
-    if ( lock == &_Thread_Dispatch_disable_level_lock )
-      sp->lock   = 'D';
-    sp->cpu    = bsp_smp_processor_id() + '0';
-    sp->count  = lock->count;
-    #if 0
-      if ( sp->lock == 'I' ) {
-        if ( _Thread_Dispatch_smp_spin_lock.id == 0 )
-          printk( "not nested %p from %p %p %p %p\n", sp,
-          __builtin_return_address(0), __builtin_return_address(1),
-          __builtin_return_address(2), __builtin_return_address(3) 
-        );
-      }
-    #endif
-    sp->nest_level =  _ISR_Nest_level; 
-    sp->ret1 = 0;
-    sp->ret2 = 0;
-    sp->ret3 = 0;
-    sp->ret4 = 0;
-    sp->ret1 = __builtin_return_address(0);
-    if ( sp->ret1 >= start && sp->ret1 <= _fini ) {
-      sp->ret2   = __builtin_return_address(1);
-      if ( sp->ret2 >= start && sp->ret2 <= _fini ) {
-        sp->ret3   = __builtin_return_address(2);
-        if ( sp->ret3 >= start && sp->ret3 <= _fini ) {
-          sp->ret4   = __builtin_return_address(3);
-        }
-      }
-    }
-  }
-  
-  static void debug_dump_log(void)
-  { 
-    debug_debug_spinlog_t *sp;
-    int       index;
-    bool      done =false;
-    
-    #if defined (ENABLE_ONESHOT_DEBUG_LOGGING)
-      index = 0;
-    #else
-      if (DEBUG_SPINLOG_INDEX >= DEBUG_SPINLOG_MAX)
-        index = 0;
-      else
-        index = DEBUG_SPINLOG_INDEX;
-    #endif
-
-
-    do {
-      sp = &DEBUG_SPINLOG[ index ];
-      printk("%d) act %c lock %c cpu %c count=%d nest %d (%p, %p, %p, %p)\n",
-        index, sp->action, sp->lock, sp->cpu, sp->count, sp->nest_level, 
-        sp->ret1, sp->ret2, sp->ret3, sp->ret4
-      );
-
-      index++;
-      if (index == DEBUG_SPINLOG_INDEX)
-        break;
-      if (index >= DEBUG_SPINLOG_MAX)
-        index = 0;
-    } while (1);
-  }
-#endif
diff --git a/cpukit/score/src/threaddispatchdisablelevel.c b/cpukit/score/src/threaddispatchdisablelevel.c
index 36be088..b193090 100644
--- a/cpukit/score/src/threaddispatchdisablelevel.c
+++ b/cpukit/score/src/threaddispatchdisablelevel.c
@@ -26,10 +26,16 @@
 #include <rtems/score/sysstate.h>
 #include <rtems/score/thread.h>
 
+#define NO_OWNER_CPU (-1)
+
 void _Thread_Dispatch_initialization( void )
 {
-  _Thread_Dispatch_disable_level = 0; 
-  _SMP_lock_spinlock_nested_Initialize(&_Thread_Dispatch_disable_level_lock);
+  Thread_Dispatch_disable_level_lock_control *level_lock =
+    &_Thread_Dispatch_disable_level_lock;
+
+  _Thread_Dispatch_disable_level = 0;
+  _SMP_lock_Initialize( &level_lock->lock );
+  level_lock->owner_cpu = NO_OWNER_CPU;
   _Thread_Dispatch_set_disable_level( 1 );
 }
 
@@ -46,59 +52,55 @@ uint32_t _Thread_Dispatch_get_disable_level(void)
   return _Thread_Dispatch_disable_level;
 }
 
-uint32_t _Thread_Dispatch_increment_disable_level(void)
+uint32_t _Thread_Dispatch_increment_disable_level( void )
 {
-  ISR_Level  isr_level;
-  uint32_t   level;
+  Thread_Dispatch_disable_level_lock_control *level_lock =
+    &_Thread_Dispatch_disable_level_lock;
+  int self_cpu = bsp_smp_processor_id();
+  ISR_Level isr_level;
+  uint32_t disable_level;
 
-  /*
-   * Note: _SMP_lock_spinlock_nested_Obtain returns
-   *       with ISR's disabled and the isr_level that
-   *       should be restored after a short period.
-   *
-   * Here we obtain the lock and increment the 
-   * Thread dispatch disable level while under the
-   * protection of the isr being off.  After this
-   * point it is safe to re-enable ISRs and allow
-   * the dispatch disable lock to provide protection.
-   */
+  _ISR_Disable_on_this_core( isr_level );
 
-  isr_level = _SMP_lock_spinlock_nested_Obtain(
-    &_Thread_Dispatch_disable_level_lock
-  );
-  
-  _Thread_Dispatch_disable_level++;
-  level = _Thread_Dispatch_disable_level;
+  if ( level_lock->owner_cpu != self_cpu ) {
+    _SMP_lock_Acquire( &level_lock->lock );
+    level_lock->owner_cpu = self_cpu;
+    level_lock->nest_level = 1;
+  } else {
+    ++level_lock->nest_level;
+  }
 
-  _ISR_Enable_on_this_core(isr_level);
-  return level;
+  disable_level = _Thread_Dispatch_disable_level;
+  ++disable_level;
+  _Thread_Dispatch_disable_level = disable_level;
+
+  _ISR_Enable_on_this_core( isr_level );
+
+  return disable_level;
 }
 
-uint32_t _Thread_Dispatch_decrement_disable_level(void)
+uint32_t _Thread_Dispatch_decrement_disable_level( void )
 {
-  ISR_Level  isr_level;
-  uint32_t   level;
+  Thread_Dispatch_disable_level_lock_control *level_lock =
+    &_Thread_Dispatch_disable_level_lock;
+  ISR_Level isr_level;
+  uint32_t disable_level;
 
-  /*  First we must disable ISRs in order to protect
-   *  accesses to the dispatch disable level.
-   */
   _ISR_Disable_on_this_core( isr_level );
 
-  _Thread_Dispatch_disable_level--;
-  level = _Thread_Dispatch_disable_level;
+  --level_lock->nest_level;
+  if ( level_lock->nest_level == 0 ) {
+    level_lock->owner_cpu = NO_OWNER_CPU;
+    _SMP_lock_Release( &level_lock->lock );
+  }
 
+  disable_level = _Thread_Dispatch_disable_level;
+  --disable_level;
+  _Thread_Dispatch_disable_level = disable_level;
 
-  /* 
-   * Note: _SMP_lock_spinlock_nested_Obtain returns with
-   *        ISR's disabled and _SMP_lock_spinlock_nested_Release
-   *        is responsable for re-enabling interrupts.
-   */
-  _SMP_lock_spinlock_nested_Release( 
-    &_Thread_Dispatch_disable_level_lock,
-    isr_level
-  ); 
+  _ISR_Enable_on_this_core( isr_level );
 
-  return level;
+  return disable_level;
 }
 
 
-- 
1.7.7




More information about the devel mailing list