summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cpukit/score/Makefile.am2
-rw-r--r--cpukit/score/cpu/i386/Makefile.am1
-rw-r--r--cpukit/score/cpu/i386/preinstall.am4
-rw-r--r--cpukit/score/cpu/i386/rtems/score/cpu.h9
-rw-r--r--cpukit/score/cpu/i386/rtems/score/cpusmplock.h100
-rw-r--r--cpukit/score/cpu/no_cpu/Makefile.am1
-rw-r--r--cpukit/score/cpu/no_cpu/preinstall.am4
-rw-r--r--cpukit/score/cpu/no_cpu/rtems/score/cpusmplock.h114
-rw-r--r--cpukit/score/cpu/sparc/Makefile.am1
-rw-r--r--cpukit/score/cpu/sparc/preinstall.am4
-rw-r--r--cpukit/score/cpu/sparc/rtems/score/cpu.h18
-rw-r--r--cpukit/score/cpu/sparc/rtems/score/cpusmplock.h105
-rw-r--r--cpukit/score/include/rtems/score/percpu.h2
-rw-r--r--cpukit/score/include/rtems/score/smplock.h174
-rw-r--r--cpukit/score/include/rtems/score/thread.h9
-rw-r--r--cpukit/score/src/smp.c14
-rw-r--r--cpukit/score/src/smplock.c285
-rw-r--r--cpukit/score/src/threaddispatchdisablelevel.c86
18 files changed, 470 insertions, 463 deletions
diff --git a/cpukit/score/Makefile.am b/cpukit/score/Makefile.am
index 604ab34669..d4c79ac4f2 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 d25002d390..e35a81c333 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 060176be04..f9faf87157 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 c262e3cf45..3f7a331c3f 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 0000000000..6fadfef419
--- /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 Swap.
+ *
+ * @{
+ */
+
+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 820579cd42..24517431e7 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 a56caeafd8..a46f8b0bfd 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 0000000000..387bbb47c1
--- /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 4bb09c6b56..3065f3ce18 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 a2bb01bfd2..e497b48f7f 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 9654c294f5..defc01a779 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 0000000000..1158040dc5
--- /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 Swap.
+ *
+ * @{
+ */
+
+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 f545310e1c..3b97a68488 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 6db8a43418..b3ef0e2cb0 100644
--- a/cpukit/score/include/rtems/score/smplock.h
+++ b/cpukit/score/include/rtems/score/smplock.h
@@ -1,149 +1,123 @@
/**
- * @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. A ticket lock
+ * is probably the most likely implementation.
+ *
+ * This SMP lock API has a flaw. It does not provide the ability to use a
+ * local context for acquire 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 248be62c95..9461c85be1 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 69f5337b75..6f1bc55cc8 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 89f8a866dd..0000000000
--- 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 36be088663..b1930909bb 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;
}