diff options
-rw-r--r-- | cpukit/score/Makefile.am | 2 | ||||
-rw-r--r-- | cpukit/score/cpu/i386/Makefile.am | 1 | ||||
-rw-r--r-- | cpukit/score/cpu/i386/preinstall.am | 4 | ||||
-rw-r--r-- | cpukit/score/cpu/i386/rtems/score/cpu.h | 9 | ||||
-rw-r--r-- | cpukit/score/cpu/i386/rtems/score/cpusmplock.h | 100 | ||||
-rw-r--r-- | cpukit/score/cpu/no_cpu/Makefile.am | 1 | ||||
-rw-r--r-- | cpukit/score/cpu/no_cpu/preinstall.am | 4 | ||||
-rw-r--r-- | cpukit/score/cpu/no_cpu/rtems/score/cpusmplock.h | 114 | ||||
-rw-r--r-- | cpukit/score/cpu/sparc/Makefile.am | 1 | ||||
-rw-r--r-- | cpukit/score/cpu/sparc/preinstall.am | 4 | ||||
-rw-r--r-- | cpukit/score/cpu/sparc/rtems/score/cpu.h | 18 | ||||
-rw-r--r-- | cpukit/score/cpu/sparc/rtems/score/cpusmplock.h | 105 | ||||
-rw-r--r-- | cpukit/score/include/rtems/score/percpu.h | 2 | ||||
-rw-r--r-- | cpukit/score/include/rtems/score/smplock.h | 174 | ||||
-rw-r--r-- | cpukit/score/include/rtems/score/thread.h | 9 | ||||
-rw-r--r-- | cpukit/score/src/smp.c | 14 | ||||
-rw-r--r-- | cpukit/score/src/smplock.c | 285 | ||||
-rw-r--r-- | cpukit/score/src/threaddispatchdisablelevel.c | 86 |
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; } |