score: Add and use _Thread_Dispatch_direct()

This function is useful for operations which synchronously block, e.g.
self restart, self deletion, yield, sleep.  It helps to detect if these
operations are called in the wrong context.  Since the thread dispatch
necessary indicator is not used, this is more robust in some SMP
situations.

Update #2751.
This commit is contained in:
Sebastian Huber
2016-11-14 09:11:07 +01:00
parent acc6d9bf37
commit d78d5294cd
15 changed files with 118 additions and 13 deletions

View File

@@ -96,7 +96,7 @@ static inline int nanosleep_yield( struct timespec *rmtp )
executing = _Thread_Get_executing(); executing = _Thread_Get_executing();
cpu_self = _Thread_Dispatch_disable(); cpu_self = _Thread_Dispatch_disable();
_Thread_Yield( executing ); _Thread_Yield( executing );
_Thread_Dispatch_enable( cpu_self ); _Thread_Dispatch_direct( cpu_self );
if ( rmtp ) { if ( rmtp ) {
rmtp->tv_sec = 0; rmtp->tv_sec = 0;
rmtp->tv_nsec = 0; rmtp->tv_nsec = 0;

View File

@@ -30,6 +30,6 @@ int sched_yield( void )
cpu_self = _Thread_Dispatch_disable(); cpu_self = _Thread_Dispatch_disable();
_Thread_Yield( _Per_CPU_Get_executing( cpu_self ) ); _Thread_Yield( _Per_CPU_Get_executing( cpu_self ) );
_Thread_Dispatch_enable( cpu_self ); _Thread_Dispatch_direct( cpu_self );
return 0; return 0;
} }

View File

@@ -48,6 +48,6 @@ rtems_status_code rtems_task_wake_after(
ticks ticks
); );
} }
_Thread_Dispatch_enable( cpu_self ); _Thread_Dispatch_direct( cpu_self );
return RTEMS_SUCCESSFUL; return RTEMS_SUCCESSFUL;
} }

View File

@@ -56,7 +56,8 @@ static const char *const internal_error_text[] = {
"INTERNAL_ERROR_RTEMS_INIT_TASK_ENTRY_IS_NULL", "INTERNAL_ERROR_RTEMS_INIT_TASK_ENTRY_IS_NULL",
"INTERNAL_ERROR_POSIX_INIT_THREAD_ENTRY_IS_NULL", "INTERNAL_ERROR_POSIX_INIT_THREAD_ENTRY_IS_NULL",
"INTERNAL_ERROR_THREAD_QUEUE_DEADLOCK", "INTERNAL_ERROR_THREAD_QUEUE_DEADLOCK",
"INTERNAL_ERROR_THREAD_QUEUE_ENQUEUE_STICKY_FROM_BAD_STATE" "INTERNAL_ERROR_THREAD_QUEUE_ENQUEUE_STICKY_FROM_BAD_STATE",
"INTERNAL_ERROR_BAD_THREAD_DISPATCH_DISABLE_LEVEL"
}; };
const char *rtems_internal_error_text( rtems_fatal_code error ) const char *rtems_internal_error_text( rtems_fatal_code error )

View File

@@ -165,7 +165,8 @@ typedef enum {
INTERNAL_ERROR_RTEMS_INIT_TASK_ENTRY_IS_NULL, INTERNAL_ERROR_RTEMS_INIT_TASK_ENTRY_IS_NULL,
INTERNAL_ERROR_POSIX_INIT_THREAD_ENTRY_IS_NULL, INTERNAL_ERROR_POSIX_INIT_THREAD_ENTRY_IS_NULL,
INTERNAL_ERROR_THREAD_QUEUE_DEADLOCK, INTERNAL_ERROR_THREAD_QUEUE_DEADLOCK,
INTERNAL_ERROR_THREAD_QUEUE_ENQUEUE_STICKY_FROM_BAD_STATE INTERNAL_ERROR_THREAD_QUEUE_ENQUEUE_STICKY_FROM_BAD_STATE,
INTERNAL_ERROR_BAD_THREAD_DISPATCH_DISABLE_LEVEL
} Internal_errors_Core_list; } Internal_errors_Core_list;
typedef CPU_Uint32ptr Internal_errors_t; typedef CPU_Uint32ptr Internal_errors_t;

View File

@@ -94,6 +94,20 @@ RTEMS_INLINE_ROUTINE void _Thread_Dispatch_initialization( void )
*/ */
void _Thread_Dispatch( void ); void _Thread_Dispatch( void );
/**
* @brief Directly do a thread dispatch.
*
* Must be called with a thread dispatch disable level of one, otherwise the
* INTERNAL_ERROR_BAD_THREAD_DISPATCH_DISABLE_LEVEL will occur. This function
* is useful for operations which synchronously block, e.g. self restart, self
* deletion, yield, sleep.
*
* @param[in] cpu_self The current processor.
*
* @see _Thread_Dispatch().
*/
void _Thread_Dispatch_direct( Per_CPU_Control *cpu_self );
/** /**
* @brief Performs a thread dispatch on the current processor. * @brief Performs a thread dispatch on the current processor.
* *

View File

@@ -233,3 +233,19 @@ void _Thread_Dispatch( void )
_ISR_Local_enable( level ); _ISR_Local_enable( level );
} }
} }
void _Thread_Dispatch_direct( Per_CPU_Control *cpu_self )
{
ISR_Level level;
if ( cpu_self->thread_dispatch_disable_level != 1 ) {
_Terminate(
INTERNAL_ERROR_CORE,
0,
INTERNAL_ERROR_BAD_THREAD_DISPATCH_DISABLE_LEVEL
);
}
_ISR_Local_disable( level );
_Thread_Do_dispatch( cpu_self, level );
}

View File

@@ -344,14 +344,8 @@ void _Thread_Life_action_handler(
if ( _Thread_Is_life_terminating( previous_life_state ) ) { if ( _Thread_Is_life_terminating( previous_life_state ) ) {
cpu_self = _Thread_Wait_for_join( executing, cpu_self ); cpu_self = _Thread_Wait_for_join( executing, cpu_self );
_Thread_Make_zombie( executing ); _Thread_Make_zombie( executing );
_Thread_Dispatch_direct( cpu_self );
/* FIXME: Workaround for https://devel.rtems.org/ticket/2751 */
cpu_self->dispatch_necessary = true;
_Assert( cpu_self->heir != executing );
_Thread_Dispatch_enable( cpu_self );
RTEMS_UNREACHABLE(); RTEMS_UNREACHABLE();
} }

View File

@@ -33,6 +33,7 @@ _SUBDIRS = \
spsignal_err01 spport_err01 spmsgq_err01 spmsgq_err02 spsem_err01 \ spsignal_err01 spport_err01 spmsgq_err01 spmsgq_err02 spsem_err01 \
spsem_err02 sptask_err01 spevent_err03 sptask_err03 sptask_err02 \ spsem_err02 sptask_err01 spevent_err03 sptask_err03 sptask_err02 \
sptask_err04 spclock_err01 sptask_err04 spclock_err01
_SUBDIRS += spfatal29
_SUBDIRS += spmutex01 _SUBDIRS += spmutex01
_SUBDIRS += spextensions01 _SUBDIRS += spextensions01
_SUBDIRS += spsysinit01 _SUBDIRS += spsysinit01

View File

@@ -193,6 +193,7 @@ spfatal20/Makefile
spfatal24/Makefile spfatal24/Makefile
spfatal25/Makefile spfatal25/Makefile
spfatal27/Makefile spfatal27/Makefile
spfatal29/Makefile
spfifo01/Makefile spfifo01/Makefile
spfifo02/Makefile spfifo02/Makefile
spfifo03/Makefile spfifo03/Makefile

View File

@@ -0,0 +1,19 @@
rtems_tests_PROGRAMS = spfatal29
spfatal29_SOURCES = ../spfatal_support/init.c ../spfatal_support/system.h testcase.h
dist_rtems_tests_DATA = spfatal29.scn spfatal29.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 = $(spfatal29_OBJECTS)
LINK_LIBS = $(spfatal29_LDLIBS)
spfatal29$(EXEEXT): $(spfatal29_OBJECTS) $(spfatal29_DEPENDENCIES)
@rm -f spfatal29$(EXEEXT)
$(make-exe)
include $(top_srcdir)/../automake/local.am

View File

@@ -0,0 +1,11 @@
This file describes the directives and concepts tested by this test set.
test set name: spfatal29
directives:
- _Thread_Dispatch_force()
concepts:
- Provoke the INTERNAL_ERROR_BAD_THREAD_DISPATCH_DISABLE_LEVEL fatal error.

View File

@@ -0,0 +1,3 @@
*** BEGIN OF TEST SPFATAL 29 ***
Fatal error (yield in interrupt context) hit
*** END OF TEST SPFATAL 29 ***

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) 2016 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.
*/
#define FATAL_ERROR_TEST_NAME "29"
#define FATAL_ERROR_DESCRIPTION "yield in interrupt context"
#define FATAL_ERROR_EXPECTED_SOURCE INTERNAL_ERROR_CORE
#define FATAL_ERROR_EXPECTED_IS_INTERNAL FALSE
#define FATAL_ERROR_EXPECTED_ERROR INTERNAL_ERROR_BAD_THREAD_DISPATCH_DISABLE_LEVEL
#define CONFIGURE_MAXIMUM_TIMERS 1
static void timer(rtems_id id, void *arg)
{
rtems_task_wake_after(RTEMS_YIELD_PROCESSOR);
}
void force_error()
{
rtems_status_code sc;
rtems_id id;
sc = rtems_timer_create(
rtems_build_name('T', 'I', 'M', 'E'),
&id
);
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
sc = rtems_timer_fire_after(id, 1, timer, NULL);
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
sc = rtems_task_delete(RTEMS_SELF);
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
}

View File

@@ -36,7 +36,7 @@ static void test_internal_error_text(void)
} while ( text != text_last ); } while ( text != text_last );
rtems_test_assert( rtems_test_assert(
error - 3 == INTERNAL_ERROR_THREAD_QUEUE_ENQUEUE_STICKY_FROM_BAD_STATE error - 3 == INTERNAL_ERROR_BAD_THREAD_DISPATCH_DISABLE_LEVEL
); );
} }