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. --- cpukit/score/include/rtems/score/thread.h | 7 + cpukit/score/include/rtems/score/userextimpl.h | 108 ++++- cpukit/score/src/threadrestart.c | 2 + cpukit/score/src/userextaddset.c | 14 +- cpukit/score/src/userextiterate.c | 84 +++- cpukit/score/src/userextremoveset.c | 9 +- testsuites/sptests/Makefile.am | 1 + testsuites/sptests/configure.ac | 1 + testsuites/sptests/spextensions01/Makefile.am | 19 + testsuites/sptests/spextensions01/init.c | 447 +++++++++++++++++++++ .../sptests/spextensions01/spextensions01.doc | 12 + .../sptests/spextensions01/spextensions01.scn | 2 + 12 files changed, 666 insertions(+), 40 deletions(-) create mode 100644 testsuites/sptests/spextensions01/Makefile.am create mode 100644 testsuites/sptests/spextensions01/init.c create mode 100644 testsuites/sptests/spextensions01/spextensions01.doc create mode 100644 testsuites/sptests/spextensions01/spextensions01.scn diff --git a/cpukit/score/include/rtems/score/thread.h b/cpukit/score/include/rtems/score/thread.h index d9f1eb2..4da4a34 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 8c2a1fa..e175c9f 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 59754a8..13b4365 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 f34ad00..19bbd36 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 beeee95..6cb8774 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 * <rt...@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 5b3fdd1..b25cc34 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. diff --git a/testsuites/sptests/Makefile.am b/testsuites/sptests/Makefile.am index 43f3d82..77acaba 100644 --- a/testsuites/sptests/Makefile.am +++ b/testsuites/sptests/Makefile.am @@ -33,6 +33,7 @@ _SUBDIRS = \ spsignal_err01 spport_err01 spmsgq_err01 spmsgq_err02 spsem_err01 \ spsem_err02 sptask_err01 spevent_err03 sptask_err03 sptask_err02 \ sptask_err04 spclock_err01 +_SUBDIRS += spextensions01 _SUBDIRS += spsysinit01 if HAS_SMP else diff --git a/testsuites/sptests/configure.ac b/testsuites/sptests/configure.ac index eeebc91..66f6860 100644 --- a/testsuites/sptests/configure.ac +++ b/testsuites/sptests/configure.ac @@ -46,6 +46,7 @@ AM_CONDITIONAL(HAS_SMP,test "$rtems_cv_RTEMS_SMP" = "yes") # Explicitly list all Makefiles here AC_CONFIG_FILES([Makefile +spextensions01/Makefile sptimerserver01/Makefile spsysinit01/Makefile splinkersets01/Makefile diff --git a/testsuites/sptests/spextensions01/Makefile.am b/testsuites/sptests/spextensions01/Makefile.am new file mode 100644 index 0000000..610c2b5 --- /dev/null +++ b/testsuites/sptests/spextensions01/Makefile.am @@ -0,0 +1,19 @@ +rtems_tests_PROGRAMS = spextensions01 +spextensions01_SOURCES = init.c + +dist_rtems_tests_DATA = spextensions01.scn spextensions01.doc + +include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg +include $(top_srcdir)/../automake/compile.am +include $(top_srcdir)/../automake/leaf.am + +AM_CPPFLAGS += -I$(top_srcdir)/../support/include + +LINK_OBJS = $(spextensions01_OBJECTS) +LINK_LIBS = $(spextensions01_LDLIBS) + +spextensions01$(EXEEXT): $(spextensions01_OBJECTS) $(spextensions01_DEPENDENCIES) + @rm -f spextensions01$(EXEEXT) + $(make-exe) + +include $(top_srcdir)/../automake/local.am diff --git a/testsuites/sptests/spextensions01/init.c b/testsuites/sptests/spextensions01/init.c new file mode 100644 index 0000000..d8593b9 --- /dev/null +++ b/testsuites/sptests/spextensions01/init.c @@ -0,0 +1,447 @@ +/* + * Copyright (c) 2016 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * <rt...@embedded-brains.de> + * + * 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. + */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include <assert.h> +#include <limits.h> +#include <stdlib.h> + +#include <rtems/test.h> + +#include <bsp.h> + +const char rtems_test_name[] = "SPEXTENSIONS 1"; + +static int counter; + +static int active_extensions = 2; + +static rtems_id master_task; + +static void assert_static_order(int index) +{ + assert((counter % active_extensions) == index); + ++counter; +} + +static void assert_forward_order(int index) +{ + assert((counter % active_extensions) == index); + ++counter; +} + +static void assert_reverse_order(int index) +{ + assert((counter % active_extensions) == (5 - index)); + ++counter; +} + +static bool zero_thread_create(rtems_tcb *a, rtems_tcb *b) +{ + assert_static_order(0); + return true; +} + +static void zero_thread_start(rtems_tcb *a, rtems_tcb *b) +{ + assert_static_order(0); +} + +static void zero_thread_restart(rtems_tcb *a, rtems_tcb *b) +{ + assert_static_order(0); +} + +static void zero_thread_delete(rtems_tcb *a, rtems_tcb *b) +{ + assert_static_order(0); +} + +static void zero_thread_switch(rtems_tcb *a, rtems_tcb *b) +{ + assert_static_order(0); +} + +static void zero_thread_begin(rtems_tcb *a) +{ + assert_static_order(0); +} + +static void zero_thread_exitted(rtems_tcb *a) +{ + assert_static_order(0); +} + +static void zero_fatal( + rtems_fatal_source source, + bool is_internal, + rtems_fatal_code code +) +{ + if (source == RTEMS_FATAL_SOURCE_EXIT) { + assert_static_order(0); + } +} + +static void zero_thread_terminate(rtems_tcb *a) +{ + assert_static_order(0); +} + +static bool one_thread_create(rtems_tcb *a, rtems_tcb *b) +{ + assert_static_order(1); + return true; +} + +static void one_thread_start(rtems_tcb *a, rtems_tcb *b) +{ + assert_static_order(1); +} + +static void one_thread_restart(rtems_tcb *a, rtems_tcb *b) +{ + assert_static_order(1); +} + +static void one_thread_delete(rtems_tcb *a, rtems_tcb *b) +{ + assert_static_order(1); +} + +static void one_thread_switch(rtems_tcb *a, rtems_tcb *b) +{ + assert_static_order(1); +} + +static void one_thread_begin(rtems_tcb *a) +{ + assert_static_order(1); +} + +static void one_thread_exitted(rtems_tcb *a) +{ + assert_static_order(1); +} + +static void one_fatal( + rtems_fatal_source source, + bool is_internal, + rtems_fatal_code code +) +{ + if (source == RTEMS_FATAL_SOURCE_EXIT) { + assert_static_order(1); + } +} + +static void one_thread_terminate(rtems_tcb *a) +{ + assert_static_order(1); +} + +static bool two_thread_create(rtems_tcb *a, rtems_tcb *b) +{ + assert_forward_order(2); + return true; +} + +static void two_thread_start(rtems_tcb *a, rtems_tcb *b) +{ + assert_forward_order(2); +} + +static void two_thread_restart(rtems_tcb *a, rtems_tcb *b) +{ + assert_static_order(2); +} + +static void two_thread_delete(rtems_tcb *a, rtems_tcb *b) +{ + assert_reverse_order(2); +} + +static void two_thread_switch(rtems_tcb *a, rtems_tcb *b) +{ + assert_forward_order(2); +} + +static void two_thread_begin(rtems_tcb *a) +{ + assert_forward_order(2); +} + +static void two_thread_exitted(rtems_tcb *a) +{ + assert_forward_order(2); +} + +static void two_fatal( + rtems_fatal_source source, + bool is_internal, + rtems_fatal_code code +) +{ + if (source == RTEMS_FATAL_SOURCE_EXIT) { + assert_reverse_order(2); + assert(counter == 72); + rtems_test_endk(); + } +} + +static void two_thread_terminate(rtems_tcb *a) +{ + assert_forward_order(2); +} + +static bool three_thread_create(rtems_tcb *a, rtems_tcb *b) +{ + assert_forward_order(3); + return true; +} + +static void three_thread_start(rtems_tcb *a, rtems_tcb *b) +{ + assert_forward_order(3); +} + +static void three_thread_restart(rtems_tcb *a, rtems_tcb *b) +{ + assert_static_order(3); +} + +static void three_thread_delete(rtems_tcb *a, rtems_tcb *b) +{ + assert_reverse_order(3); +} + +static void three_thread_switch(rtems_tcb *a, rtems_tcb *b) +{ + assert_forward_order(3); +} + +static void three_thread_begin(rtems_tcb *a) +{ + assert_forward_order(3); +} + +static void three_thread_exitted(rtems_tcb *a) +{ + assert_forward_order(3); +} + +static void three_fatal( + rtems_fatal_source source, + bool is_internal, + rtems_fatal_code code +) +{ + if (source == RTEMS_FATAL_SOURCE_EXIT) { + assert_reverse_order(3); + } +} + +static void three_thread_terminate(rtems_tcb *a) +{ + assert_forward_order(3); +} + +#define ZERO \ + { \ + .thread_create = zero_thread_create, \ + .thread_start = zero_thread_start, \ + .thread_restart = zero_thread_restart, \ + .thread_delete = zero_thread_delete, \ + .thread_switch = zero_thread_switch, \ + .thread_begin = zero_thread_begin, \ + .thread_exitted = zero_thread_exitted, \ + .fatal = zero_fatal, \ + .thread_terminate = zero_thread_terminate \ + } + +#define ONE \ + { \ + .thread_create = one_thread_create, \ + .thread_start = one_thread_start, \ + .thread_restart = one_thread_restart, \ + .thread_delete = one_thread_delete, \ + .thread_switch = one_thread_switch, \ + .thread_begin = one_thread_begin, \ + .thread_exitted = one_thread_exitted, \ + .fatal = one_fatal, \ + .thread_terminate = one_thread_terminate \ + } + +static const rtems_extensions_table two = { + .thread_create = two_thread_create, + .thread_start = two_thread_start, + .thread_restart = two_thread_restart, + .thread_delete = two_thread_delete, + .thread_switch = two_thread_switch, + .thread_begin = two_thread_begin, + .thread_exitted = two_thread_exitted, + .fatal = two_fatal, + .thread_terminate = two_thread_terminate +}; + +static const rtems_extensions_table three = { + .thread_create = three_thread_create, + .thread_start = three_thread_start, + .thread_restart = three_thread_restart, + .thread_delete = three_thread_delete, + .thread_switch = three_thread_switch, + .thread_begin = three_thread_begin, + .thread_exitted = three_thread_exitted, + .fatal = three_fatal, + .thread_terminate = three_thread_terminate +}; + +static const rtems_extensions_table initial_test = + RTEMS_TEST_INITIAL_EXTENSION; + +#ifdef BSP_INITIAL_EXTENSION +static const rtems_extensions_table initial_bsp = + BSP_INITIAL_EXTENSION; +#endif + +static void wake_up_master(void) +{ + rtems_status_code sc; + + sc = rtems_event_transient_send(master_task); + assert(sc == RTEMS_SUCCESSFUL); +} + +static void wait_for_worker(void) +{ + rtems_status_code sc; + + sc = rtems_event_transient_receive( + RTEMS_WAIT, + RTEMS_NO_TIMEOUT + ); + assert(sc == RTEMS_SUCCESSFUL); +} + +static void worker(rtems_task_argument arg) +{ + wake_up_master(); + + (void) rtems_task_suspend(RTEMS_SELF); + assert(false); +} + +static void test(void) +{ + rtems_status_code sc; + rtems_id id; + + master_task = rtems_task_self(); + +#ifdef BSP_INITIAL_EXTENSION + sc = rtems_extension_create( + rtems_build_name(' ', 'B', 'S', 'P'), + &initial_bsp, + &id + ); + assert(sc == RTEMS_SUCCESSFUL); +#undef BSP_INITIAL_EXTENSION +#endif + + sc = rtems_extension_create( + rtems_build_name('T', 'E', 'S', 'T'), + &initial_test, + &id + ); + assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_extension_create( + rtems_build_name('2', ' ', ' ', ' '), + &two, + &id + ); + assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_extension_create( + rtems_build_name('3', ' ', ' ', ' '), + &three, + &id + ); + assert(sc == RTEMS_SUCCESSFUL); + + active_extensions = 4; + assert(counter == 14); + counter = 16; + + sc = rtems_task_create( + rtems_build_name('W', 'O', 'R', 'K'), + 2, + RTEMS_MINIMUM_STACK_SIZE, + RTEMS_DEFAULT_MODES, + RTEMS_DEFAULT_ATTRIBUTES, + &id + ); + assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_task_start(id, worker, 0); + assert(sc == RTEMS_SUCCESSFUL); + + wait_for_worker(); + + sc = rtems_task_restart(id, 0); + assert(sc == RTEMS_SUCCESSFUL); + + wait_for_worker(); + + sc = rtems_task_delete(id); + assert(sc == RTEMS_SUCCESSFUL); + + /* Process zombies to trigger delete extensions */ + sc = rtems_task_create( + rtems_build_name('N', 'U', 'L', 'L'), + 2, + SIZE_MAX, + RTEMS_DEFAULT_MODES, + RTEMS_DEFAULT_ATTRIBUTES, + &id + ); + assert(sc == RTEMS_UNSATISFIED); +} + +static void Init(rtems_task_argument arg) +{ + rtems_test_begink(); + + test(); + + exit(0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER +#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER + +#define CONFIGURE_MAXIMUM_USER_EXTENSIONS 4 + +#define CONFIGURE_MAXIMUM_TASKS 2 + +#define CONFIGURE_INITIAL_EXTENSIONS ZERO, ONE + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT + +#include <rtems/confdefs.h> diff --git a/testsuites/sptests/spextensions01/spextensions01.doc b/testsuites/sptests/spextensions01/spextensions01.doc new file mode 100644 index 0000000..5e91e84 --- /dev/null +++ b/testsuites/sptests/spextensions01/spextensions01.doc @@ -0,0 +1,12 @@ +This file describes the directives and concepts tested by this test set. + +test set name: spextensions01 + +directives: + + - rtems_extension_create() + - _User_extensions_Iterate() + +concepts: + + - Ensure that the user extensions are called in the right order. diff --git a/testsuites/sptests/spextensions01/spextensions01.scn b/testsuites/sptests/spextensions01/spextensions01.scn new file mode 100644 index 0000000..7a51b94 --- /dev/null +++ b/testsuites/sptests/spextensions01/spextensions01.scn @@ -0,0 +1,2 @@ +*** BEGIN OF TEST SPEXTENSIONS 1 *** +*** END OF TEST SPEXTENSIONS 1 *** -- 1.8.4.5 _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel