Esempio n. 1
0
void _Thread_Handler( void )
{
    Thread_Control  *executing;
    ISR_Level        level;
    Per_CPU_Control *cpu_self;

    /*
     * Some CPUs need to tinker with the call frame or registers when the
     * thread actually begins to execute for the first time.  This is a
     * hook point where the port gets a shot at doing whatever it requires.
     */
    _Context_Initialization_at_thread_begin();
    executing = _Thread_Executing;

    /*
     * have to put level into a register for those cpu's that use
     * inline asm here
     */
    level = executing->Start.isr_level;
    _ISR_Set_level( level );

    /*
     * Initialize the floating point context because we do not come
     * through _Thread_Dispatch on our first invocation. So the normal
     * code path for performing the FP context switch is not hit.
     */
    _Thread_Restore_fp( executing );

    /*
     * Do not use the level of the thread control block, since it has a
     * different format.
     */
    _ISR_Local_disable( level );

    /*
     *  At this point, the dispatch disable level BETTER be 1.
     */
    cpu_self = _Per_CPU_Get();
    _Assert( cpu_self->thread_dispatch_disable_level == 1 );

    /*
     * Make sure we lose no thread dispatch necessary update and execute the
     * post-switch actions.  As a side-effect change the thread dispatch level
     * from one to zero.  Do not use _Thread_Enable_dispatch() since there is no
     * valid thread dispatch necessary indicator in this context.
     */
    _Thread_Do_dispatch( cpu_self, level );

    /*
     * Invoke the thread begin extensions in the context of the thread entry
     * function with thread dispatching enabled.  This enables use of dynamic
     * memory allocation, creation of POSIX keys and use of C++ thread local
     * storage.  Blocking synchronization primitives are allowed also.
     */
    _User_extensions_Thread_begin( executing );

    /*
     *  RTEMS supports multiple APIs and each API can define a different
     *  thread/task prototype. The following code supports invoking the
     *  user thread entry point using the prototype expected.
     */
    ( *executing->Start.Entry.adaptor )( executing );

    /*
     *  In the call above, the return code from the user thread body which return
     *  something was placed in return_argument.  This assumed that if it
     *  returned anything (which is not supporting in all APIs), then it would be
     *  able to fit in a (void *).
     */

    _User_extensions_Thread_exitted( executing );

    _Internal_error( INTERNAL_ERROR_THREAD_EXITTED );
}
Esempio n. 2
0
void _Thread_Do_dispatch( Per_CPU_Control *cpu_self, ISR_Level level )
{
  Thread_Control *executing;

  _Assert( cpu_self->thread_dispatch_disable_level == 1 );

  executing = cpu_self->executing;

  do {
    Thread_Control *heir = _Thread_Get_heir_and_make_it_executing( cpu_self );

    /*
     *  When the heir and executing are the same, then we are being
     *  requested to do the post switch dispatching.  This is normally
     *  done to dispatch signals.
     */
    if ( heir == executing )
      goto post_switch;

    /*
     *  Since heir and executing are not the same, we need to do a real
     *  context switch.
     */
#if __RTEMS_ADA__
    executing->rtems_ada_self = rtems_ada_self;
    rtems_ada_self = heir->rtems_ada_self;
#endif
    if ( heir->budget_algorithm == THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE )
      heir->cpu_time_budget = rtems_configuration_get_ticks_per_timeslice();

    /*
     * On SMP the complete context switch must be atomic with respect to one
     * processor.  See also _Thread_Handler() since _Context_switch() may branch
     * to this function.
     */
#if !defined( RTEMS_SMP )
    _ISR_Enable( level );
#endif

    #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
      _Thread_Update_cpu_time_used(
        executing,
        &cpu_self->time_of_last_context_switch
      );
    #else
      {
        _TOD_Get_uptime( &cpu_self->time_of_last_context_switch );
        heir->cpu_time_used++;
      }
    #endif

#if !defined(__DYNAMIC_REENT__)
    /*
     * Switch libc's task specific data.
     */
    if ( _Thread_libc_reent ) {
      executing->libc_reent = *_Thread_libc_reent;
      *_Thread_libc_reent = heir->libc_reent;
    }
#endif

    _User_extensions_Thread_switch( executing, heir );
    _Thread_Save_fp( executing );
    _Context_Switch( &executing->Registers, &heir->Registers );
    _Thread_Restore_fp( executing );

    /*
     * We have to obtain this value again after the context switch since the
     * heir thread may have migrated from another processor.  Values from the
     * stack or non-volatile registers reflect the old execution environment.
     */
    cpu_self = _Per_CPU_Get();

    _Thread_Debug_set_real_processor( executing, cpu_self );

#if !defined( RTEMS_SMP )
    _ISR_Disable( level );
#endif
  } while (
#if defined( RTEMS_SMP )
    false
#else
    cpu_self->dispatch_necessary
#endif
  );

post_switch:
  _Assert( cpu_self->thread_dispatch_disable_level == 1 );
  cpu_self->thread_dispatch_disable_level = 0;
  _Profiling_Thread_dispatch_enable( cpu_self, 0 );

  _ISR_Enable_without_giant( level );

  _Thread_Run_post_switch_actions( executing );
}