diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2016-04-13 06:48:58 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2016-04-18 08:20:16 +0200 |
commit | 709f38a97287ff1aa8e8c0668c2d066e711db87c (patch) | |
tree | e711e14275c58c0ee8483468fca804476db0fdbd /cpukit | |
parent | score: _User_extensions_Handler_initialization() (diff) | |
download | rtems-709f38a97287ff1aa8e8c0668c2d066e711db87c.tar.bz2 |
score: Use chain iterator for user extensions
Add a lock and use a chain iterator for safe iteration during concurrent
user extension addition and removal.
Ensure that dynamically added thread delete and fatal extensions are
called in reverse order.
Update #2555.
Update #2692.
Diffstat (limited to '')
-rw-r--r-- | cpukit/score/include/rtems/score/thread.h | 7 | ||||
-rw-r--r-- | cpukit/score/include/rtems/score/userextimpl.h | 108 | ||||
-rw-r--r-- | cpukit/score/src/threadrestart.c | 2 | ||||
-rw-r--r-- | cpukit/score/src/userextaddset.c | 14 | ||||
-rw-r--r-- | cpukit/score/src/userextiterate.c | 84 | ||||
-rw-r--r-- | cpukit/score/src/userextremoveset.c | 9 |
6 files changed, 184 insertions, 40 deletions
diff --git a/cpukit/score/include/rtems/score/thread.h b/cpukit/score/include/rtems/score/thread.h index d9f1eb2d6d..4da4a341d6 100644 --- a/cpukit/score/include/rtems/score/thread.h +++ b/cpukit/score/include/rtems/score/thread.h @@ -48,6 +48,8 @@ struct Scheduler_Control; struct Scheduler_Node; +struct User_extensions_Iterator; + #ifdef __cplusplus extern "C" { #endif @@ -899,6 +901,11 @@ struct _Thread_Control { struct _pthread_cleanup_context *last_cleanup_context; /** + * @brief LIFO list of user extensions iterators. + */ + struct User_extensions_Iterator *last_user_extensions_iterator; + + /** * @brief Variable length array of user extension pointers. * * The length is defined by the application via <rtems/confdefs.h>. diff --git a/cpukit/score/include/rtems/score/userextimpl.h b/cpukit/score/include/rtems/score/userextimpl.h index 8c2a1fac4d..e175c9f0a5 100644 --- a/cpukit/score/include/rtems/score/userextimpl.h +++ b/cpukit/score/include/rtems/score/userextimpl.h @@ -19,6 +19,7 @@ #define _RTEMS_SCORE_USEREXTIMPL_H #include <rtems/score/userext.h> +#include <rtems/score/isrlock.h> #include <rtems/score/chainimpl.h> #include <rtems/score/percpu.h> @@ -36,9 +37,41 @@ extern "C" { /**@{**/ /** + * @brief Chain iterator for dynamic user extensions. + * + * Since user extensions may delete or restart the executing thread, we must + * clean up registered iterators. + * + * @see _User_extensions_Iterate(), _User_extensions_Destroy_iterators() and + * Thread_Control::last_user_extensions_iterator. + */ +typedef struct User_extensions_Iterator { + Chain_Iterator Iterator; + struct User_extensions_Iterator *previous; +} User_extensions_Iterator; + +typedef struct { + /** + * @brief Active dynamically added user extensions. + */ + Chain_Control Active; + + /** + * @brief Chain iterator registration. + */ + Chain_Iterator_registry Iterators; + + /** + * @brief Lock to protect User_extensions_List::Active and + * User_extensions_List::Iterators. + */ + ISR_LOCK_MEMBER( Lock ) +} User_extensions_List; + +/** * @brief List of active extensions. */ -extern Chain_Control _User_extensions_List; +extern User_extensions_List _User_extensions_List; /** * @brief List of active task switch extensions. @@ -153,11 +186,13 @@ void _User_extensions_Thread_terminate_visitor( * @brief Iterates through all user extensions and calls the visitor for each. * * @param[in, out] arg The argument passed to the visitor. - * @param[in] visitor is the visitor for each extension. + * @param[in] visitor The visitor for each extension. + * @param[in] direction The iteration direction for dynamic extensions. */ void _User_extensions_Iterate( - void *arg, - User_extensions_Visitor visitor + void *arg, + User_extensions_Visitor visitor, + Chain_Iterator_direction direction ); /** @} */ @@ -171,7 +206,11 @@ static inline bool _User_extensions_Thread_create( Thread_Control *created ) { User_extensions_Thread_create_context ctx = { created, true }; - _User_extensions_Iterate( &ctx, _User_extensions_Thread_create_visitor ); + _User_extensions_Iterate( + &ctx, + _User_extensions_Thread_create_visitor, + CHAIN_ITERATOR_FORWARD + ); return ctx.ok; } @@ -180,7 +219,8 @@ static inline void _User_extensions_Thread_delete( Thread_Control *deleted ) { _User_extensions_Iterate( deleted, - _User_extensions_Thread_delete_visitor + _User_extensions_Thread_delete_visitor, + CHAIN_ITERATOR_BACKWARD ); } @@ -188,7 +228,8 @@ static inline void _User_extensions_Thread_start( Thread_Control *started ) { _User_extensions_Iterate( started, - _User_extensions_Thread_start_visitor + _User_extensions_Thread_start_visitor, + CHAIN_ITERATOR_FORWARD ); } @@ -196,7 +237,8 @@ static inline void _User_extensions_Thread_restart( Thread_Control *restarted ) { _User_extensions_Iterate( restarted, - _User_extensions_Thread_restart_visitor + _User_extensions_Thread_restart_visitor, + CHAIN_ITERATOR_FORWARD ); } @@ -204,7 +246,8 @@ static inline void _User_extensions_Thread_begin( Thread_Control *executing ) { _User_extensions_Iterate( executing, - _User_extensions_Thread_begin_visitor + _User_extensions_Thread_begin_visitor, + CHAIN_ITERATOR_FORWARD ); } @@ -239,7 +282,8 @@ static inline void _User_extensions_Thread_exitted( Thread_Control *executing ) { _User_extensions_Iterate( executing, - _User_extensions_Thread_exitted_visitor + _User_extensions_Thread_exitted_visitor, + CHAIN_ITERATOR_FORWARD ); } @@ -251,7 +295,11 @@ static inline void _User_extensions_Fatal( { User_extensions_Fatal_context ctx = { source, is_internal, error }; - _User_extensions_Iterate( &ctx, _User_extensions_Fatal_visitor ); + _User_extensions_Iterate( + &ctx, + _User_extensions_Fatal_visitor, + CHAIN_ITERATOR_BACKWARD + ); } static inline void _User_extensions_Thread_terminate( @@ -260,10 +308,46 @@ static inline void _User_extensions_Thread_terminate( { _User_extensions_Iterate( executing, - _User_extensions_Thread_terminate_visitor + _User_extensions_Thread_terminate_visitor, + CHAIN_ITERATOR_FORWARD + ); +} + +static inline void _User_extensions_Acquire( ISR_lock_Context *lock_context ) +{ + _ISR_lock_ISR_disable_and_acquire( + &_User_extensions_List.Lock, + lock_context ); } +static inline void _User_extensions_Release( ISR_lock_Context *lock_context ) +{ + _ISR_lock_Release_and_ISR_enable( + &_User_extensions_List.Lock, + lock_context + ); +} + +static inline void _User_extensions_Destroy_iterators( + Thread_Control *the_thread +) +{ + ISR_lock_Context lock_context; + User_extensions_Iterator *iter; + + _User_extensions_Acquire( &lock_context ); + + iter = the_thread->last_user_extensions_iterator; + + while ( iter != NULL ) { + _Chain_Iterator_destroy( &iter->Iterator ); + iter = iter->previous; + } + + _User_extensions_Release( &lock_context ); +} + /** @} */ /** @} */ diff --git a/cpukit/score/src/threadrestart.c b/cpukit/score/src/threadrestart.c index 59754a86fb..13b4365b35 100644 --- a/cpukit/score/src/threadrestart.c +++ b/cpukit/score/src/threadrestart.c @@ -97,6 +97,7 @@ static void _Thread_Free( Thread_Control *the_thread ) _Objects_Get_information_id( the_thread->Object.id ); _User_extensions_Thread_delete( the_thread ); + _User_extensions_Destroy_iterators( the_thread ); _ISR_lock_Destroy( &the_thread->Keys.Lock ); _Scheduler_Node_destroy( _Scheduler_Get( the_thread ), the_thread ); _ISR_lock_Destroy( &the_thread->Timer.Lock ); @@ -255,6 +256,7 @@ void _Thread_Life_action_handler( executing->Life.state = THREAD_LIFE_NORMAL; + _User_extensions_Destroy_iterators( executing ); _Thread_Load_environment( executing ); _Thread_Restart_self( executing ); RTEMS_UNREACHABLE(); diff --git a/cpukit/score/src/userextaddset.c b/cpukit/score/src/userextaddset.c index f34ad0072f..19bbd361e9 100644 --- a/cpukit/score/src/userextaddset.c +++ b/cpukit/score/src/userextaddset.c @@ -20,20 +20,20 @@ #endif #include <rtems/score/userextimpl.h> -#include <rtems/score/objectimpl.h> #include <rtems/score/percpu.h> -#include <rtems/score/sysstate.h> void _User_extensions_Add_set( User_extensions_Control *the_extension ) { - _Assert( - _Objects_Allocator_is_owner() - || _System_state_Is_before_multitasking( _System_state_Get() ) - ); + ISR_lock_Context lock_context; - _Chain_Append_unprotected( &_User_extensions_List, &the_extension->Node ); + _User_extensions_Acquire( &lock_context ); + _Chain_Append_unprotected( + &_User_extensions_List.Active, + &the_extension->Node + ); + _User_extensions_Release( &lock_context ); /* * If a switch handler is present, append it to the switch chain. diff --git a/cpukit/score/src/userextiterate.c b/cpukit/score/src/userextiterate.c index beeee9570b..6cb877452b 100644 --- a/cpukit/score/src/userextiterate.c +++ b/cpukit/score/src/userextiterate.c @@ -7,10 +7,10 @@ */ /* - * Copyright (c) 2012 embedded brains GmbH. All rights reserved. + * Copyright (c) 2012, 2016 embedded brains GmbH. All rights reserved. * * embedded brains GmbH - * Obere Lagerstr. 30 + * Dornierstr. 4 * 82178 Puchheim * Germany * <rtems@embedded-brains.de> @@ -27,7 +27,16 @@ #include <rtems/config.h> #include <rtems/score/userextimpl.h> -CHAIN_DEFINE_EMPTY( _User_extensions_List ); +#include <pthread.h> + +User_extensions_List _User_extensions_List = { + CHAIN_INITIALIZER_EMPTY( _User_extensions_List.Active ), + CHAIN_ITERATOR_REGISTRY_INITIALIZER( _User_extensions_List.Iterators ) +#if defined(RTEMS_SMP) + , + ISR_LOCK_INITIALIZER( "User Extensions List" ) +#endif +}; void _User_extensions_Thread_create_visitor( Thread_Control *executing, @@ -139,17 +148,24 @@ void _User_extensions_Thread_terminate_visitor( } void _User_extensions_Iterate( - void *arg, - User_extensions_Visitor visitor + void *arg, + User_extensions_Visitor visitor, + Chain_Iterator_direction direction ) { - Thread_Control *executing = _Thread_Get_executing(); - const User_extensions_Table *callouts_current = - rtems_configuration_get_user_extension_table(); - const User_extensions_Table *callouts_end = - callouts_current + rtems_configuration_get_number_of_initial_extensions(); - const Chain_Node *node; - const Chain_Node *tail; + Thread_Control *executing; + const User_extensions_Table *callouts_current; + const User_extensions_Table *callouts_end; + const Chain_Node *end; + Chain_Node *node; + User_extensions_Iterator iter; + ISR_lock_Context lock_context; + + executing = _Thread_Get_executing(); + + callouts_current = rtems_configuration_get_user_extension_table(); + callouts_end = callouts_current + + rtems_configuration_get_number_of_initial_extensions(); while ( callouts_current != callouts_end ) { (*visitor)( executing, arg, callouts_current ); @@ -157,14 +173,44 @@ void _User_extensions_Iterate( ++callouts_current; } - node = _Chain_Immutable_first( &_User_extensions_List ); - tail = _Chain_Immutable_tail( &_User_extensions_List ); - while ( node != tail ) { - const User_extensions_Control *extension = - (const User_extensions_Control *) node; + if ( direction == CHAIN_ITERATOR_FORWARD ) { + end = _Chain_Immutable_tail( &_User_extensions_List.Active ); + } else { + end = _Chain_Immutable_head( &_User_extensions_List.Active ); + } + + _User_extensions_Acquire( &lock_context ); + + _Chain_Iterator_initialize( + &_User_extensions_List.Active, + &_User_extensions_List.Iterators, + &iter.Iterator, + direction + ); + + if ( executing != NULL ) { + iter.previous = executing->last_user_extensions_iterator; + executing->last_user_extensions_iterator = &iter; + } + + while ( ( node = _Chain_Iterator_next( &iter.Iterator ) ) != end ) { + const User_extensions_Control *extension; + + _Chain_Iterator_set_position( &iter.Iterator, node ); + + _User_extensions_Release( &lock_context ); - (*visitor)( executing, arg, &extension->Callouts ); + extension = (const User_extensions_Control *) node; + ( *visitor )( executing, arg, &extension->Callouts ); - node = _Chain_Immutable_next( node ); + _User_extensions_Acquire( &lock_context ); } + + if ( executing != NULL ) { + executing->last_user_extensions_iterator = iter.previous; + } + + _Chain_Iterator_destroy( &iter.Iterator ); + + _User_extensions_Release( &lock_context ); } diff --git a/cpukit/score/src/userextremoveset.c b/cpukit/score/src/userextremoveset.c index 5b3fdd1aea..b25cc344b4 100644 --- a/cpukit/score/src/userextremoveset.c +++ b/cpukit/score/src/userextremoveset.c @@ -20,16 +20,21 @@ #endif #include <rtems/score/userextimpl.h> -#include <rtems/score/objectimpl.h> #include <rtems/score/percpu.h> void _User_extensions_Remove_set ( User_extensions_Control *the_extension ) { - _Assert( _Objects_Allocator_is_owner() ); + ISR_lock_Context lock_context; + _User_extensions_Acquire( &lock_context ); + _Chain_Iterator_registry_update( + &_User_extensions_List.Iterators, + &the_extension->Node + ); _Chain_Extract_unprotected( &the_extension->Node ); + _User_extensions_Release( &lock_context ); /* * If a switch handler is present, remove it. |