score: Use thread action for thread restart

The thread restart is now supported on SMP.  New test
smptests/smpthreadlife01.
This commit is contained in:
Sebastian Huber
2014-03-31 08:29:43 +02:00
parent 8061f568de
commit 5c731a8348
13 changed files with 239 additions and 72 deletions
+1 -9
View File
@@ -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 );
@@ -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().
*/
@@ -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)
+33 -4
View File
@@ -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 ) ) {
+5
View File
@@ -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
*/
+38 -18
View File
@@ -20,7 +20,39 @@
#include <rtems/score/threadimpl.h>
#include <rtems/score/userextimpl.h>
#include <rtems/config.h>
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
)
{
_Thread_Set_transient( the_thread );
_Thread_Reset( the_thread, pointer_argument, numeric_argument );
_Thread_Add_post_switch_action( the_thread, &the_thread->Life.Action );
_Thread_Ready( the_thread );
_Thread_Request_dispatch_if_executing( the_thread );
}
bool _Thread_Restart(
Thread_Control *the_thread,
@@ -28,24 +60,12 @@ bool _Thread_Restart(
Thread_Entry_numeric_type numeric_argument
)
{
#if defined( RTEMS_SMP )
if (
rtems_configuration_is_smp_enabled()
&& !_Thread_Is_executing( the_thread )
) {
return false;
}
#endif
if ( !_States_Is_dormant( the_thread->current_state ) ) {
_Thread_Set_transient( the_thread );
_Thread_Reset( the_thread, pointer_argument, numeric_argument );
_Thread_Load_environment( the_thread );
_Thread_Ready( the_thread );
_Thread_Request_life_change(
the_thread,
pointer_argument,
numeric_argument
);
_User_extensions_Thread_restart( the_thread );
+1
View File
@@ -21,6 +21,7 @@ SUBDIRS += smpmigration01
SUBDIRS += smpschedule01
SUBDIRS += smpsignal01
SUBDIRS += smpswitchextension01
SUBDIRS += smpthreadlife01
SUBDIRS += smpunsupported01
if HAS_POSIX
SUBDIRS += smppsxaffinity01
+1
View File
@@ -78,6 +78,7 @@ smppsxsignal01/Makefile
smpschedule01/Makefile
smpsignal01/Makefile
smpswitchextension01/Makefile
smpthreadlife01/Makefile
smpunsupported01/Makefile
])
AC_OUTPUT
@@ -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
+122
View File
@@ -0,0 +1,122 @@
/*
* Copyright (c) 2014 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Dornierstr. 4
* 82178 Puchheim
* Germany
* <rtems@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.org/license/LICENSE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "tmacros.h"
#include <rtems.h>
#include <rtems/score/smpbarrier.h>
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 <rtems/confdefs.h>
@@ -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.
@@ -0,0 +1,2 @@
*** BEGIN OF TEST SMPTHREADLIFE 1 ***
*** END OF TEST SMPTHREADLIFE 1 ***
+1 -24
View File
@@ -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)