Changeset fcb11510 in rtems


Ignore:
Timestamp:
Feb 26, 2020, 9:02:37 AM (3 months ago)
Author:
Sebastian Huber <sebastian.huber@…>
Branches:
master
Children:
8bd3915
Parents:
2220a53
git-author:
Sebastian Huber <sebastian.huber@…> (02/26/20 09:02:37)
git-committer:
Sebastian Huber <sebastian.huber@…> (02/28/20 06:50:19)
Message:

score: Fix context switch extensions (SMP)

In uniprocessor and SMP configurations, the context switch extensions
were called during _Thread_Do_dispatch():

void _Thread_Do_dispatch( Per_CPU_Control *cpu_self, ISR_Level level )
{

Thread_Control *executing;

executing = cpu_self->executing;

...
do {

Thread_Control *heir;

heir = _Thread_Get_heir_and_make_it_executing( cpu_self );
...
_User_extensions_Thread_switch( executing, heir );
...
_Context_Switch( &executing->Registers, &heir->Registers );
...

} while ( cpu_self->dispatch_necessary );
...

}

In uniprocessor configurations, this is fine and the context switch
extensions are called for all thread switches except the very first
thread switch to the initialization thread. However, in SMP
configurations, the context switch may be invalidated and updated in the
low-level _Context_Switch() routine. See:

https://docs.rtems.org/branches/master/c-user/symmetric_multiprocessing_services.html#thread-dispatch-details

In case such an update happens, a thread will execute on the processor
which was not seen in the previous call of the context switch
extensions. This can confuse for example event record consumers which
use events generated by a context switch extension.

Fixing this is not straight forward. The context switch extensions call
must move after the low-level context switch. The problem here is that
we may end up in _Thread_Handler(). Adding the context switch
extensions call to _Thread_Handler() covers now also the thread switch
to the initialization thread. We also have to save the last executing
thread (ancestor) of the processor. Registers or the stack cannot be
used for this purpose. We have to add it to the per-processor
information. Existing extensions may be affected, since now context
switch extensions use the stack of the heir thread. The stack checker
is affected by this.

Calling the thread switch extensions in the low-level context switch is
difficult since at this point an intermediate stack is used which is
only large enough to enable servicing of interrupts.

Update #3885.

Files:
8 edited

Legend:

Unmodified
Added
Removed
  • cpukit/include/rtems/score/percpu.h

    r2220a53 rfcb11510  
    530530
    531531    /**
     532     * @brief The ancestor of the executing thread.
     533     *
     534     * This member is used by _User_extensions_Thread_switch().
     535     */
     536    struct _Thread_Control *ancestor;
     537
     538    /**
    532539     * @brief Begin of the per-CPU data area.
    533540     *
  • cpukit/include/rtems/score/userextimpl.h

    r2220a53 rfcb11510  
    387387    _Per_CPU_Acquire( cpu_self, &lock_context );
    388388
     389    executing = cpu_self->ancestor;
     390    cpu_self->ancestor = heir;
    389391    node = _Chain_Immutable_first( chain );
     392
     393    /*
     394     * An executing thread equal to the heir thread may happen in two
     395     * situations.  Firstly, in case context switch extensions are created after
     396     * system initialization.  Secondly, during a thread self restart.
     397     */
     398    if ( executing != heir ) {
    390399#endif
    391400
     
    399408
    400409#if defined(RTEMS_SMP)
     410    }
     411
    401412    _Per_CPU_Release( cpu_self, &lock_context );
    402413    _ISR_lock_ISR_enable( &lock_context );
  • cpukit/libmisc/stackchk/check.c

    r2220a53 rfcb11510  
    296296 */
    297297void rtems_stack_checker_switch_extension(
    298   Thread_Control *running RTEMS_UNUSED,
    299   Thread_Control *heir RTEMS_UNUSED
     298  Thread_Control *running,
     299  Thread_Control *heir
    300300)
    301301{
     
    307307   *  Check for an out of bounds stack pointer or an overwrite
    308308   */
     309#if defined(RTEMS_SMP)
     310  sp_ok = Stack_check_Frame_pointer_in_range( heir );
     311
     312  if ( !sp_ok ) {
     313    pattern_ok = Stack_check_Is_sanity_pattern_valid(
     314      &heir->Start.Initial_stack
     315    );
     316    Stack_check_report_blown_task( heir, pattern_ok );
     317  }
     318
     319  pattern_ok = Stack_check_Is_sanity_pattern_valid( &running->Start.Initial_stack );
     320
     321  if ( !pattern_ok ) {
     322    Stack_check_report_blown_task( running, pattern_ok );
     323  }
     324#else
    309325  sp_ok = Stack_check_Frame_pointer_in_range( running );
    310326
     
    314330    Stack_check_report_blown_task( running, pattern_ok );
    315331  }
     332#endif
    316333
    317334  stack = &Stack_check_Interrupt_stack[ _SMP_Get_current_processor() ];
     
    330347bool rtems_stack_checker_is_blown( void )
    331348{
    332   rtems_stack_checker_switch_extension( _Thread_Get_executing(), NULL );
     349  Thread_Control *executing;
     350
     351  executing = _Thread_Get_executing();
     352  rtems_stack_checker_switch_extension( executing, executing );
    333353
    334354  /*
  • cpukit/score/src/threadcreateidle.c

    r2220a53 rfcb11510  
    7676  cpu->heir      =
    7777  cpu->executing = idle;
     78#if defined(RTEMS_SMP)
     79  cpu->ancestor = idle;
     80#endif
    7881
    7982  idle->is_idle = true;
  • cpukit/score/src/threaddispatch.c

    r2220a53 rfcb11510  
    298298    _ISR_Local_enable( level );
    299299
     300#if !defined(RTEMS_SMP)
    300301    _User_extensions_Thread_switch( executing, heir );
     302#endif
    301303    _Thread_Save_fp( executing );
    302304    _Context_Switch( &executing->Registers, &heir->Registers );
    303305    _Thread_Restore_fp( executing );
     306#if defined(RTEMS_SMP)
     307    _User_extensions_Thread_switch( NULL, executing );
     308#endif
    304309
    305310    /*
  • cpukit/score/src/threadhandler.c

    r2220a53 rfcb11510  
    9898  _Thread_Restore_fp( executing );
    9999
     100#if defined(RTEMS_SMP)
     101  _User_extensions_Thread_switch( NULL, executing );
     102#endif
     103
    100104  /*
    101105   * Do not use the level of the thread control block, since it has a
  • cpukit/score/src/userextaddset.c

    r2220a53 rfcb11510  
    2121
    2222#include <rtems/score/userextimpl.h>
     23#include <rtems/score/smp.h>
    2324#include <rtems/score/percpu.h>
     25
     26static void _User_extensions_Set_ancestors( void )
     27{
     28#if defined(RTEMS_SMP)
     29  if ( _Chain_Is_empty( &_User_extensions_Switches_list ) ) {
     30    uint32_t cpu_max;
     31    uint32_t cpu_index;
     32
     33    cpu_max = _SMP_Get_processor_maximum();
     34
     35    for ( cpu_index = 0 ; cpu_index < cpu_max ; ++cpu_index ) {
     36       Per_CPU_Control *cpu;
     37
     38       cpu = _Per_CPU_Get_by_index( cpu_index );
     39       cpu->ancestor = cpu->executing;
     40    }
     41  }
     42#endif
     43}
    2444
    2545void _User_extensions_Add_set(
     
    4666
    4767    _Per_CPU_Acquire_all( &lock_context );
     68    _User_extensions_Set_ancestors();
    4869    _Chain_Initialize_node( &the_extension->Switch.Node );
    4970    _Chain_Append_unprotected(
  • testsuites/sptests/spextensions01/init.c

    r2220a53 rfcb11510  
    454454
    455455  active_extensions = 4;
     456#ifdef RTEMS_SMP
     457  assert(counter == 12);
     458#else
    456459  assert(counter == 10);
    457460  counter = 12;
     461#endif
    458462
    459463  sc = rtems_task_create(
Note: See TracChangeset for help on using the changeset viewer.