Use an ISR lock to protect the spinlock state. Remove empty attributes. Update #2555. --- cpukit/posix/include/rtems/posix/spinlockimpl.h | 27 ++++------ cpukit/posix/src/pspindestroy.c | 63 +++++++--------------- cpukit/posix/src/pspininit.c | 5 +- cpukit/posix/src/pspinlock.c | 50 ++++++----------- cpukit/posix/src/pspintrylock.c | 52 +++++------------- cpukit/posix/src/pspinunlock.c | 47 ++++------------ cpukit/score/Makefile.am | 2 +- cpukit/score/include/rtems/score/corespinlock.h | 30 +++++------ .../score/include/rtems/score/corespinlockimpl.h | 55 +++++++++++-------- cpukit/score/src/corespinlock.c | 37 ------------- cpukit/score/src/corespinlockrelease.c | 19 +++---- cpukit/score/src/corespinlockwait.c | 63 +++++++++------------- 12 files changed, 149 insertions(+), 301 deletions(-) delete mode 100644 cpukit/score/src/corespinlock.c
diff --git a/cpukit/posix/include/rtems/posix/spinlockimpl.h b/cpukit/posix/include/rtems/posix/spinlockimpl.h index 01fe372..0904050 100644 --- a/cpukit/posix/include/rtems/posix/spinlockimpl.h +++ b/cpukit/posix/include/rtems/posix/spinlockimpl.h @@ -75,26 +75,19 @@ RTEMS_INLINE_ROUTINE void _POSIX_Spinlock_Free ( _Objects_Free( &_POSIX_Spinlock_Information, &the_spinlock->Object ); } -/** - * @brief Get a spinlock control block. - * - * This function maps spinlock IDs to spinlock control blocks. - * If ID corresponds to a local spinlock, then it returns - * the_spinlock control pointer which maps to ID and location - * is set to OBJECTS_LOCAL. if the spinlock ID is global and - * resides on a remote node, then location is set to OBJECTS_REMOTE, - * and the_spinlock is undefined. Otherwise, location is set - * to OBJECTS_ERROR and the_spinlock is undefined. - */ -RTEMS_INLINE_ROUTINE POSIX_Spinlock_Control *_POSIX_Spinlock_Get ( +RTEMS_INLINE_ROUTINE POSIX_Spinlock_Control *_POSIX_Spinlock_Get( pthread_spinlock_t *spinlock, - Objects_Locations *location + ISR_lock_Context *lock_context ) { - return (POSIX_Spinlock_Control *) _Objects_Get( - &_POSIX_Spinlock_Information, - (Objects_Id) *spinlock, - location + if ( spinlock == NULL ) { + return NULL; + } + + return (POSIX_Spinlock_Control *) _Objects_Get_local( + &_POSIX_Spinlock_Information, + *spinlock, + lock_context ); } diff --git a/cpukit/posix/src/pspindestroy.c b/cpukit/posix/src/pspindestroy.c index ab45ad1..42a6e76 100644 --- a/cpukit/posix/src/pspindestroy.c +++ b/cpukit/posix/src/pspindestroy.c @@ -18,58 +18,35 @@ #include "config.h" #endif -#include <pthread.h> -#include <errno.h> - -#include <rtems/system.h> #include <rtems/posix/spinlockimpl.h> -/** - * This directive allows a thread to delete a spinlock specified by - * the spinlock id. The spinlock is freed back to the inactive - * spinlock chain. - * - * @param[in] spinlock is the spinlock id - * - * @return This method returns 0 if there was not an - * error. Otherwise, a status code is returned indicating the - * source of the error. - */ -int pthread_spin_destroy( - pthread_spinlock_t *spinlock -) -{ - POSIX_Spinlock_Control *the_spinlock = NULL; - Objects_Locations location; +#include <errno.h> - if ( !spinlock ) - return EINVAL; +int pthread_spin_destroy( pthread_spinlock_t *spinlock ) +{ + POSIX_Spinlock_Control *the_spinlock; + ISR_lock_Context lock_context; _Objects_Allocator_lock(); - the_spinlock = _POSIX_Spinlock_Get( spinlock, &location ); - switch ( location ) { - case OBJECTS_LOCAL: - if ( _CORE_spinlock_Is_busy( &the_spinlock->Spinlock ) ) { - _Objects_Put( &the_spinlock->Object ); - return EBUSY; - } - - _Objects_Close( &_POSIX_Spinlock_Information, &the_spinlock->Object ); - _Objects_Put( &the_spinlock->Object ); - _POSIX_Spinlock_Free( the_spinlock ); - _Objects_Allocator_unlock(); + the_spinlock = _POSIX_Spinlock_Get( spinlock, &lock_context ); + if ( the_spinlock == NULL ) { + _Objects_Allocator_unlock(); + return EINVAL; + } - return 0; + _CORE_spinlock_Acquire_critical( &the_spinlock->Spinlock, &lock_context ); -#if defined(RTEMS_MULTIPROCESSING) - case OBJECTS_REMOTE: -#endif - case OBJECTS_ERROR: - break; + if ( _CORE_spinlock_Is_busy( &the_spinlock->Spinlock ) ) { + _CORE_spinlock_Release( &the_spinlock->Spinlock, &lock_context ); + _Objects_Allocator_unlock(); + return EBUSY; } - _Objects_Allocator_unlock(); + _CORE_spinlock_Release( &the_spinlock->Spinlock, &lock_context ); - return EINVAL; + _Objects_Close( &_POSIX_Spinlock_Information, &the_spinlock->Object ); + _POSIX_Spinlock_Free( the_spinlock ); + _Objects_Allocator_unlock(); + return 0; } diff --git a/cpukit/posix/src/pspininit.c b/cpukit/posix/src/pspininit.c index 02b07c8..bc131e2 100644 --- a/cpukit/posix/src/pspininit.c +++ b/cpukit/posix/src/pspininit.c @@ -47,7 +47,6 @@ int pthread_spin_init( ) { POSIX_Spinlock_Control *the_spinlock; - CORE_spinlock_Attributes attributes; if ( !spinlock ) return EINVAL; @@ -67,9 +66,7 @@ int pthread_spin_init( return EAGAIN; } - _CORE_spinlock_Initialize_attributes( &attributes ); - - _CORE_spinlock_Initialize( &the_spinlock->Spinlock, &attributes ); + _CORE_spinlock_Initialize( &the_spinlock->Spinlock ); _Objects_Open_u32( &_POSIX_Spinlock_Information, &the_spinlock->Object, 0 ); diff --git a/cpukit/posix/src/pspinlock.c b/cpukit/posix/src/pspinlock.c index d13ffe6..502177c 100644 --- a/cpukit/posix/src/pspinlock.c +++ b/cpukit/posix/src/pspinlock.c @@ -18,46 +18,26 @@ #include "config.h" #endif -#include <pthread.h> -#include <errno.h> - -#include <rtems/system.h> #include <rtems/posix/spinlockimpl.h> -/** - * This directive allows a thread to wait at a spinlock. - * - * @param[in] spinlock is spinlock id - * - * @return This method returns 0 if there was not an - * error. Otherwise, a status code is returned indicating the - * source of the error. - */ -int pthread_spin_lock( - pthread_spinlock_t *spinlock -) +#include <errno.h> + +int pthread_spin_lock( pthread_spinlock_t *spinlock ) { - POSIX_Spinlock_Control *the_spinlock = NULL; - Objects_Locations location; - CORE_spinlock_Status status; + POSIX_Spinlock_Control *the_spinlock; + ISR_lock_Context lock_context; + CORE_spinlock_Status status; - if ( !spinlock ) + the_spinlock = _POSIX_Spinlock_Get( spinlock, &lock_context ); + if ( the_spinlock == NULL ) { return EINVAL; - - the_spinlock = _POSIX_Spinlock_Get( spinlock, &location ); - switch ( location ) { - - case OBJECTS_LOCAL: - status = _CORE_spinlock_Wait( &the_spinlock->Spinlock, true, 0 ); - _Objects_Put( &the_spinlock->Object ); - return _POSIX_Spinlock_Translate_core_spinlock_return_code( status ); - -#if defined(RTEMS_MULTIPROCESSING) - case OBJECTS_REMOTE: -#endif - case OBJECTS_ERROR: - break; } - return EINVAL; + status = _CORE_spinlock_Seize( + &the_spinlock->Spinlock, + true, + 0, + &lock_context + ); + return _POSIX_Spinlock_Translate_core_spinlock_return_code( status ); } diff --git a/cpukit/posix/src/pspintrylock.c b/cpukit/posix/src/pspintrylock.c index d304908..5f132a3 100644 --- a/cpukit/posix/src/pspintrylock.c +++ b/cpukit/posix/src/pspintrylock.c @@ -18,50 +18,26 @@ #include "config.h" #endif -#include <pthread.h> -#include <errno.h> - -#include <rtems/system.h> #include <rtems/posix/spinlockimpl.h> -/* - * pthread_spin_trylock - * - * This directive allows a thread to poll an attempt at locking a spinlock. - * - * Input parameters: - * spinlock - spinlock id - * - * Output parameters: - * 0 - if successful - * error code - if unsuccessful - */ +#include <errno.h> -int pthread_spin_trylock( - pthread_spinlock_t *spinlock -) +int pthread_spin_trylock( pthread_spinlock_t *spinlock ) { - POSIX_Spinlock_Control *the_spinlock = NULL; - Objects_Locations location; - CORE_spinlock_Status status; + POSIX_Spinlock_Control *the_spinlock; + ISR_lock_Context lock_context; + CORE_spinlock_Status status; - if ( !spinlock ) + the_spinlock = _POSIX_Spinlock_Get( spinlock, &lock_context ); + if ( the_spinlock == NULL ) { return EINVAL; - - the_spinlock = _POSIX_Spinlock_Get( spinlock, &location ); - switch ( location ) { - - case OBJECTS_LOCAL: - status = _CORE_spinlock_Wait( &the_spinlock->Spinlock, false, 0 ); - _Objects_Put( &the_spinlock->Object ); - return _POSIX_Spinlock_Translate_core_spinlock_return_code( status ); - -#if defined(RTEMS_MULTIPROCESSING) - case OBJECTS_REMOTE: -#endif - case OBJECTS_ERROR: - break; } - return EINVAL; + status = _CORE_spinlock_Seize( + &the_spinlock->Spinlock, + false, + 0, + &lock_context + ); + return _POSIX_Spinlock_Translate_core_spinlock_return_code( status ); } diff --git a/cpukit/posix/src/pspinunlock.c b/cpukit/posix/src/pspinunlock.c index 3a483ad..35dbcb9 100644 --- a/cpukit/posix/src/pspinunlock.c +++ b/cpukit/posix/src/pspinunlock.c @@ -20,50 +20,21 @@ #include "config.h" #endif -#include <pthread.h> -#include <errno.h> - -#include <rtems/system.h> #include <rtems/posix/spinlockimpl.h> -/* - * pthread_spin_unlock - * - * This directive allows a thread to wait at a spinlock. - * - * Input parameters: - * spinlock - spinlock id - * - * Output parameters: - * 0 - if successful - * error code - if unsuccessful - */ +#include <errno.h> -int pthread_spin_unlock( - pthread_spinlock_t *spinlock -) +int pthread_spin_unlock( pthread_spinlock_t *spinlock ) { - POSIX_Spinlock_Control *the_spinlock = NULL; - Objects_Locations location; - CORE_spinlock_Status status; + POSIX_Spinlock_Control *the_spinlock; + ISR_lock_Context lock_context; + CORE_spinlock_Status status; - if ( !spinlock ) + the_spinlock = _POSIX_Spinlock_Get( spinlock, &lock_context ); + if ( the_spinlock == NULL ) { return EINVAL; - - the_spinlock = _POSIX_Spinlock_Get( spinlock, &location ); - switch ( location ) { - - case OBJECTS_LOCAL: - status = _CORE_spinlock_Release( &the_spinlock->Spinlock ); - _Objects_Put( &the_spinlock->Object ); - return _POSIX_Spinlock_Translate_core_spinlock_return_code( status ); - -#if defined(RTEMS_MULTIPROCESSING) - case OBJECTS_REMOTE: -#endif - case OBJECTS_ERROR: - break; } - return EINVAL; + status = _CORE_spinlock_Surrender( &the_spinlock->Spinlock, &lock_context ); + return _POSIX_Spinlock_Translate_core_spinlock_return_code( status ); } diff --git a/cpukit/score/Makefile.am b/cpukit/score/Makefile.am index b6824ad..6ff4e02 100644 --- a/cpukit/score/Makefile.am +++ b/cpukit/score/Makefile.am @@ -194,7 +194,7 @@ libscore_a_SOURCES += src/coresem.c ## CORE_SPINLOCK_C_FILES if HAS_PTHREADS -libscore_a_SOURCES += src/corespinlock.c src/corespinlockrelease.c \ +libscore_a_SOURCES += src/corespinlockrelease.c \ src/corespinlockwait.c endif diff --git a/cpukit/score/include/rtems/score/corespinlock.h b/cpukit/score/include/rtems/score/corespinlock.h index ca50eed..1666538 100644 --- a/cpukit/score/include/rtems/score/corespinlock.h +++ b/cpukit/score/include/rtems/score/corespinlock.h @@ -19,7 +19,8 @@ #ifndef _RTEMS_SCORE_CORESPINLOCK_H #define _RTEMS_SCORE_CORESPINLOCK_H -#include <rtems/score/object.h> +#include <rtems/score/isrlock.h> +#include <rtems/score/thread.h> #ifdef __cplusplus extern "C" { @@ -36,37 +37,34 @@ extern "C" { /**@{*/ /** - * The following defines the control block used to manage the - * attributes of each spinlock. - */ -typedef struct { - /** This element indicates XXX - */ - uint32_t XXX; -} CORE_spinlock_Attributes; - -/** * The following defines the control block used to manage each * spinlock. */ typedef struct { - /** XXX may not be needed */ - CORE_spinlock_Attributes Attributes; + /** + * @brief Lock to protect the other fields. + * + * This implementation is a bit stupid. However, test cases in the Linux + * Test Project do things like sleep() and printf() while owning a + * pthread_spinlock_t, e.g. + * testcases/open_posix_testsuite/conformance/interfaces/pthread_spin_lock/1-2.c + */ + ISR_LOCK_MEMBER( Lock ) /** This field is the lock. */ - volatile uint32_t lock; + uint32_t lock; /** This field is a count of the current number of threads using * this spinlock. It includes the thread holding the lock as well * as those waiting. */ - volatile uint32_t users; + uint32_t users; /** This field is the Id of the thread holding the lock. It may or may * not be the thread which acquired it. */ - volatile Objects_Id holder; + Thread_Control *holder; } CORE_spinlock_Control; /**@}*/ diff --git a/cpukit/score/include/rtems/score/corespinlockimpl.h b/cpukit/score/include/rtems/score/corespinlockimpl.h index fe6f9b6..189bddb 100644 --- a/cpukit/score/include/rtems/score/corespinlockimpl.h +++ b/cpukit/score/include/rtems/score/corespinlockimpl.h @@ -22,6 +22,8 @@ #include <rtems/score/corespinlock.h> #include <rtems/score/watchdog.h> +#include <string.h> + #ifdef __cplusplus extern "C" { #endif @@ -78,12 +80,29 @@ typedef enum { * This routine initializes the spinlock based on the parameters passed. * * @param[in] the_spinlock is the spinlock control block to initialize - * @param[in] the_spinlock_attributes define the behavior of this instance */ -void _CORE_spinlock_Initialize( - CORE_spinlock_Control *the_spinlock, - CORE_spinlock_Attributes *the_spinlock_attributes -); +RTEMS_INLINE_ROUTINE void _CORE_spinlock_Initialize( + CORE_spinlock_Control *the_spinlock +) +{ + memset( the_spinlock, 0, sizeof( *the_spinlock ) ); +} + +RTEMS_INLINE_ROUTINE void _CORE_spinlock_Acquire_critical( + CORE_spinlock_Control *the_spinlock, + ISR_lock_Context *lock_context +) +{ + _ISR_lock_Acquire( &the_spinlock->Lock, lock_context ); +} + +RTEMS_INLINE_ROUTINE void _CORE_spinlock_Release( + CORE_spinlock_Control *the_spinlock, + ISR_lock_Context *lock_context +) +{ + _ISR_lock_Release_and_ISR_enable( &the_spinlock->Lock, lock_context ); +} /** * @brief Wait for spinlock. @@ -100,10 +119,11 @@ void _CORE_spinlock_Initialize( * @retval A status is returned which indicates the success or failure of * this operation. */ -CORE_spinlock_Status _CORE_spinlock_Wait( - CORE_spinlock_Control *the_spinlock, - bool wait, - Watchdog_Interval timeout +CORE_spinlock_Status _CORE_spinlock_Seize( + CORE_spinlock_Control *the_spinlock, + bool wait, + Watchdog_Interval timeout, + ISR_lock_Context *lock_context ); /** @@ -114,23 +134,12 @@ CORE_spinlock_Status _CORE_spinlock_Wait( * * @param[in] the_spinlock is the spinlock to surrender */ -CORE_spinlock_Status _CORE_spinlock_Release( - CORE_spinlock_Control *the_spinlock +CORE_spinlock_Status _CORE_spinlock_Surrender( + CORE_spinlock_Control *the_spinlock, + ISR_lock_Context *lock_context ); /** - * This method is used to initialize core spinlock attributes. - * - * @param[in] the_attributes pointer to the attributes to initialize. - */ -RTEMS_INLINE_ROUTINE void _CORE_spinlock_Initialize_attributes( - CORE_spinlock_Attributes *the_attributes -) -{ - the_attributes->XXX = 0; -} - -/** * This method is used to determine if the spinlock is available or not. * * @param[in] the_spinlock will be checked diff --git a/cpukit/score/src/corespinlock.c b/cpukit/score/src/corespinlock.c deleted file mode 100644 index b84eb2e..0000000 --- a/cpukit/score/src/corespinlock.c +++ /dev/null @@ -1,37 +0,0 @@ -/** - * @file - * - * @brief Initialize a Spinlock - * - * @ingroup ScoreSpinlock - */ - -/* - * COPYRIGHT (c) 1989-2006. - * 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.org/license/LICENSE. - */ - -#if HAVE_CONFIG_H -#include "config.h" -#endif - -#include <rtems/system.h> -#include <rtems/score/corespinlockimpl.h> -#include <rtems/score/thread.h> - -void _CORE_spinlock_Initialize( - CORE_spinlock_Control *the_spinlock, - CORE_spinlock_Attributes *the_spinlock_attributes -) -{ - - the_spinlock->Attributes = *the_spinlock_attributes; - - the_spinlock->lock = 0; - the_spinlock->users = 0; - the_spinlock->holder = 0; -} diff --git a/cpukit/score/src/corespinlockrelease.c b/cpukit/score/src/corespinlockrelease.c index c10337a..358d352 100644 --- a/cpukit/score/src/corespinlockrelease.c +++ b/cpukit/score/src/corespinlockrelease.c @@ -20,30 +20,27 @@ #include <rtems/score/corespinlockimpl.h> #include <rtems/score/percpu.h> -#include <rtems/score/thread.h> -#include <rtems/score/watchdog.h> -CORE_spinlock_Status _CORE_spinlock_Release( - CORE_spinlock_Control *the_spinlock +CORE_spinlock_Status _CORE_spinlock_Surrender( + CORE_spinlock_Control *the_spinlock, + ISR_lock_Context *lock_context ) { - ISR_Level level; - - _ISR_Disable( level ); + _CORE_spinlock_Acquire_critical( the_spinlock, lock_context ); /* * It must locked before it can be unlocked. */ if ( the_spinlock->lock == CORE_SPINLOCK_UNLOCKED ) { - _ISR_Enable( level ); + _CORE_spinlock_Release( the_spinlock, lock_context ); return CORE_SPINLOCK_NOT_LOCKED; } /* * It must locked by the current thread before it can be unlocked. */ - if ( the_spinlock->holder != _Thread_Executing->Object.id ) { - _ISR_Enable( level ); + if ( the_spinlock->holder != _Thread_Executing ) { + _CORE_spinlock_Release( the_spinlock, lock_context ); return CORE_SPINLOCK_NOT_HOLDER; } @@ -54,6 +51,6 @@ CORE_spinlock_Status _CORE_spinlock_Release( the_spinlock->lock = CORE_SPINLOCK_UNLOCKED; the_spinlock->holder = 0; - _ISR_Enable( level ); + _CORE_spinlock_Release( the_spinlock, lock_context ); return CORE_SPINLOCK_SUCCESSFUL; } diff --git a/cpukit/score/src/corespinlockwait.c b/cpukit/score/src/corespinlockwait.c index 1f10296..cc939c2 100644 --- a/cpukit/score/src/corespinlockwait.c +++ b/cpukit/score/src/corespinlockwait.c @@ -18,48 +18,36 @@ #include "config.h" #endif -#include <rtems/system.h> #include <rtems/score/corespinlockimpl.h> -#include <rtems/score/thread.h> -#include <rtems/score/threaddispatch.h> +#include <rtems/score/percpu.h> -/* - * _CORE_spinlock_Wait - * - * This function waits for the spinlock to become available. Optionally, - * a limit may be placed on the duration of the spin. - * - * Input parameters: - * the_spinlock - the spinlock control block to initialize - * wait - true if willing to wait - * timeout - the maximum number of ticks to spin (0 is forever) - * - * Output parameters: NONE - */ - -CORE_spinlock_Status _CORE_spinlock_Wait( - CORE_spinlock_Control *the_spinlock, - bool wait, - Watchdog_Interval timeout +CORE_spinlock_Status _CORE_spinlock_Seize( + CORE_spinlock_Control *the_spinlock, + bool wait, + Watchdog_Interval timeout, + ISR_lock_Context *lock_context ) { - ISR_Level level; + Thread_Control *executing; + #if defined(FUNCTIONALITY_NOT_CURRENTLY_USED_BY_ANY_API) Watchdog_Interval limit = _Watchdog_Ticks_since_boot + timeout; #endif - _ISR_Disable( level ); - if ( (the_spinlock->lock == CORE_SPINLOCK_LOCKED) && - (the_spinlock->holder == _Thread_Executing->Object.id) ) { - _ISR_Enable( level ); + executing = _Thread_Executing; + + _CORE_spinlock_Acquire_critical( the_spinlock, lock_context ); + if ( the_spinlock->lock == CORE_SPINLOCK_LOCKED && + the_spinlock->holder == executing ) { + _CORE_spinlock_Release( the_spinlock, lock_context ); return CORE_SPINLOCK_HOLDER_RELOCKING; } the_spinlock->users += 1; for ( ;; ) { if ( the_spinlock->lock == CORE_SPINLOCK_UNLOCKED ) { the_spinlock->lock = CORE_SPINLOCK_LOCKED; - the_spinlock->holder = _Thread_Executing->Object.id; - _ISR_Enable( level ); + the_spinlock->holder = executing; + _CORE_spinlock_Release( the_spinlock, lock_context ); return CORE_SPINLOCK_SUCCESSFUL; } @@ -68,7 +56,7 @@ CORE_spinlock_Status _CORE_spinlock_Wait( */ if ( !wait ) { the_spinlock->users -= 1; - _ISR_Enable( level ); + _CORE_spinlock_Release( the_spinlock, lock_context ); return CORE_SPINLOCK_UNAVAILABLE; } @@ -78,7 +66,7 @@ CORE_spinlock_Status _CORE_spinlock_Wait( */ if ( timeout && (limit <= _Watchdog_Ticks_since_boot) ) { the_spinlock->users -= 1; - _ISR_Enable( level ); + _CORE_spinlock_Release( the_spinlock, lock_context ); return CORE_SPINLOCK_TIMEOUT; } #endif @@ -100,16 +88,15 @@ CORE_spinlock_Status _CORE_spinlock_Wait( * safe from deletion. */ - _ISR_Enable( level ); - /* An ISR could occur here */ - - _Thread_Enable_dispatch(); - /* Another thread could get dispatched here */ + _CORE_spinlock_Release( the_spinlock, lock_context ); - /* Reenter the critical sections so we can attempt the lock again. */ - _Thread_Disable_dispatch(); + /* + * An ISR could occur here. Another thread could get dispatched here. + * Reenter the critical sections so we can attempt the lock again. + */ - _ISR_Disable( level ); + _ISR_lock_ISR_disable( lock_context ); + _CORE_spinlock_Acquire_critical( the_spinlock, lock_context ); } } -- 1.8.4.5 _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel