/** * POSIX 1003.1b 4.5.2 - Get Process Times */ clock_t _times( struct tms *ptms ) { rtems_interval ticks, us_per_tick; Thread_Control *executing; if ( !ptms ) rtems_set_errno_and_return_minus_one( EFAULT ); /* * This call does not depend on TOD being initialized and can't fail. */ ticks = rtems_clock_get_ticks_since_boot(); us_per_tick = rtems_configuration_get_microseconds_per_tick(); /* * RTEMS technically has no notion of system versus user time * since there is no separation of OS from application tasks. * But we can at least make a distinction between the number * of ticks since boot and the number of ticks executed by this * this thread. */ { Timestamp_Control per_tick; uint32_t ticks_of_executing; uint32_t fractional_ticks; Per_CPU_Control *cpu_self; _Timestamp_Set( &per_tick, rtems_configuration_get_microseconds_per_tick() / TOD_MICROSECONDS_PER_SECOND, (rtems_configuration_get_nanoseconds_per_tick() % TOD_NANOSECONDS_PER_SECOND) ); cpu_self = _Thread_Dispatch_disable(); executing = _Thread_Executing; _Thread_Update_cpu_time_used( executing, &_Thread_Time_of_last_context_switch ); _Timestamp_Divide( &executing->cpu_time_used, &per_tick, &ticks_of_executing, &fractional_ticks ); _Thread_Dispatch_enable( cpu_self ); ptms->tms_utime = ticks_of_executing * us_per_tick; } ptms->tms_stime = ticks * us_per_tick; ptms->tms_cutime = 0; ptms->tms_cstime = 0; return ticks * us_per_tick; }
void _Thread_Dispatch( void ) { Per_CPU_Control *cpu_self; Thread_Control *executing; ISR_Level level; #if defined( RTEMS_SMP ) /* * 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. */ _ISR_Disable_without_giant( level ); #endif cpu_self = _Per_CPU_Get(); _Assert( cpu_self->thread_dispatch_disable_level == 0 ); _Profiling_Thread_dispatch_disable( cpu_self, 0 ); cpu_self->thread_dispatch_disable_level = 1; /* * Now determine if we need to perform a dispatch on the current CPU. */ executing = cpu_self->executing; #if !defined( RTEMS_SMP ) _ISR_Disable( level ); #endif #if defined( RTEMS_SMP ) if ( cpu_self->dispatch_necessary ) { #else while ( cpu_self->dispatch_necessary ) { #endif 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(); #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 ); /* * If the CPU has hardware floating point, then we must address saving * and restoring it as part of the context switch. * * The second conditional compilation section selects the algorithm used * to context switch between floating point tasks. The deferred algorithm * can be significantly better in a system with few floating point tasks * because it reduces the total number of save and restore FP context * operations. However, this algorithm can not be used on all CPUs due * to unpredictable use of FP registers by some compilers for integer * operations. */ #if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE ) #if ( CPU_USE_DEFERRED_FP_SWITCH != TRUE ) if ( executing->fp_context != NULL ) _Context_Save_fp( &executing->fp_context ); #endif #endif _Context_Switch( &executing->Registers, &heir->Registers ); #if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE ) #if ( CPU_USE_DEFERRED_FP_SWITCH == TRUE ) if ( (executing->fp_context != NULL) && !_Thread_Is_allocated_fp( executing ) ) { if ( _Thread_Allocated_fp != NULL ) _Context_Save_fp( &_Thread_Allocated_fp->fp_context ); _Context_Restore_fp( &executing->fp_context ); _Thread_Allocated_fp = executing; } #else if ( executing->fp_context != NULL ) _Context_Restore_fp( &executing->fp_context ); #endif #endif /* * 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 } 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 ); }
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 ); }