From 84a539885335c629100a6a12b57ead54bbbc0165 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Thu, 21 Apr 2016 06:32:16 +0200 Subject: score: Avoid Giant lock for CORE rwlock Update #2555. --- cpukit/posix/include/rtems/posix/rwlockimpl.h | 5 +- cpukit/posix/src/prwlockdestroy.c | 72 ++++------- cpukit/posix/src/prwlockinit.c | 22 ++-- cpukit/posix/src/prwlockrdlock.c | 56 +++------ cpukit/posix/src/prwlocktimedrdlock.c | 88 +++++-------- cpukit/posix/src/prwlocktimedwrlock.c | 87 +++++-------- cpukit/posix/src/prwlocktryrdlock.c | 61 +++------ cpukit/posix/src/prwlocktrywrlock.c | 60 +++------ cpukit/posix/src/prwlockunlock.c | 41 ++---- cpukit/posix/src/prwlockwrlock.c | 56 +++------ cpukit/score/include/rtems/score/corerwlockimpl.h | 24 +++- cpukit/score/src/corerwlockobtainread.c | 98 ++++++++------- cpukit/score/src/corerwlockobtainwrite.c | 78 ++++++------ cpukit/score/src/corerwlockrelease.c | 144 +++++++++++++--------- 14 files changed, 367 insertions(+), 525 deletions(-) diff --git a/cpukit/posix/include/rtems/posix/rwlockimpl.h b/cpukit/posix/include/rtems/posix/rwlockimpl.h index 8c94843160..6f3088ebd4 100644 --- a/cpukit/posix/include/rtems/posix/rwlockimpl.h +++ b/cpukit/posix/include/rtems/posix/rwlockimpl.h @@ -23,6 +23,7 @@ #include #include +#include #include #ifdef __cplusplus @@ -86,8 +87,8 @@ RTEMS_INLINE_ROUTINE void _POSIX_RWLock_Free ( } POSIX_RWLock_Control *_POSIX_RWLock_Get( - pthread_rwlock_t *rwlock, - Objects_Locations *location + pthread_rwlock_t *rwlock, + ISR_lock_Context *lock_context ); #ifdef __cplusplus diff --git a/cpukit/posix/src/prwlockdestroy.c b/cpukit/posix/src/prwlockdestroy.c index a675b90757..6f9eec8a1d 100644 --- a/cpukit/posix/src/prwlockdestroy.c +++ b/cpukit/posix/src/prwlockdestroy.c @@ -17,68 +17,42 @@ #include "config.h" #endif -#include -#include - #include -#include -/** - * This directive allows a thread to delete a rwlock specified by - * the rwlock id. The rwlock is freed back to the inactive - * rwlock chain. - * - * @param[in] rwlock is the rwlock 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_rwlock_destroy( pthread_rwlock_t *rwlock ) { - POSIX_RWLock_Control *the_rwlock = NULL; - Objects_Locations location; + POSIX_RWLock_Control *the_rwlock; + ISR_lock_Context lock_context; _Objects_Allocator_lock(); - the_rwlock = _POSIX_RWLock_Get( rwlock, &location ); - switch ( location ) { + the_rwlock = _POSIX_RWLock_Get( rwlock, &lock_context ); - case OBJECTS_LOCAL: - /* - * If there is at least one thread waiting, then do not delete it. - */ - if ( - _Thread_queue_First( - &the_rwlock->RWLock.Wait_queue, - CORE_RWLOCK_TQ_OPERATIONS - ) != NULL - ) { - _Objects_Put( &the_rwlock->Object ); - _Objects_Allocator_unlock(); - return EBUSY; - } - - /* - * POSIX doesn't require behavior when it is locked. - */ + if ( the_rwlock == NULL ) { + _Objects_Allocator_unlock(); + return EINVAL; + } - _Objects_Close( &_POSIX_RWLock_Information, &the_rwlock->Object ); - _Objects_Put( &the_rwlock->Object ); - _POSIX_RWLock_Free( the_rwlock ); - _Objects_Allocator_unlock(); + _CORE_RWLock_Acquire_critical( &the_rwlock->RWLock, &lock_context ); - return 0; + /* + * If there is at least one thread waiting, then do not delete it. + */ -#if defined(RTEMS_MULTIPROCESSING) - case OBJECTS_REMOTE: -#endif - case OBJECTS_ERROR: - break; + if ( !_Thread_queue_Is_empty( &the_rwlock->RWLock.Wait_queue.Queue ) ) { + _CORE_RWLock_Release( &the_rwlock->RWLock, &lock_context ); + _Objects_Allocator_unlock(); + return EBUSY; } - _Objects_Allocator_unlock(); + /* + * POSIX doesn't require behavior when it is locked. + */ - return EINVAL; + _Objects_Close( &_POSIX_RWLock_Information, &the_rwlock->Object ); + _CORE_RWLock_Release( &the_rwlock->RWLock, &lock_context ); + _POSIX_RWLock_Free( the_rwlock ); + _Objects_Allocator_unlock(); + return 0; } diff --git a/cpukit/posix/src/prwlockinit.c b/cpukit/posix/src/prwlockinit.c index afb70563e0..8bbb2fda8f 100644 --- a/cpukit/posix/src/prwlockinit.c +++ b/cpukit/posix/src/prwlockinit.c @@ -20,20 +20,14 @@ #include "config.h" #endif -#include -#include - #include #include static bool _POSIX_RWLock_Check_id_and_auto_init( - pthread_mutex_t *rwlock, - Objects_Locations *location + pthread_mutex_t *rwlock ) { if ( rwlock == NULL ) { - *location = OBJECTS_ERROR; - return false; } @@ -51,8 +45,6 @@ static bool _POSIX_RWLock_Check_id_and_auto_init( _Once_Unlock(); if ( eno != 0 ) { - *location = OBJECTS_ERROR; - return false; } } @@ -61,18 +53,18 @@ static bool _POSIX_RWLock_Check_id_and_auto_init( } POSIX_RWLock_Control *_POSIX_RWLock_Get( - pthread_rwlock_t *rwlock, - Objects_Locations *location + pthread_rwlock_t *rwlock, + ISR_lock_Context *lock_context ) { - if ( !_POSIX_RWLock_Check_id_and_auto_init( rwlock, location ) ) { + if ( !_POSIX_RWLock_Check_id_and_auto_init( rwlock ) ) { return NULL; } - return (POSIX_RWLock_Control *) _Objects_Get( - &_POSIX_RWLock_Information, + return (POSIX_RWLock_Control *) _Objects_Get_local( *rwlock, - location + &_POSIX_RWLock_Information, + lock_context ); } diff --git a/cpukit/posix/src/prwlockrdlock.c b/cpukit/posix/src/prwlockrdlock.c index 7d1bcaa9f4..3459399c6b 100644 --- a/cpukit/posix/src/prwlockrdlock.c +++ b/cpukit/posix/src/prwlockrdlock.c @@ -18,53 +18,31 @@ #include "config.h" #endif -#include -#include - #include -#include - -/** - * This directive attempts to obtain a read only lock on an rwlock instance. - * - * @param[in] rwlock is the pointer to rwlock id - * - * @retval 0 if successful - * @retval error_code if unsuccessful - */ int pthread_rwlock_rdlock( pthread_rwlock_t *rwlock ) { - POSIX_RWLock_Control *the_rwlock; - Objects_Locations location; - Thread_Control *executing; - - the_rwlock = _POSIX_RWLock_Get( rwlock, &location ); - switch ( location ) { - - case OBJECTS_LOCAL: + POSIX_RWLock_Control *the_rwlock; + ISR_lock_Context lock_context; + Thread_Control *executing; - executing = _Thread_Executing; - _CORE_RWLock_Seize_for_reading( - &the_rwlock->RWLock, - executing, - true, /* we are willing to wait forever */ - 0 - ); + the_rwlock = _POSIX_RWLock_Get( rwlock, &lock_context ); - _Objects_Put( &the_rwlock->Object ); - return _POSIX_RWLock_Translate_core_RWLock_return_code( - (CORE_RWLock_Status) executing->Wait.return_code - ); - -#if defined(RTEMS_MULTIPROCESSING) - case OBJECTS_REMOTE: -#endif - case OBJECTS_ERROR: - break; + if ( the_rwlock == NULL ) { + return EINVAL; } - return EINVAL; + executing = _Thread_Executing; + _CORE_RWLock_Seize_for_reading( + &the_rwlock->RWLock, + executing, + true, /* we are willing to wait forever */ + 0, + &lock_context + ); + return _POSIX_RWLock_Translate_core_RWLock_return_code( + (CORE_RWLock_Status) executing->Wait.return_code + ); } diff --git a/cpukit/posix/src/prwlocktimedrdlock.c b/cpukit/posix/src/prwlocktimedrdlock.c index 0f2878b581..829e1696a3 100644 --- a/cpukit/posix/src/prwlocktimedrdlock.c +++ b/cpukit/posix/src/prwlocktimedrdlock.c @@ -18,37 +18,20 @@ #include "config.h" #endif -#include -#include - #include -#include #include -/* - * pthread_rwlock_timedrdlock - * - * This directive attempts to obtain a read only lock on an rwlock instance. - * - * Input parameters: - * rwlock - pointer to rwlock id - * - * Output parameters: - * 0 - if successful - * error code - if unsuccessful - */ - int pthread_rwlock_timedrdlock( pthread_rwlock_t *rwlock, const struct timespec *abstime ) { - POSIX_RWLock_Control *the_rwlock; - Objects_Locations location; - Watchdog_Interval ticks; - bool do_wait = true; + POSIX_RWLock_Control *the_rwlock; + ISR_lock_Context lock_context; + Watchdog_Interval ticks; + bool do_wait; TOD_Absolute_timeout_conversion_results status; - Thread_Control *executing; + Thread_Control *executing; /* * POSIX requires that blocking calls with timeouts that take @@ -64,43 +47,40 @@ int pthread_rwlock_timedrdlock( * then we should not wait. */ status = _TOD_Absolute_timeout_to_ticks( abstime, &ticks ); - if ( status != TOD_ABSOLUTE_TIMEOUT_IS_IN_FUTURE ) - do_wait = false; - - the_rwlock = _POSIX_RWLock_Get( rwlock, &location ); - switch ( location ) { + do_wait = ( status == TOD_ABSOLUTE_TIMEOUT_IS_IN_FUTURE ); - case OBJECTS_LOCAL: + the_rwlock = _POSIX_RWLock_Get( rwlock, &lock_context ); - executing = _Thread_Executing; - _CORE_RWLock_Seize_for_reading( - &the_rwlock->RWLock, - executing, - do_wait, - ticks - ); + if ( the_rwlock == NULL ) { + return EINVAL; + } - _Objects_Put( &the_rwlock->Object ); - if ( !do_wait ) { - if ( executing->Wait.return_code == CORE_RWLOCK_UNAVAILABLE ) { - if ( status == TOD_ABSOLUTE_TIMEOUT_INVALID ) - return EINVAL; - if ( status == TOD_ABSOLUTE_TIMEOUT_IS_IN_PAST || - status == TOD_ABSOLUTE_TIMEOUT_IS_NOW ) - return ETIMEDOUT; - } - } + executing = _Thread_Executing; + _CORE_RWLock_Seize_for_reading( + &the_rwlock->RWLock, + executing, + do_wait, + ticks, + &lock_context + ); - return _POSIX_RWLock_Translate_core_RWLock_return_code( - (CORE_RWLock_Status) executing->Wait.return_code - ); + if ( + !do_wait + && ( executing->Wait.return_code == CORE_RWLOCK_UNAVAILABLE ) + ) { + if ( status == TOD_ABSOLUTE_TIMEOUT_INVALID ) { + return EINVAL; + } -#if defined(RTEMS_MULTIPROCESSING) - case OBJECTS_REMOTE: -#endif - case OBJECTS_ERROR: - break; + if ( + status == TOD_ABSOLUTE_TIMEOUT_IS_IN_PAST + || status == TOD_ABSOLUTE_TIMEOUT_IS_NOW + ) { + return ETIMEDOUT; + } } - return EINVAL; + return _POSIX_RWLock_Translate_core_RWLock_return_code( + (CORE_RWLock_Status) executing->Wait.return_code + ); } diff --git a/cpukit/posix/src/prwlocktimedwrlock.c b/cpukit/posix/src/prwlocktimedwrlock.c index 51558de5f8..1258c2bebb 100644 --- a/cpukit/posix/src/prwlocktimedwrlock.c +++ b/cpukit/posix/src/prwlocktimedwrlock.c @@ -20,37 +20,20 @@ #include "config.h" #endif -#include -#include - #include -#include #include -/* - * pthread_rwlock_timedwrlock - * - * This directive attempts to obtain a write only lock on an rwlock instance. - * - * Input parameters: - * rwlock - pointer to rwlock id - * - * Output parameters: - * 0 - if successful - * error code - if unsuccessful - */ - int pthread_rwlock_timedwrlock( pthread_rwlock_t *rwlock, const struct timespec *abstime ) { - POSIX_RWLock_Control *the_rwlock; - Objects_Locations location; - Watchdog_Interval ticks; - bool do_wait = true; + POSIX_RWLock_Control *the_rwlock; + ISR_lock_Context lock_context; + Watchdog_Interval ticks; + bool do_wait; TOD_Absolute_timeout_conversion_results status; - Thread_Control *executing; + Thread_Control *executing; /* * POSIX requires that blocking calls with timeouts that take @@ -66,42 +49,40 @@ int pthread_rwlock_timedwrlock( * then we should not wait. */ status = _TOD_Absolute_timeout_to_ticks( abstime, &ticks ); - if ( status != TOD_ABSOLUTE_TIMEOUT_IS_IN_FUTURE ) - do_wait = false; - - the_rwlock = _POSIX_RWLock_Get( rwlock, &location ); - switch ( location ) { + do_wait = ( status == TOD_ABSOLUTE_TIMEOUT_IS_IN_FUTURE ); - case OBJECTS_LOCAL: + the_rwlock = _POSIX_RWLock_Get( rwlock, &lock_context ); - executing = _Thread_Executing; - _CORE_RWLock_Seize_for_writing( - &the_rwlock->RWLock, - executing, - do_wait, - ticks - ); + if ( the_rwlock == NULL ) { + return EINVAL; + } - _Objects_Put( &the_rwlock->Object ); - if ( !do_wait && - (executing->Wait.return_code == CORE_RWLOCK_UNAVAILABLE) ) { - if ( status == TOD_ABSOLUTE_TIMEOUT_INVALID ) - return EINVAL; - if ( status == TOD_ABSOLUTE_TIMEOUT_IS_IN_PAST || - status == TOD_ABSOLUTE_TIMEOUT_IS_NOW ) - return ETIMEDOUT; - } + executing = _Thread_Executing; + _CORE_RWLock_Seize_for_writing( + &the_rwlock->RWLock, + executing, + do_wait, + ticks, + &lock_context + ); - return _POSIX_RWLock_Translate_core_RWLock_return_code( - (CORE_RWLock_Status) executing->Wait.return_code - ); + if ( + !do_wait + && ( executing->Wait.return_code == CORE_RWLOCK_UNAVAILABLE ) + ) { + if ( status == TOD_ABSOLUTE_TIMEOUT_INVALID ) { + return EINVAL; + } -#if defined(RTEMS_MULTIPROCESSING) - case OBJECTS_REMOTE: -#endif - case OBJECTS_ERROR: - break; + if ( + status == TOD_ABSOLUTE_TIMEOUT_IS_IN_PAST + || status == TOD_ABSOLUTE_TIMEOUT_IS_NOW + ) { + return ETIMEDOUT; + } } - return EINVAL; + return _POSIX_RWLock_Translate_core_RWLock_return_code( + (CORE_RWLock_Status) executing->Wait.return_code + ); } diff --git a/cpukit/posix/src/prwlocktryrdlock.c b/cpukit/posix/src/prwlocktryrdlock.c index 642ed868ea..a73d122ed6 100644 --- a/cpukit/posix/src/prwlocktryrdlock.c +++ b/cpukit/posix/src/prwlocktryrdlock.c @@ -18,58 +18,31 @@ #include "config.h" #endif -#include -#include - #include -#include - -/* - * pthread_rwlock_tryrdlock - * - * This directive attempts to obtain a read only lock on an rwlock instance. - * - * Input parameters: - * rwlock - pointer to rwlock id - * - * Output parameters: - * 0 - if successful - * error code - if unsuccessful - */ int pthread_rwlock_tryrdlock( pthread_rwlock_t *rwlock ) { - POSIX_RWLock_Control *the_rwlock; - Objects_Locations location; - Thread_Control *executing; - - the_rwlock = _POSIX_RWLock_Get( rwlock, &location ); - switch ( location ) { - - case OBJECTS_LOCAL: + POSIX_RWLock_Control *the_rwlock; + ISR_lock_Context lock_context; + Thread_Control *executing; - executing = _Thread_Executing; - _CORE_RWLock_Seize_for_reading( - &the_rwlock->RWLock, - executing, - false, /* do not wait for the rwlock */ - 0 - ); + the_rwlock = _POSIX_RWLock_Get( rwlock, &lock_context ); - - _Objects_Put( &the_rwlock->Object ); - return _POSIX_RWLock_Translate_core_RWLock_return_code( - (CORE_RWLock_Status) executing->Wait.return_code - ); - -#if defined(RTEMS_MULTIPROCESSING) - case OBJECTS_REMOTE: -#endif - case OBJECTS_ERROR: - break; + if ( the_rwlock == NULL ) { + return EINVAL; } - return EINVAL; + executing = _Thread_Executing; + _CORE_RWLock_Seize_for_reading( + &the_rwlock->RWLock, + executing, + false, /* do not wait for the rwlock */ + 0, + &lock_context + ); + return _POSIX_RWLock_Translate_core_RWLock_return_code( + (CORE_RWLock_Status) executing->Wait.return_code + ); } diff --git a/cpukit/posix/src/prwlocktrywrlock.c b/cpukit/posix/src/prwlocktrywrlock.c index 065199b88a..a44a54ffb5 100644 --- a/cpukit/posix/src/prwlocktrywrlock.c +++ b/cpukit/posix/src/prwlocktrywrlock.c @@ -18,57 +18,31 @@ #include "config.h" #endif -#include -#include - #include -#include - -/* - * pthread_rwlock_trywrlock - * - * This directive attempts to obtain a Write only lock on an rwlock instance. - * - * Input parameters: - * rwlock - pointer to rwlock id - * - * Output parameters: - * 0 - if successful - * error code - if unsuccessful - */ int pthread_rwlock_trywrlock( pthread_rwlock_t *rwlock ) { - POSIX_RWLock_Control *the_rwlock; - Objects_Locations location; - Thread_Control *executing; - - the_rwlock = _POSIX_RWLock_Get( rwlock, &location ); - switch ( location ) { - - case OBJECTS_LOCAL: + POSIX_RWLock_Control *the_rwlock; + ISR_lock_Context lock_context; + Thread_Control *executing; - executing = _Thread_Executing; - _CORE_RWLock_Seize_for_writing( - &the_rwlock->RWLock, - executing, - false, /* we are not willing to wait */ - 0 - ); + the_rwlock = _POSIX_RWLock_Get( rwlock, &lock_context ); - _Objects_Put( &the_rwlock->Object ); - return _POSIX_RWLock_Translate_core_RWLock_return_code( - (CORE_RWLock_Status) executing->Wait.return_code - ); - -#if defined(RTEMS_MULTIPROCESSING) - case OBJECTS_REMOTE: -#endif - case OBJECTS_ERROR: - break; + if ( the_rwlock == NULL ) { + return EINVAL; } - return EINVAL; + executing = _Thread_Executing; + _CORE_RWLock_Seize_for_writing( + &the_rwlock->RWLock, + executing, + false, /* we are not willing to wait */ + 0, + &lock_context + ); + return _POSIX_RWLock_Translate_core_RWLock_return_code( + (CORE_RWLock_Status) executing->Wait.return_code + ); } diff --git a/cpukit/posix/src/prwlockunlock.c b/cpukit/posix/src/prwlockunlock.c index 5dc70995e8..bf6b4deaf0 100644 --- a/cpukit/posix/src/prwlockunlock.c +++ b/cpukit/posix/src/prwlockunlock.c @@ -20,47 +20,22 @@ #include "config.h" #endif -#include -#include - -#include #include -/* - * pthread_rwlock_unlock - * - * This directive attempts to release a lock on an RWLock. - * - * Input parameters: - * rwlock - pointer to rwlock id - * - * Output parameters: - * 0 - if successful - * error code - if unsuccessful - */ - int pthread_rwlock_unlock( pthread_rwlock_t *rwlock ) { - POSIX_RWLock_Control *the_rwlock; - Objects_Locations location; - CORE_RWLock_Status status; + POSIX_RWLock_Control *the_rwlock; + ISR_lock_Context lock_context; + CORE_RWLock_Status status; - the_rwlock = _POSIX_RWLock_Get( rwlock, &location ); - switch ( location ) { + the_rwlock = _POSIX_RWLock_Get( rwlock, &lock_context ); - case OBJECTS_LOCAL: - status = _CORE_RWLock_Surrender( &the_rwlock->RWLock, _Thread_Executing ); - _Objects_Put( &the_rwlock->Object ); - return _POSIX_RWLock_Translate_core_RWLock_return_code( status ); - -#if defined(RTEMS_MULTIPROCESSING) - case OBJECTS_REMOTE: -#endif - case OBJECTS_ERROR: - break; + if ( the_rwlock == NULL ) { + return EINVAL; } - return EINVAL; + status = _CORE_RWLock_Surrender( &the_rwlock->RWLock, &lock_context ); + return _POSIX_RWLock_Translate_core_RWLock_return_code( status ); } diff --git a/cpukit/posix/src/prwlockwrlock.c b/cpukit/posix/src/prwlockwrlock.c index aa35a2c567..635f376e7d 100644 --- a/cpukit/posix/src/prwlockwrlock.c +++ b/cpukit/posix/src/prwlockwrlock.c @@ -28,51 +28,29 @@ THREAD_WAIT_QUEUE_OBJECT_ASSERT( POSIX_RWLock_Control, RWLock.Wait_queue ); -/* - * pthread_rwlock_wrlock - * - * This directive attempts to obtain a write only lock on an rwlock instance. - * - * Input parameters: - * rwlock - pointer to rwlock id - * - * Output parameters: - * 0 - if successful - * error code - if unsuccessful - */ - int pthread_rwlock_wrlock( pthread_rwlock_t *rwlock ) { - POSIX_RWLock_Control *the_rwlock; - Objects_Locations location; - Thread_Control *executing; - - the_rwlock = _POSIX_RWLock_Get( rwlock, &location ); - switch ( location ) { - - case OBJECTS_LOCAL: + POSIX_RWLock_Control *the_rwlock; + ISR_lock_Context lock_context; + Thread_Control *executing; - executing = _Thread_Executing; - _CORE_RWLock_Seize_for_writing( - &the_rwlock->RWLock, - executing, - true, /* do not timeout -- wait forever */ - 0 - ); + the_rwlock = _POSIX_RWLock_Get( rwlock, &lock_context ); - _Objects_Put( &the_rwlock->Object ); - return _POSIX_RWLock_Translate_core_RWLock_return_code( - (CORE_RWLock_Status) executing->Wait.return_code - ); - -#if defined(RTEMS_MULTIPROCESSING) - case OBJECTS_REMOTE: -#endif - case OBJECTS_ERROR: - break; + if ( the_rwlock == NULL ) { + return EINVAL; } - return EINVAL; + executing = _Thread_Executing; + _CORE_RWLock_Seize_for_writing( + &the_rwlock->RWLock, + executing, + true, /* do not timeout -- wait forever */ + 0, + &lock_context + ); + return _POSIX_RWLock_Translate_core_RWLock_return_code( + (CORE_RWLock_Status) executing->Wait.return_code + ); } diff --git a/cpukit/score/include/rtems/score/corerwlockimpl.h b/cpukit/score/include/rtems/score/corerwlockimpl.h index e727ad62c2..ed59d696b6 100644 --- a/cpukit/score/include/rtems/score/corerwlockimpl.h +++ b/cpukit/score/include/rtems/score/corerwlockimpl.h @@ -86,6 +86,22 @@ RTEMS_INLINE_ROUTINE void _CORE_RWLock_Destroy( _Thread_queue_Destroy( &the_rwlock->Wait_queue ); } +RTEMS_INLINE_ROUTINE void _CORE_RWLock_Acquire_critical( + CORE_RWLock_Control *the_rwlock, + ISR_lock_Context *lock_context +) +{ + _Thread_queue_Acquire_critical( &the_rwlock->Wait_queue, lock_context ); +} + +RTEMS_INLINE_ROUTINE void _CORE_RWLock_Release( + CORE_RWLock_Control *the_rwlock, + ISR_lock_Context *lock_context +) +{ + _Thread_queue_Release( &the_rwlock->Wait_queue, lock_context ); +} + /** * @brief Obtain RWLock for reading. * @@ -103,7 +119,8 @@ void _CORE_RWLock_Seize_for_reading( CORE_RWLock_Control *the_rwlock, Thread_Control *executing, bool wait, - Watchdog_Interval timeout + Watchdog_Interval timeout, + ISR_lock_Context *lock_context ); /** @@ -122,7 +139,8 @@ void _CORE_RWLock_Seize_for_writing( CORE_RWLock_Control *the_rwlock, Thread_Control *executing, bool wait, - Watchdog_Interval timeout + Watchdog_Interval timeout, + ISR_lock_Context *lock_context ); /** @@ -137,7 +155,7 @@ void _CORE_RWLock_Seize_for_writing( */ CORE_RWLock_Status _CORE_RWLock_Surrender( CORE_RWLock_Control *the_rwlock, - Thread_Control *executing + ISR_lock_Context *lock_context ); /** @} */ diff --git a/cpukit/score/src/corerwlockobtainread.c b/cpukit/score/src/corerwlockobtainread.c index 3d3757144f..fcbaf4a829 100644 --- a/cpukit/score/src/corerwlockobtainread.c +++ b/cpukit/score/src/corerwlockobtainread.c @@ -27,70 +27,68 @@ void _CORE_RWLock_Seize_for_reading( CORE_RWLock_Control *the_rwlock, Thread_Control *executing, bool wait, - Watchdog_Interval timeout + Watchdog_Interval timeout, + ISR_lock_Context *lock_context ) { - ISR_lock_Context lock_context; - /* * If unlocked, then OK to read. * If locked for reading and no waiters, then OK to read. * If any thread is waiting, then we wait. */ - _Thread_queue_Acquire( &the_rwlock->Wait_queue, &lock_context ); - switch ( the_rwlock->current_state ) { - case CORE_RWLOCK_UNLOCKED: - the_rwlock->current_state = CORE_RWLOCK_LOCKED_FOR_READING; - the_rwlock->number_of_readers += 1; - _Thread_queue_Release( &the_rwlock->Wait_queue, &lock_context ); - executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL; - return; + _CORE_RWLock_Acquire_critical( the_rwlock, lock_context ); + + switch ( the_rwlock->current_state ) { + case CORE_RWLOCK_UNLOCKED: + the_rwlock->current_state = CORE_RWLOCK_LOCKED_FOR_READING; + the_rwlock->number_of_readers += 1; + _CORE_RWLock_Release( the_rwlock, lock_context ); + executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL; + return; - case CORE_RWLOCK_LOCKED_FOR_READING: { - Thread_Control *waiter; - waiter = _Thread_queue_First_locked( - &the_rwlock->Wait_queue, - CORE_RWLOCK_TQ_OPERATIONS - ); - if ( !waiter ) { - the_rwlock->number_of_readers += 1; - _Thread_queue_Release( &the_rwlock->Wait_queue, &lock_context ); - executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL; - return; - } - break; + case CORE_RWLOCK_LOCKED_FOR_READING: { + Thread_Control *waiter; + waiter = _Thread_queue_First_locked( + &the_rwlock->Wait_queue, + CORE_RWLOCK_TQ_OPERATIONS + ); + if ( !waiter ) { + the_rwlock->number_of_readers += 1; + _CORE_RWLock_Release( the_rwlock, lock_context ); + executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL; + return; } - case CORE_RWLOCK_LOCKED_FOR_WRITING: - break; + break; } + case CORE_RWLOCK_LOCKED_FOR_WRITING: + break; + } - /* - * If the thread is not willing to wait, then return immediately. - */ - - if ( !wait ) { - _Thread_queue_Release( &the_rwlock->Wait_queue, &lock_context ); - executing->Wait.return_code = CORE_RWLOCK_UNAVAILABLE; - return; - } + /* + * If the thread is not willing to wait, then return immediately. + */ - /* - * We need to wait to enter this critical section - */ + if ( !wait ) { + _CORE_RWLock_Release( the_rwlock, lock_context ); + executing->Wait.return_code = CORE_RWLOCK_UNAVAILABLE; + return; + } - executing->Wait.option = CORE_RWLOCK_THREAD_WAITING_FOR_READ; - executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL; + /* + * We need to wait to enter this critical section + */ - _Thread_queue_Enqueue_critical( - &the_rwlock->Wait_queue.Queue, - CORE_RWLOCK_TQ_OPERATIONS, - executing, - STATES_WAITING_FOR_RWLOCK, - timeout, - CORE_RWLOCK_TIMEOUT, - &lock_context - ); + executing->Wait.option = CORE_RWLOCK_THREAD_WAITING_FOR_READ; + executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL; - /* return to API level so it can dispatch and we block */ + _Thread_queue_Enqueue_critical( + &the_rwlock->Wait_queue.Queue, + CORE_RWLOCK_TQ_OPERATIONS, + executing, + STATES_WAITING_FOR_RWLOCK, + timeout, + CORE_RWLOCK_TIMEOUT, + lock_context + ); } diff --git a/cpukit/score/src/corerwlockobtainwrite.c b/cpukit/score/src/corerwlockobtainwrite.c index 07fe03acaa..e1bb1bd14a 100644 --- a/cpukit/score/src/corerwlockobtainwrite.c +++ b/cpukit/score/src/corerwlockobtainwrite.c @@ -24,14 +24,13 @@ #include void _CORE_RWLock_Seize_for_writing( - CORE_RWLock_Control *the_rwlock, - Thread_Control *executing, - bool wait, - Watchdog_Interval timeout + CORE_RWLock_Control *the_rwlock, + Thread_Control *executing, + bool wait, + Watchdog_Interval timeout, + ISR_lock_Context *lock_context ) { - ISR_lock_Context lock_context; - /* * If unlocked, then OK to read. * Otherwise, we have to block. @@ -39,45 +38,44 @@ void _CORE_RWLock_Seize_for_writing( * If any thread is waiting, then we wait. */ - _Thread_queue_Acquire( &the_rwlock->Wait_queue, &lock_context ); - switch ( the_rwlock->current_state ) { - case CORE_RWLOCK_UNLOCKED: - the_rwlock->current_state = CORE_RWLOCK_LOCKED_FOR_WRITING; - _Thread_queue_Release( &the_rwlock->Wait_queue, &lock_context ); - executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL; - return; + _CORE_RWLock_Acquire_critical( the_rwlock, lock_context ); - case CORE_RWLOCK_LOCKED_FOR_READING: - case CORE_RWLOCK_LOCKED_FOR_WRITING: - break; - } + switch ( the_rwlock->current_state ) { + case CORE_RWLOCK_UNLOCKED: + the_rwlock->current_state = CORE_RWLOCK_LOCKED_FOR_WRITING; + _CORE_RWLock_Release( the_rwlock, lock_context ); + executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL; + return; - /* - * If the thread is not willing to wait, then return immediately. - */ + case CORE_RWLOCK_LOCKED_FOR_READING: + case CORE_RWLOCK_LOCKED_FOR_WRITING: + break; + } - if ( !wait ) { - _Thread_queue_Release( &the_rwlock->Wait_queue, &lock_context ); - executing->Wait.return_code = CORE_RWLOCK_UNAVAILABLE; - return; - } + /* + * If the thread is not willing to wait, then return immediately. + */ - /* - * We need to wait to enter this critical section - */ + if ( !wait ) { + _CORE_RWLock_Release( the_rwlock, lock_context ); + executing->Wait.return_code = CORE_RWLOCK_UNAVAILABLE; + return; + } - executing->Wait.option = CORE_RWLOCK_THREAD_WAITING_FOR_WRITE; - executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL; + /* + * We need to wait to enter this critical section + */ - _Thread_queue_Enqueue_critical( - &the_rwlock->Wait_queue.Queue, - CORE_RWLOCK_TQ_OPERATIONS, - executing, - STATES_WAITING_FOR_RWLOCK, - timeout, - CORE_RWLOCK_TIMEOUT, - &lock_context - ); + executing->Wait.option = CORE_RWLOCK_THREAD_WAITING_FOR_WRITE; + executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL; - /* return to API level so it can dispatch and we block */ + _Thread_queue_Enqueue_critical( + &the_rwlock->Wait_queue.Queue, + CORE_RWLOCK_TQ_OPERATIONS, + executing, + STATES_WAITING_FOR_RWLOCK, + timeout, + CORE_RWLOCK_TIMEOUT, + lock_context + ); } diff --git a/cpukit/score/src/corerwlockrelease.c b/cpukit/score/src/corerwlockrelease.c index d8180fce6c..3ace00da8e 100644 --- a/cpukit/score/src/corerwlockrelease.c +++ b/cpukit/score/src/corerwlockrelease.c @@ -19,19 +19,65 @@ #include "config.h" #endif -#include #include -#include -#include +#include + +static bool _CORE_RWLock_Is_waiting_for_reading( + const Thread_Control *the_thread +) +{ + if ( the_thread->Wait.option == CORE_RWLOCK_THREAD_WAITING_FOR_READ ) { + return true; + } else { + _Assert( the_thread->Wait.option == CORE_RWLOCK_THREAD_WAITING_FOR_WRITE ); + return false; + } +} + +static Thread_Control *_CORE_RWLock_Flush_filter( + Thread_Control *the_thread, + Thread_queue_Queue *queue, + ISR_lock_Context *lock_context +) +{ + CORE_RWLock_Control *the_rwlock; + + the_rwlock = RTEMS_CONTAINER_OF( + queue, + CORE_RWLock_Control, + Wait_queue.Queue + ); + + switch ( the_rwlock->current_state ) { + case CORE_RWLOCK_LOCKED_FOR_READING: + if ( _CORE_RWLock_Is_waiting_for_reading( the_thread ) ) { + the_rwlock->number_of_readers += 1; + } else { + the_thread = NULL; + } + break; + case CORE_RWLOCK_LOCKED_FOR_WRITING: + the_thread = NULL; + break; + default: + _Assert( the_rwlock->current_state == CORE_RWLOCK_UNLOCKED ); + if ( _CORE_RWLock_Is_waiting_for_reading( the_thread ) ) { + the_rwlock->current_state = CORE_RWLOCK_LOCKED_FOR_READING; + the_rwlock->number_of_readers = 1; + } else { + the_rwlock->current_state = CORE_RWLOCK_LOCKED_FOR_WRITING; + } + break; + } + + return the_thread; +} CORE_RWLock_Status _CORE_RWLock_Surrender( CORE_RWLock_Control *the_rwlock, - Thread_Control *executing + ISR_lock_Context *lock_context ) { - ISR_Level level; - Thread_Control *next; - /* * If unlocked, then OK to read. * Otherwise, we have to block. @@ -39,67 +85,43 @@ CORE_RWLock_Status _CORE_RWLock_Surrender( * If any thread is waiting, then we wait. */ - _ISR_Disable( level ); - if ( the_rwlock->current_state == CORE_RWLOCK_UNLOCKED){ - _ISR_Enable( level ); - executing->Wait.return_code = CORE_RWLOCK_UNAVAILABLE; - return CORE_RWLOCK_SUCCESSFUL; - } - if ( the_rwlock->current_state == CORE_RWLOCK_LOCKED_FOR_READING ) { - the_rwlock->number_of_readers -= 1; - if ( the_rwlock->number_of_readers != 0 ) { - /* must be unlocked again */ - _ISR_Enable( level ); - return CORE_RWLOCK_SUCCESSFUL; - } - } - - /* CORE_RWLOCK_LOCKED_FOR_WRITING or READING with readers */ - executing->Wait.return_code = CORE_RWLOCK_SUCCESSFUL; + _CORE_RWLock_Acquire_critical( the_rwlock, lock_context ); - /* - * Implicitly transition to "unlocked" and find another thread interested - * in obtaining this rwlock. - */ - the_rwlock->current_state = CORE_RWLOCK_UNLOCKED; - _ISR_Enable( level ); + if ( the_rwlock->current_state == CORE_RWLOCK_UNLOCKED){ + /* This is an error at the caller site */ + _CORE_RWLock_Release( the_rwlock, lock_context ); + return CORE_RWLOCK_SUCCESSFUL; + } - next = _Thread_queue_Dequeue( - &the_rwlock->Wait_queue, - CORE_RWLOCK_TQ_OPERATIONS, - NULL, - 0 - ); + if ( the_rwlock->current_state == CORE_RWLOCK_LOCKED_FOR_READING ) { + the_rwlock->number_of_readers -= 1; - if ( next ) { - if ( next->Wait.option == CORE_RWLOCK_THREAD_WAITING_FOR_WRITE ) { - the_rwlock->current_state = CORE_RWLOCK_LOCKED_FOR_WRITING; + if ( the_rwlock->number_of_readers != 0 ) { + /* must be unlocked again */ + _CORE_RWLock_Release( the_rwlock, lock_context ); return CORE_RWLOCK_SUCCESSFUL; } - - /* - * Must be CORE_RWLOCK_THREAD_WAITING_FOR_READING - */ - the_rwlock->number_of_readers += 1; - the_rwlock->current_state = CORE_RWLOCK_LOCKED_FOR_READING; - - /* - * Now see if more readers can be let go. - */ - while ( 1 ) { - next = _Thread_queue_First( - &the_rwlock->Wait_queue, - CORE_RWLOCK_TQ_OPERATIONS - ); - if ( !next || - next->Wait.option == CORE_RWLOCK_THREAD_WAITING_FOR_WRITE ) - return CORE_RWLOCK_SUCCESSFUL; - the_rwlock->number_of_readers += 1; - _Thread_queue_Extract( next ); - } } - /* indentation is to match _ISR_Disable at top */ + _Assert( + the_rwlock->current_state == CORE_RWLOCK_LOCKED_FOR_WRITING + || ( the_rwlock->current_state == CORE_RWLOCK_LOCKED_FOR_READING + && the_rwlock->number_of_readers == 0 ) + ); + + /* + * Implicitly transition to "unlocked" and find another thread interested + * in obtaining this rwlock. + */ + the_rwlock->current_state = CORE_RWLOCK_UNLOCKED; + _Thread_queue_Flush_critical( + &the_rwlock->Wait_queue.Queue, + CORE_RWLOCK_TQ_OPERATIONS, + _CORE_RWLock_Flush_filter, + NULL, + 0, + lock_context + ); return CORE_RWLOCK_SUCCESSFUL; } -- cgit v1.2.3