From 5c731a83485ce3e7a6b6556e7a38b92d10a98cd6 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 17 Mar 2014 10:12:14 +0100 Subject: score: Use thread action for thread restart The thread restart is now supported on SMP. New test smptests/smpthreadlife01. --- cpukit/rtems/src/taskrestart.c | 10 +- cpukit/score/include/rtems/score/objectimpl.h | 17 --- cpukit/score/include/rtems/score/thread.h | 5 + cpukit/score/include/rtems/score/threadimpl.h | 37 ++++++- cpukit/score/src/threadinitialize.c | 5 + cpukit/score/src/threadrestart.c | 50 ++++++--- testsuites/smptests/Makefile.am | 1 + testsuites/smptests/configure.ac | 1 + testsuites/smptests/smpthreadlife01/Makefile.am | 19 ++++ testsuites/smptests/smpthreadlife01/init.c | 122 +++++++++++++++++++++ .../smptests/smpthreadlife01/smpthreadlife01.doc | 11 ++ .../smptests/smpthreadlife01/smpthreadlife01.scn | 2 + testsuites/smptests/smpunsupported01/init.c | 25 +---- 13 files changed, 236 insertions(+), 69 deletions(-) create mode 100644 testsuites/smptests/smpthreadlife01/Makefile.am create mode 100644 testsuites/smptests/smpthreadlife01/init.c create mode 100644 testsuites/smptests/smpthreadlife01/smpthreadlife01.doc create mode 100644 testsuites/smptests/smpthreadlife01/smpthreadlife01.scn diff --git a/cpukit/rtems/src/taskrestart.c b/cpukit/rtems/src/taskrestart.c index daac0da0c7..ad446421f9 100644 --- a/cpukit/rtems/src/taskrestart.c +++ b/cpukit/rtems/src/taskrestart.c @@ -34,15 +34,7 @@ rtems_status_code rtems_task_restart( case OBJECTS_LOCAL: if ( _Thread_Restart( the_thread, NULL, argument ) ) { - if ( _Thread_Is_executing( the_thread ) ) { - _Objects_Put_and_keep_thread_dispatch_disabled( - &the_thread->Object - ); - _Thread_Restart_self(); - } else { - _Objects_Put( &the_thread->Object ); - } - + _Objects_Put( &the_thread->Object ); return RTEMS_SUCCESSFUL; } _Objects_Put( &the_thread->Object ); diff --git a/cpukit/score/include/rtems/score/objectimpl.h b/cpukit/score/include/rtems/score/objectimpl.h index 3764c664fd..119f11d829 100644 --- a/cpukit/score/include/rtems/score/objectimpl.h +++ b/cpukit/score/include/rtems/score/objectimpl.h @@ -879,23 +879,6 @@ RTEMS_INLINE_ROUTINE void _Objects_Put_without_thread_dispatch( _Thread_Unnest_dispatch(); } -/** - * @brief Puts back an object obtained with _Objects_Get(). - * - * The thread dispatch disable level will remain unchanged. - * - * On SMP configurations the Giant lock will be released. - */ -RTEMS_INLINE_ROUTINE void _Objects_Put_and_keep_thread_dispatch_disabled( - Objects_Control *the_object -) -{ - (void) the_object; -#if defined(RTEMS_SMP) - _Giant_Release(); -#endif -} - /** * @brief Puts back an object obtained with _Objects_Get_isr_disable(). */ diff --git a/cpukit/score/include/rtems/score/thread.h b/cpukit/score/include/rtems/score/thread.h index e5a1a55acd..d853aa035a 100644 --- a/cpukit/score/include/rtems/score/thread.h +++ b/cpukit/score/include/rtems/score/thread.h @@ -396,6 +396,10 @@ typedef struct { Chain_Control Chain; } Thread_Action_control; +typedef struct { + Thread_Action Action; +} Thread_Life_control; + /** * This structure defines the Thread Control Block (TCB). */ @@ -543,6 +547,7 @@ struct Thread_Control_struct { */ Chain_Control Key_Chain; + Thread_Life_control Life; }; #if (CPU_PROVIDES_IDLE_THREAD_BODY == FALSE) diff --git a/cpukit/score/include/rtems/score/threadimpl.h b/cpukit/score/include/rtems/score/threadimpl.h index bbaa10a2f0..b8647276a5 100644 --- a/cpukit/score/include/rtems/score/threadimpl.h +++ b/cpukit/score/include/rtems/score/threadimpl.h @@ -219,6 +219,13 @@ void _Thread_Reset( Thread_Entry_numeric_type numeric_argument ); +void _Thread_Life_action_handler( + Thread_Control *executing, + Thread_Action *action, + Per_CPU_Control *cpu, + ISR_Level level +); + /** * @brief Frees all memory associated with the specified thread. * @@ -501,21 +508,23 @@ RTEMS_INLINE_ROUTINE void _Thread_Unblock ( * to that of its initial state. */ -RTEMS_INLINE_ROUTINE void _Thread_Restart_self( void ) +RTEMS_INLINE_ROUTINE void _Thread_Restart_self( Thread_Control *executing ) { #if defined(RTEMS_SMP) ISR_Level level; + _Giant_Release(); + _Per_CPU_ISR_disable_and_acquire( _Per_CPU_Get(), level ); ( void ) level; #endif #if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE ) - if ( _Thread_Executing->fp_context != NULL ) - _Context_Restore_fp( &_Thread_Executing->fp_context ); + if ( executing->fp_context != NULL ) + _Context_Restore_fp( &executing->fp_context ); #endif - _CPU_Context_Restart_self( &_Thread_Executing->Registers ); + _CPU_Context_Restart_self( &executing->Registers ); } /** @@ -603,6 +612,26 @@ RTEMS_INLINE_ROUTINE Thread_Control *_Thread_Internal_allocate( void ) return (Thread_Control *) _Objects_Allocate( &_Thread_Internal_information ); } +RTEMS_INLINE_ROUTINE void _Thread_Request_dispatch_if_executing( + Thread_Control *thread +) +{ +#if defined(RTEMS_SMP) + if ( thread->is_executing ) { + const Per_CPU_Control *cpu_of_executing = _Per_CPU_Get(); + Per_CPU_Control *cpu_of_thread = _Thread_Get_CPU( thread ); + + cpu_of_thread->dispatch_necessary = true; + + if ( cpu_of_executing != cpu_of_thread ) { + _Per_CPU_Send_interrupt( cpu_of_thread ); + } + } +#else + (void) thread; +#endif +} + RTEMS_INLINE_ROUTINE void _Thread_Signal_notification( Thread_Control *thread ) { if ( _ISR_Is_in_progress() && _Thread_Is_executing( thread ) ) { diff --git a/cpukit/score/src/threadinitialize.c b/cpukit/score/src/threadinitialize.c index 315156e52a..c851320936 100644 --- a/cpukit/score/src/threadinitialize.c +++ b/cpukit/score/src/threadinitialize.c @@ -240,6 +240,11 @@ bool _Thread_Initialize( _Thread_Action_control_initialize( &the_thread->Post_switch_actions ); + _Thread_Action_initialize( + &the_thread->Life.Action, + _Thread_Life_action_handler + ); + /* * Open the object */ diff --git a/cpukit/score/src/threadrestart.c b/cpukit/score/src/threadrestart.c index b9a7dd56ae..d982f720e7 100644 --- a/cpukit/score/src/threadrestart.c +++ b/cpukit/score/src/threadrestart.c @@ -20,32 +20,52 @@ #include #include -#include -bool _Thread_Restart( +void _Thread_Life_action_handler( + Thread_Control *executing, + Thread_Action *action, + Per_CPU_Control *cpu, + ISR_Level level +) +{ + (void) action; + _Thread_Action_release_and_ISR_enable( cpu, level ); + + _Thread_Disable_dispatch(); + + _Thread_Load_environment( executing ); + _Thread_Restart_self( executing ); +} + +static void _Thread_Request_life_change( Thread_Control *the_thread, void *pointer_argument, Thread_Entry_numeric_type numeric_argument ) { -#if defined( RTEMS_SMP ) - if ( - rtems_configuration_is_smp_enabled() - && !_Thread_Is_executing( the_thread ) - ) { - return false; - } -#endif + _Thread_Set_transient( the_thread ); - if ( !_States_Is_dormant( the_thread->current_state ) ) { + _Thread_Reset( the_thread, pointer_argument, numeric_argument ); - _Thread_Set_transient( the_thread ); + _Thread_Add_post_switch_action( the_thread, &the_thread->Life.Action ); - _Thread_Reset( the_thread, pointer_argument, numeric_argument ); + _Thread_Ready( the_thread ); - _Thread_Load_environment( the_thread ); + _Thread_Request_dispatch_if_executing( the_thread ); +} - _Thread_Ready( the_thread ); +bool _Thread_Restart( + Thread_Control *the_thread, + void *pointer_argument, + Thread_Entry_numeric_type numeric_argument +) +{ + if ( !_States_Is_dormant( the_thread->current_state ) ) { + _Thread_Request_life_change( + the_thread, + pointer_argument, + numeric_argument + ); _User_extensions_Thread_restart( the_thread ); diff --git a/testsuites/smptests/Makefile.am b/testsuites/smptests/Makefile.am index c7fa0286ab..dddd7abe3a 100644 --- a/testsuites/smptests/Makefile.am +++ b/testsuites/smptests/Makefile.am @@ -21,6 +21,7 @@ SUBDIRS += smpmigration01 SUBDIRS += smpschedule01 SUBDIRS += smpsignal01 SUBDIRS += smpswitchextension01 +SUBDIRS += smpthreadlife01 SUBDIRS += smpunsupported01 if HAS_POSIX SUBDIRS += smppsxaffinity01 diff --git a/testsuites/smptests/configure.ac b/testsuites/smptests/configure.ac index 0d08f0db1a..b7bd8d2259 100644 --- a/testsuites/smptests/configure.ac +++ b/testsuites/smptests/configure.ac @@ -78,6 +78,7 @@ smppsxsignal01/Makefile smpschedule01/Makefile smpsignal01/Makefile smpswitchextension01/Makefile +smpthreadlife01/Makefile smpunsupported01/Makefile ]) AC_OUTPUT diff --git a/testsuites/smptests/smpthreadlife01/Makefile.am b/testsuites/smptests/smpthreadlife01/Makefile.am new file mode 100644 index 0000000000..02b5bd542f --- /dev/null +++ b/testsuites/smptests/smpthreadlife01/Makefile.am @@ -0,0 +1,19 @@ +rtems_tests_PROGRAMS = smpthreadlife01 +smpthreadlife01_SOURCES = init.c + +dist_rtems_tests_DATA = smpthreadlife01.scn smpthreadlife01.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 = $(smpthreadlife01_OBJECTS) +LINK_LIBS = $(smpthreadlife01_LDLIBS) + +smpthreadlife01$(EXEEXT): $(smpthreadlife01_OBJECTS) $(smpthreadlife01_DEPENDENCIES) + @rm -f smpthreadlife01$(EXEEXT) + $(make-exe) + +include $(top_srcdir)/../automake/local.am diff --git a/testsuites/smptests/smpthreadlife01/init.c b/testsuites/smptests/smpthreadlife01/init.c new file mode 100644 index 0000000000..ee36068c73 --- /dev/null +++ b/testsuites/smptests/smpthreadlife01/init.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2014 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * 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. + */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include "tmacros.h" + +#include +#include + +const char rtems_test_name[] = "SMPTHREADLIFE 1"; + +#define CPU_COUNT 2 + +typedef struct { + volatile rtems_task_argument main_arg; + volatile rtems_task_argument worker_arg; + SMP_barrier_Control barrier; + SMP_barrier_State worker_barrier_state; +} test_context; + +static test_context test_instance = { + .barrier = SMP_BARRIER_CONTROL_INITIALIZER, + .worker_barrier_state = SMP_BARRIER_STATE_INITIALIZER +}; + +static void worker_task(rtems_task_argument arg) +{ + test_context *ctx = &test_instance; + + rtems_test_assert(arg == ctx->main_arg); + + ctx->worker_arg = arg; + + _SMP_barrier_Wait(&ctx->barrier, &ctx->worker_barrier_state, CPU_COUNT); + + while (true) { + /* Do nothing */ + } +} + +static void test(void) +{ + test_context *ctx = &test_instance; + SMP_barrier_State barrier_state = SMP_BARRIER_STATE_INITIALIZER; + rtems_status_code sc; + rtems_id id; + rtems_task_argument arg; + + sc = rtems_task_create( + rtems_build_name('W', 'O', 'R', 'K'), + 1, + RTEMS_MINIMUM_STACK_SIZE, + RTEMS_DEFAULT_MODES, + RTEMS_DEFAULT_ATTRIBUTES, + &id + ); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + sc = rtems_task_start(id, worker_task, 0); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + _SMP_barrier_Wait( + &ctx->barrier, + &barrier_state, + CPU_COUNT + ); + + for (arg = 1; arg < 23; ++arg) { + ctx->main_arg = arg; + ctx->worker_arg = 0; + + sc = rtems_task_restart(id, arg); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + _SMP_barrier_Wait(&ctx->barrier, &barrier_state, CPU_COUNT); + + rtems_test_assert(ctx->worker_arg == arg); + } +} + +static void Init(rtems_task_argument arg) +{ + TEST_BEGIN(); + + if (rtems_smp_get_processor_count() >= CPU_COUNT) { + test(); + } + + TEST_END(); + rtems_test_exit(0); +} + +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER +#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER + +#define CONFIGURE_SMP_APPLICATION + +#define CONFIGURE_SMP_MAXIMUM_PROCESSORS CPU_COUNT + +#define CONFIGURE_MAXIMUM_TASKS CPU_COUNT + +#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION + +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE + +#define CONFIGURE_INIT + +#include diff --git a/testsuites/smptests/smpthreadlife01/smpthreadlife01.doc b/testsuites/smptests/smpthreadlife01/smpthreadlife01.doc new file mode 100644 index 0000000000..f6205677a4 --- /dev/null +++ b/testsuites/smptests/smpthreadlife01/smpthreadlife01.doc @@ -0,0 +1,11 @@ +This file describes the directives and concepts tested by this test set. + +test set name: smprestart01 + +directives: + + - rtems_task_restart() + +concepts: + + - Ensure that a restart of a task executing on another processor works. diff --git a/testsuites/smptests/smpthreadlife01/smpthreadlife01.scn b/testsuites/smptests/smpthreadlife01/smpthreadlife01.scn new file mode 100644 index 0000000000..7b4de1b8ec --- /dev/null +++ b/testsuites/smptests/smpthreadlife01/smpthreadlife01.scn @@ -0,0 +1,2 @@ +*** BEGIN OF TEST SMPTHREADLIFE 1 *** +*** END OF TEST SMPTHREADLIFE 1 *** diff --git a/testsuites/smptests/smpunsupported01/init.c b/testsuites/smptests/smpunsupported01/init.c index a2ffbed168..ffa40137aa 100644 --- a/testsuites/smptests/smpunsupported01/init.c +++ b/testsuites/smptests/smpunsupported01/init.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 embedded brains GmbH. All rights reserved. + * Copyright (c) 2013-2014 embedded brains GmbH. All rights reserved. * * embedded brains GmbH * Dornierstr. 4 @@ -20,13 +20,6 @@ const char rtems_test_name[] = "SMPUNSUPPORTED 1"; -static void some_task(rtems_task_argument arg) -{ - (void) arg; - - while (1); -} - static void test(void) { rtems_status_code sc; @@ -59,22 +52,6 @@ static void test(void) &id ); rtems_test_assert(sc == RTEMS_UNSATISFIED); - - sc = rtems_task_create( - rtems_build_name('T', 'A', 'S', 'K'), - RTEMS_MAXIMUM_PRIORITY, - RTEMS_MINIMUM_STACK_SIZE, - RTEMS_DEFAULT_MODES, - RTEMS_DEFAULT_ATTRIBUTES, - &id - ); - rtems_test_assert(sc == RTEMS_SUCCESSFUL); - - sc = rtems_task_start(id, some_task, 0); - rtems_test_assert(sc == RTEMS_SUCCESSFUL); - - sc = rtems_task_restart(id, 0); - rtems_test_assert(sc == RTEMS_INCORRECT_STATE); } static void Init(rtems_task_argument arg) -- cgit v1.2.3